2025-01-17 12:14:53 +00:00

751 lines
24 KiB
JavaScript

// if scroll is greater than 100px, add class to body
document.addEventListener('DOMContentLoaded', function () {
document.addEventListener('scroll', checkIsScrolling);
registerUserInteractionEvents();
checkIsScrolling();
addBodyLoaded();
scrollIfFragment();
registerNiceSelect();
registerProductFeatureToggles();
registerProductRotateButton();
registerTimeline();
registerETargets();
registerFeatureImagePreload();
registerControlsCableEntry();
registerCarousels();
registerVideoModal();
registerBurgerIcon();
registerCycleLocalCloud();
registerLanguageSelectChange();
registerFeatureCycle();
registerFaqItems();
registerLazySections();
});
function addBodyLoaded() {
document.body.classList.add('js-ready');
document.documentElement.style.scrollPaddingTop = '80px';
}
let languageSelect = null;
function registerNiceSelect() {
languageSelect = NiceSelect.bind(document.querySelector("select#language-select"), { searchable: true });
}
function scrollIfFragment() {
if (!window.location.hash) return;
if (window.location.hash.startsWith('#faq-')) return;
let elem = document.querySelector(window.location.hash);
if (!elem) return;
elem.scrollIntoView({ behavior: 'smooth' });
}
function registerUserInteractionEvents() {
// on mousemove, touchmove, scroll
document.addEventListener('mousemove', userInteract, { passive: true, once: true });
document.addEventListener('touchmove', userInteract, { passive: true, once: true });
document.addEventListener('scroll', userInteract, { passive: true, once: true });
document.querySelectorAll('.nav-logo').forEach(logo => {
logo.addEventListener('click', function () {
window.scrollTo({ top: 0, behavior: 'smooth' });
}, { passive: true });
});
// load any video[data-src] elements that are in view
const lazyVideos = document.querySelectorAll('video[data-src]');
if (lazyVideos) {
lazyVideos.forEach(video => {
if (video.getBoundingClientRect().top < window.innerHeight) {
video.setAttribute('src', video.getAttribute('data-src'));
video.removeAttribute('data-src');
}
});
}
}
let interacted = false;
function userInteract() {
if (interacted) return;
interacted = true;
const lazyVideos = document.querySelectorAll('video[data-src]');
if (lazyVideos) {
lazyVideos.forEach(video => {
video.setAttribute('src', video.getAttribute('data-src'));
video.removeAttribute('data-src');
});
}
}
let isPinned = false;
function checkIsScrolling() {
let header = document.querySelector('.vpe-nav');
if (window.scrollY > 80 && !isPinned) {
header.classList.add('pinned');
isPinned = true;
} else if (window.scrollY <= 80 && isPinned) {
header.classList.remove('pinned');
isPinned = false;
}
}
function registerProductFeatureToggles() {
const buttons = document.querySelectorAll('#features .product-toggles .feature-toggle');
if (!buttons) return;
const elem = document.querySelector('#features .product');
buttons.forEach(button => {
button.addEventListener('click', function () {
// if active, remove class
if (button.classList.contains('active')) {
button.classList.remove('active');
elem.setAttribute('data-feature', '');
return;
}
// remove active class from all buttons
buttons.forEach(b => b.classList.remove('active'));
// add active class to clicked button
button.classList.add('active');
// set data-feature attribute to product
elem.setAttribute('data-feature', button.getAttribute('data-feature'));
});
});
}
let eDepsloaded = false;
let eAudio;
let eDone = false;
function registerETargets() {
document.querySelectorAll('.etarget').forEach(elem => {
elem.addEventListener('click', function () {
elem.classList.add('active');
checkETargets();
});
});
setTimeout(() => {
if (eDone || eDepsloaded) return;
console.log(decodeURIComponent(escape(atob('Tm8gZWFzdGVyIGVnZ3MgdG8gZmluZCBoZXJlIPCfmYo='))));
}, 10000);
}
function checkETargets() {
if (eDone) return;
const targets = document.querySelectorAll('.etarget');
const total = targets.length;
let active = [...targets].filter(target => target.classList.contains('active')).length;
if (active > 3 && !eDepsloaded) {
eDepsloaded = true;
console.log(decodeURIComponent(escape(atob('SGV5ISBTdG9wIGNsaWNraW5nIHRob3NlIGJ1dHRvbnMg8J+kqg=='))));
let script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/@tsparticles/confetti@3.0.3/tsparticles.confetti.bundle.min.js';
document.body.appendChild(script);
// audio
eAudio = document.createElement('audio');
eAudio.src = '/images/voice-pe/vpe-sound.mp3';
eAudio.autoplay = false;
eAudio.loop = false;
eAudio.volume = .5;
document.body.appendChild(eAudio);
}
if (active === total) {
eDone = true;
console.log(decodeURIComponent(escape(atob('QWxyaWdodCwgSSBsaWVkLCB0aGVyZSB3YXMgYW4gZWFzdGVyIGVnZy4uLiDwn5iF'))));
confetti({ particleCount: 100, spread: 100, scalar: 1.5, startVelocity: 80, ticks: 100, angle: 50, origin: { y: 1, x: 0 }, colors: ["#00AEF8"] });
setTimeout(() => {
console.log(decodeURIComponent(escape(atob('QnV0IGNhbiB5b3UgZmluZCBhbm90aGVyIG9uZSBpbiBvdXIgVm9pY2UgUHJldmlldyBFZGl0aW9uPyDwn5iP'))));
confetti({ particleCount: 100, spread: 100, scalar: 1.5, startVelocity: 80, ticks: 100, angle: 125, origin: { y: 1, x: 1 }, colors: ["#DB582E"] });
}, 500);
setTimeout(() => {
console.log(decodeURIComponent(escape(atob('R29vZCBsdWNrIQ=='))));
eAudio.play();
}, 920);
setTimeout(() => {
console.log(decodeURIComponent(escape(atob('LURhcnJlbg=='))));
confetti({ particleCount: 1000, spread: 360, scalar: 1.5, startVelocity: 150, ticks: 100, angle: 90, origin: { y: 1, x: .5 }, colors: ["#00AEF8", "#DB582E", "#16F3BE"] });
}, 1000);
}
}
function registerProductRotateButton() {
const button = document.querySelector('#features .product .button');
if (!button) return;
const elem = document.querySelector('#features .product');
button.addEventListener('click', function () {
// toggle data-side between left and right
elem.setAttribute('data-side', elem.getAttribute('data-side') === 'left' ? 'right' : 'left');
// get first button on side
const firstButton = elem.querySelector('.feature-toggle[data-side="' + elem.getAttribute('data-side') + '"]');
if (firstButton) {
// remove active class from all buttons
elem.querySelectorAll('.product-toggles .feature-toggle').forEach(b => b.classList.remove('active'));
// add active class to first button
firstButton.classList.add('active');
// set data-feature attribute to product
elem.setAttribute('data-feature', firstButton.getAttribute('data-feature'));
}
});
}
function registerTimeline() {
const timeline = document.querySelector('#timeline');
if (!timeline) return;
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
timeline.setAttribute('data-event', '2');
}
});
}, {
threshold: .25
});
observer.observe(timeline);
}
function registerFeatureImagePreload() {
// add intersection observer to #product-features. Only execute once
const features = document.querySelector('#features');
if (!features) return;
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
observer.disconnect();
preloadImage('/images/voice-pe/features/left-desktop.webp');
preloadImage('/images/voice-pe/features/left-mobile.webp');
}
});
}, {
threshold: .25
});
observer.observe(features);
}
function registerControlsCableEntry() {
// add intersection observer to #product-features. Only execute once
const controls = document.querySelector('#controls');
if (!controls) return;
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
observer.disconnect();
// remove loading="lazy" from all images
controls.querySelectorAll('img').forEach(img => img.removeAttribute('loading'));
controls.style.setProperty('--draw-cable', 1);
setTimeout(() => {
registerControlCycle();
}, 1000);
}
});
}, {
threshold: .5
});
observer.observe(controls);
}
function preloadImage(url) {
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'image';
link.href = url;
document.head.appendChild(link);
}
function registerControlCycle() {
const controlsWrapper = document.querySelector('#controls');
if (!controlsWrapper) return;
const innerControlsWrapper = controlsWrapper.querySelector('.controls');
if (!innerControlsWrapper) return
const controls = innerControlsWrapper.querySelectorAll('.control');
if (!controls) return;
let currentIndex = 1;
controlsWrapper.setAttribute('data-index', currentIndex);
controls[currentIndex - 1].classList.add('last');
// set data-index on controlsWrapper
setInterval(() => {
currentIndex = currentIndex === controls.length ? 1 : currentIndex + 1;
innerControlsWrapper.setAttribute('data-index', currentIndex);
controlsWrapper.setAttribute('data-index', 0);
setTimeout(() => {
controls.forEach(control => control.classList.remove('last'));
controls[currentIndex - 1].classList.add('last');
controlsWrapper.setAttribute('data-index', currentIndex);
}, 1000);
}, 4000);
}
function registerCarousels() {
// add intersection observer to #product-features. Only execute once
const carousels = document.querySelectorAll('.carousel-images');
if (!carousels) return;
carousels.forEach(carousel => {
const slides = carousel.querySelectorAll('.slide');
if (!slides) return;
const controls = carousel.querySelector('.controls');
if (controls) {
controls.innerHTML = '<span></span>'.repeat(slides.length);
}
// allow controls to be clicked
if (controls) {
const controlSpans = controls.querySelectorAll('span');
controlSpans.forEach((span, index) => {
span.addEventListener('click', function () {
resetCarousel(carousel, index);
});
});
}
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
observer.disconnect();
// set css variable for
resetCarousel(carousel);
}
});
}, {
threshold: .5
});
observer.observe(carousel);
});
}
let carouselInterval = null;
function resetCarousel(carousel, slideIndex = 0) {
clearInterval(carouselInterval);
const slides = carousel.querySelectorAll('.slide');
if (!slides) return;
if (slideIndex >= slides.length) {
slideIndex = 0;
}
carousel.setAttribute('data-slide', slideIndex);
carouselInterval = setInterval(() => {
const currentIndex = parseInt(carousel.getAttribute('data-slide'));
const nextIndex = currentIndex === slides.length - 1 ? 0 : currentIndex + 1;
carousel.setAttribute('data-slide', nextIndex);
}, 2500);
}
function registerVideoModal() {
const video = document.querySelector('.timeline-content .video');
if (!video) return;
const modal = document.querySelector('.video-modal');
if (!modal) return;
const previewVideoElem = video.querySelector('video');
const modalVideoElem = modal.querySelector('video');
const modalClose = modal.querySelector('.close');
if (modalClose) {
modalClose.addEventListener('click', function () {
handleVideoModalClose(previewVideoElem, modal, modalVideoElem);
});
}
video.addEventListener('click', function () {
handleVideoModalOpen(previewVideoElem, modal, modalVideoElem);
});
modal.addEventListener('click', function (e) {
if (e.target === modal) {
handleVideoModalClose(previewVideoElem, modal, modalVideoElem);
}
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') {
handleVideoModalClose(previewVideoElem, modal, modalVideoElem);
}
});
}
function handleVideoModalOpen(previewVideoElem, modal, modalVideoElem) {
modal.classList.add('open');
document.body.classList.add('modal-open');
document.documentElement.style.overflow = "hidden";
previewVideoElem.pause();
modalVideoElem.controls = true;
modalVideoElem.currentTime = 0;
modalVideoElem.muted = false;
modalVideoElem.play();
}
function handleVideoModalClose(previewVideoElem, modal, modalVideoElem) {
modal.classList.remove('open');
document.body.classList.remove('modal-open');
document.documentElement.style.overflow = "";
modalVideoElem.controls = false;
modalVideoElem.pause();
previewVideoElem.play();
}
function registerBurgerIcon() {
const burger = document.querySelector('.burger');
if (!burger) return;
const nav = document.querySelector('.vpe-nav');
if (!nav) return;
burger.addEventListener('click', function () {
nav.classList.toggle('mobile-open');
});
// if any of the burger links are clicked, close the nav
const links = nav.querySelectorAll('a');
if (!links) return;
links.forEach(link => {
link.addEventListener('click', function () {
nav.classList.remove('mobile-open');
});
});
}
function registerCycleLocalCloud() {
// add intersection observer to #product-features. Only execute once
const sides = document.querySelector('#local-cloud .sides');
if (!sides) return;
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
observer.disconnect();
// set css variable for
let lastSide = 'cloud';
let interval = null;
interval = setInterval(() => {
// toggle between data-side="local" and data-side="cloud"
sides.setAttribute('data-side', '');
setTimeout(() => {
lastSide = lastSide === 'local' ? 'cloud' : 'local';
sides.setAttribute('data-side', lastSide);
}, 500);
}, 5000);
// if hover on left side, set to local
sides.querySelector('.side.local').addEventListener('mouseenter', function () {
clearInterval(interval);
sides.setAttribute('data-side', 'local');
});
// if hover on right side, set to cloud
sides.querySelector('.side.cloud').addEventListener('mouseenter', function () {
clearInterval(interval);
sides.setAttribute('data-side', 'cloud');
});
}
});
}, {
threshold: .5
});
observer.observe(sides);
}
function registerLanguageSelectChange() {
const browserLocale = navigator.language || navigator.userLanguage;
updateLanguageSupports(browserLocale);
document.querySelector('#language-select').addEventListener('change', function (e) {
updateLanguageSupports(e.target.value);
});
}
function updateLanguageSupports(locale = null) {
let data = {
"en-US": [3, 3],
"es-ES": [3, 3],
"pt-BR": [3, 3],
"pt-PT": [2, 2],
"de-DE": [3, 3],
"de-CH": [0, 2],
"it-IT": [2, 2],
"ru-RU": [2, 2],
"ja-JP": [0, 0],
"tr-TR": [0, 1],
"ko-KR": [0, 1],
"fr-FR": [0, 3],
"ca-ES": [0, 3],
"pl-PL": [0, 3],
"nl-BE": [0, 3],
"nl-NL": [0, 3],
"id-ID": [0, 1],
"zh-HK": [0, 2],
"zh-CN": [0, 1],
"ms-MY": [0, 1],
"sv-SE": [0, 2],
"uk-UA": [0, 2],
"th-TH": [0, 1],
"vi-VN": [0, 1],
"fi-FI": [0, 3],
"no-NO": [0, 0],
"gl-ES": [0, 2],
"ar-JO": [0, 2],
"ur-IN": [0, 0],
"el-GR": [0, 1],
"ro-RO": [0, 3],
"da-DK": [0, 2],
"ta-IN": [0, 0],
"hr-HR": [0, 3],
"mk-MK": [0, 0],
"sk-SK": [0, 1],
"he-IL": [0, 2],
"sr-RS": [0, 1],
"hu-HU": [0, 3],
"bg-BG": [0, 2],
"cs-CZ": [0, 1],
"bs-BA": [0, 0],
"sl-SI": [0, 2],
"az-AZ": [0, 0],
"et-EE": [0, 1],
"lv-LV": [0, 1],
"af-ZA": [0, 0],
"cy-GB": [0, 0],
"fa-IR": [0, 1],
"lt-LT": [0, 1],
"jv-ID": [0, 0],
"sw-KE": [0, 0],
"sw-TZ": [0, 0],
"is-IS": [0, 1],
"mt-MT": [0, 0],
"ps-AF": [0, 0],
"mr-IN": [0, 0],
"bn-IN": [0, 0],
"lb-LU": [0, 0],
"hi-IN": [0, 0],
"gu-IN": [0, 0],
"km-KH": [0, 0],
"ne-NP": [0, 0],
"lo-LA": [0, 0],
"te-IN": [0, 1],
"kn-IN": [0, 0],
"ml-IN": [0, 1],
"kk-KZ": [0, 0],
"so-SO": [0, 0],
"uz-UZ": [0, 0],
"ka-GE": [0, 1],
"my-MM": [0, 0],
"mn-MN": [0, 0],
"hy-AM": [0, 0],
"am-ET": [0, 0],
"nb-NO": [0, 3],
"eu-ES": [0, 1],
"fil-PH": [0, 0],
"ga-IE": [0, 0],
"si-LK": [0, 0],
"sq-AL": [0, 0],
"su-ID": [0, 0],
"wuu-CN": [0, 0],
"yue-CN": [0, 0],
"zu-ZA": [0, 0]
};
let elems = document.querySelectorAll('.supported-cards .supported-card');
if (!elems) return;
let supports = data[locale];
let foundLocale = locale;
if (!supports) {
Object.keys(data).forEach(key => {
if (key.split('-')[0] === locale.split('-')[0]) {
supports = data[key];
foundLocale = key;
}
});
}
if (!supports) return;
document.querySelector('#language-select').value = foundLocale;
languageSelect.update();
elems.forEach(elem => elem.setAttribute('data-state', '-1'));
elems.forEach((elem, index) => {
// set data-state to the value of the value
elem.setAttribute('data-state', supports[index]);
});
}
function registerFeatureCycle() {
const featuresElem = document.querySelector('#features');
const rotateBtn = document.querySelector('#features .button');
const features = document.querySelectorAll('#features .feature-toggle');
let interval = null;
rotateBtn.addEventListener('click', function () {
if (interval) {
clearInterval(interval);
interval = null;
return;
}
});
features.forEach((feature, index) => {
feature.addEventListener('click', function () {
if (interval) {
clearInterval(interval);
interval = null;
return;
}
});
});
let availableStates = [
["microphones", "right"],
["case", "right"],
["mute", "right"],
["speaker", "right"],
["controls", "left"],
["led-ring", "left"],
["audio-jack", "left"]
]
let currentIndex = 0;
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
observer.disconnect();
// set css variable for
interval = setInterval(() => {
currentIndex = currentIndex === availableStates.length - 1 ? 0 : currentIndex + 1;
let state = availableStates[currentIndex];
document.querySelector('#features .product').setAttribute('data-feature', state[0]);
document.querySelector('#features .product').setAttribute('data-side', state[1]);
document.querySelectorAll('#features .product-toggles .feature-toggle').forEach(feature => {
feature.classList.remove('active');
});
document.querySelector('#features .product-toggles .feature-toggle[data-feature="' + state[0] + '"]').classList.add('active');
}, 5000);
}
});
}, {
threshold: .5
});
observer.observe(featuresElem);
}
function registerFaqItems() {
const faqItems = document.querySelectorAll('.faq-item');
if (!faqItems) return;
faqItems.forEach(faqItem => {
let header = faqItem.querySelector('.faq-item-heading');
header.addEventListener('click', function () {
faqItem.classList.toggle('active');
});
});
// if url contains id of faq item, open it
faqItems.forEach(faqItem => {
if (!faqItem.id) return;
if (window.location.hash === '#' + faqItem.id) {
faqItem.scrollIntoView({ behavior: 'smooth' });
setTimeout(() => {
faqItem.classList.add('active');
}, 1000);
}
document.querySelectorAll('a[href="#' + faqItem.id + '"]').forEach(link => {
link.addEventListener('click', function () {
faqItem.scrollIntoView({ behavior: 'smooth' });
setTimeout(() => {
faqItem.classList.add('active');
}, 1000);
});
});
});
}
function showBuyDialog() {
buyDialog.style.display = "flex";
document.documentElement.style.overflow = "hidden";
}
function closeDialog() {
buyDialog.style.display = "none";
document.documentElement.style.overflow = "";
}
function randomInRange(min, max) {
return Math.random() * (max - min) + min;
}
function registerLazySections() {
// for each section, register an intersection observer at 0.0. If it is intersecting, disconnect. Then, make any data-src images load
const sections = document.querySelectorAll('.vpe-main section');
if (!sections) return;
sections.forEach(section => {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
observer.disconnect();
loadLazyImages(section);
}
});
}, {
threshold: 0,
rootMargin: '80px'
});
observer.observe(section);
});
}
function loadLazyImages(section) {
const lazyImages = section.querySelectorAll('img[data-src]');
if (!lazyImages) return;
lazyImages.forEach(img => {
img.setAttribute('src', img.getAttribute('data-src'));
img.removeAttribute('data-src');
});
let lazyBackgrounds = section.querySelectorAll('[data-bg-image-lazy]');
if (!lazyBackgrounds) return;
lazyBackgrounds.forEach(lazyBackground => {
// remove the attribute
lazyBackground.removeAttribute('data-bg-image-lazy');
});
}