ReVoltVPN website
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]>
This commit is contained in:
commit
9abf266444
31 files changed
+2602
No files matched your search
@@ -0,0 +1,104 @@
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
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');
|
||||
|
||||
})();
|
||||
Reference in new issue
Block a user