The landing page for ReVoltVPN, live at userevolt.app. Vanilla HTML, CSS and JavaScript: no framework, no build step, no dependencies. Every claim on the page is checked against the app it describes, which is the reason this is public. GPL-3.0, same as the app. Co-Authored-By: Claude Opus 5 <[email protected]>
105 lines
4.0 KiB
JavaScript
105 lines
4.0 KiB
JavaScript
/* ═══════════════════════════════════════════════════════════════════════════
|
|
tabs.js — Tab system
|
|
- Toggles .active on .tab-pane sections already in the HTML
|
|
- Hash routing, back/forward
|
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
(function () {
|
|
'use strict';
|
|
|
|
var TABS = ['home', 'features', 'why', 'faq', 'contact', 'download', 'github', 'terms', 'privacy'];
|
|
var contentEl = document.getElementById('tab-content');
|
|
var navLinks = document.querySelectorAll('.nav__tab');
|
|
|
|
function switchTo(name) {
|
|
contentEl.querySelectorAll('.tab-pane').forEach(function (p) { p.classList.remove('active'); });
|
|
var target = document.getElementById('tab-' + name);
|
|
if (target) target.classList.add('active');
|
|
|
|
navLinks.forEach(function (link) {
|
|
link.classList.toggle('active', link.getAttribute('href') === '#' + name);
|
|
});
|
|
|
|
contentEl.scrollTop = 0;
|
|
if (window.location.hash !== '#' + name) history.pushState(null, '', '#' + name);
|
|
|
|
var titles = {
|
|
home: 'ReVoltVPN', features: 'Features — ReVoltVPN', why: 'Why ReVolt — ReVoltVPN',
|
|
faq: 'FAQ — ReVoltVPN', contact: 'Contact — ReVoltVPN', download: 'Download — ReVoltVPN', github: 'Source — ReVoltVPN',
|
|
terms: 'Terms of Service — ReVoltVPN', privacy: 'Privacy Policy — ReVoltVPN'
|
|
};
|
|
if (titles[name]) document.title = titles[name];
|
|
}
|
|
|
|
navLinks.forEach(function (link) {
|
|
link.addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
var name = this.getAttribute('href').replace('#', '');
|
|
if (TABS.indexOf(name) !== -1) {
|
|
switchTo(name);
|
|
closeMenu();
|
|
}
|
|
});
|
|
});
|
|
|
|
/* ── Hamburger menu ──────────────────────────────────────────────────── */
|
|
var navEl = document.getElementById('nav');
|
|
var hamburger = document.querySelector('.nav__hamburger');
|
|
|
|
function openMenu() {
|
|
navEl.classList.add('nav--open');
|
|
hamburger.setAttribute('aria-expanded', 'true');
|
|
}
|
|
|
|
function closeMenu() {
|
|
navEl.classList.remove('nav--open');
|
|
hamburger.setAttribute('aria-expanded', 'false');
|
|
}
|
|
|
|
if (hamburger) {
|
|
hamburger.addEventListener('click', function () {
|
|
navEl.classList.contains('nav--open') ? closeMenu() : openMenu();
|
|
});
|
|
|
|
/* Close when clicking outside */
|
|
document.addEventListener('click', function (e) {
|
|
if (!navEl.contains(e.target)) closeMenu();
|
|
});
|
|
|
|
/* Close on Escape */
|
|
document.addEventListener('keydown', function (e) {
|
|
if (e.key === 'Escape') closeMenu();
|
|
});
|
|
}
|
|
|
|
window.addEventListener('popstate', function () {
|
|
var hash = window.location.hash.replace('#', '');
|
|
switchTo(TABS.indexOf(hash) !== -1 ? hash : 'home');
|
|
});
|
|
|
|
var el = document.getElementById('home-headline');
|
|
if (el) {
|
|
var headlines = [
|
|
'A VPN that does not ask who you are.',
|
|
'Privacy is not a subscription.',
|
|
'Your ISP is not your friend.',
|
|
'Encryption should not require an account.',
|
|
'The internet, without the surveillance.',
|
|
'You are not the product.',
|
|
'A VPN that minds its own business.',
|
|
'Your data belongs to you. Not your ISP.',
|
|
'Open source. Closed mouths.',
|
|
'Browse like nobody is watching. Because nobody is.',
|
|
'The VPN that forgets you immediately.',
|
|
'Free speech deserves free tools.',
|
|
'You decide how you pay. Not your data.',
|
|
'Privacy first. Payment optional.'
|
|
];
|
|
el.textContent = headlines[Math.floor(Math.random() * headlines.length)];
|
|
}
|
|
|
|
var hash = window.location.hash.replace('#', '');
|
|
switchTo(TABS.indexOf(hash) !== -1 ? hash : 'home');
|
|
|
|
})();
|