ba90eff5db
Adds the cyber theme to the console and login page, replaces the dark/light toggle with a theme switcher, and moves the login page script to /login.js so it is served under the existing CSP.
113 lines
4.2 KiB
JavaScript
113 lines
4.2 KiB
JavaScript
(() => {
|
|
const root = document.documentElement;
|
|
const buttons = document.querySelectorAll('.tg button');
|
|
const reducedMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
function setTheme(theme) {
|
|
root.setAttribute('data-theme', theme);
|
|
try {
|
|
localStorage.setItem('thecloud-theme', theme);
|
|
} catch (ignored) {
|
|
// Theme persistence is optional when browser storage is unavailable.
|
|
}
|
|
buttons.forEach((button) => button.classList.toggle('on', button.dataset.t === theme));
|
|
}
|
|
|
|
let initialTheme = matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
|
try {
|
|
const savedTheme = localStorage.getItem('thecloud-theme');
|
|
if (savedTheme === 'dark' || savedTheme === 'light' || savedTheme === 'cyber') {
|
|
initialTheme = savedTheme;
|
|
}
|
|
} catch (ignored) {
|
|
// The OS preference remains the fallback when browser storage is unavailable.
|
|
}
|
|
setTheme(initialTheme);
|
|
|
|
buttons.forEach((button) => button.addEventListener('click', () => setTheme(button.dataset.t)));
|
|
document.addEventListener('keydown', (event) => {
|
|
if ((event.key === 't' || event.key === 'T') && !event.metaKey && !event.ctrlKey && !event.altKey && !/INPUT|TEXTAREA/.test(event.target.tagName)) {
|
|
const themes = ['dark', 'light', 'cyber'];
|
|
setTheme(themes[(themes.indexOf(root.getAttribute('data-theme')) + 1) % themes.length]);
|
|
}
|
|
});
|
|
|
|
const lines = ['hello, engineer.', 'aws s3 mb s3://my-bucket', 'your own AWS, on your own hardware.', 'sfn start-execution --local', 'welcome to TheCloud.'];
|
|
const typewriter = document.getElementById('tw');
|
|
let line = 0;
|
|
let count = 0;
|
|
let deleting = false;
|
|
if (reducedMotion) {
|
|
typewriter.textContent = lines[2];
|
|
} else {
|
|
function type() {
|
|
const word = lines[line];
|
|
if (deleting) {
|
|
count--;
|
|
typewriter.textContent = word.slice(0, count);
|
|
if (count === 0) {
|
|
deleting = false;
|
|
line = (line + 1) % lines.length;
|
|
setTimeout(type, 400);
|
|
return;
|
|
}
|
|
setTimeout(type, 35);
|
|
return;
|
|
}
|
|
count++;
|
|
typewriter.textContent = word.slice(0, count);
|
|
if (count === word.length) {
|
|
deleting = true;
|
|
setTimeout(type, 2200);
|
|
return;
|
|
}
|
|
setTimeout(type, 75 + Math.random() * 50);
|
|
}
|
|
type();
|
|
}
|
|
|
|
const hero = document.getElementById('top');
|
|
const glow = document.getElementById('grid-glow');
|
|
if (!reducedMotion) {
|
|
hero.addEventListener('mousemove', (event) => {
|
|
const rect = hero.getBoundingClientRect();
|
|
glow.style.left = `${event.clientX - rect.left}px`;
|
|
glow.style.top = `${event.clientY - rect.top}px`;
|
|
glow.style.opacity = '1';
|
|
});
|
|
hero.addEventListener('mouseleave', () => {
|
|
glow.style.opacity = '0';
|
|
});
|
|
}
|
|
|
|
const progress = document.getElementById('bar');
|
|
addEventListener('scroll', () => {
|
|
const height = document.documentElement.scrollHeight - innerHeight;
|
|
progress.style.width = `${height > 0 ? scrollY / height * 100 : 0}%`;
|
|
}, {passive: true});
|
|
|
|
const form = document.querySelector('[data-sso-form]');
|
|
if (form) {
|
|
form.addEventListener('submit', () => {
|
|
const button = form.querySelector('.btn');
|
|
button.classList.add('is-loading');
|
|
button.disabled = true;
|
|
document.getElementById('label').textContent = 'Redirecting...';
|
|
});
|
|
}
|
|
|
|
const copy = document.getElementById('cp');
|
|
if (copy) {
|
|
copy.addEventListener('click', () => {
|
|
navigator.clipboard.writeText(document.getElementById('code').innerText).then(() => {
|
|
copy.textContent = 'copied';
|
|
copy.classList.add('ok');
|
|
setTimeout(() => {
|
|
copy.textContent = 'copy';
|
|
copy.classList.remove('ok');
|
|
}, 1800);
|
|
});
|
|
});
|
|
}
|
|
})();
|