59 lines
1.7 KiB
JavaScript
59 lines
1.7 KiB
JavaScript
// bonzi homepage — minimal, no framework
|
|
(() => {
|
|
'use strict';
|
|
|
|
// 1. type-typing effect on commands
|
|
const cmds = document.querySelectorAll('[data-typing]');
|
|
const speeds = [55, 38, 75, 30, 38, 30]; // per command ms/char
|
|
let i = 0;
|
|
const typeNext = () => {
|
|
if (i >= cmds.length) return;
|
|
const el = cmds[i];
|
|
const text = el.textContent;
|
|
el.textContent = '';
|
|
let j = 0;
|
|
const speed = speeds[i] || 45;
|
|
const tick = () => {
|
|
if (j <= text.length) {
|
|
el.textContent = text.slice(0, j);
|
|
j++;
|
|
setTimeout(tick, speed + (Math.random() * 30 - 15));
|
|
} else {
|
|
i++;
|
|
setTimeout(typeNext, 220);
|
|
}
|
|
};
|
|
tick();
|
|
};
|
|
// start after a short delay
|
|
setTimeout(typeNext, 350);
|
|
|
|
// 2. reveal output blocks as they scroll into view
|
|
const blocks = document.querySelectorAll('[data-reveal]');
|
|
if ('IntersectionObserver' in window) {
|
|
const io = new IntersectionObserver((entries) => {
|
|
entries.forEach((e) => {
|
|
if (e.isIntersecting) {
|
|
e.target.classList.add('in');
|
|
io.unobserve(e.target);
|
|
}
|
|
});
|
|
}, { threshold: 0.12 });
|
|
blocks.forEach((b) => io.observe(b));
|
|
} else {
|
|
blocks.forEach((b) => b.classList.add('in'));
|
|
}
|
|
|
|
// 3. live timestamp
|
|
const nowEl = document.getElementById('now');
|
|
if (nowEl) {
|
|
const fmt = () => {
|
|
const d = new Date();
|
|
const pad = (n) => String(n).padStart(2, '0');
|
|
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth()+1)}-${pad(d.getUTCDate())} ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())} UTC`;
|
|
};
|
|
nowEl.textContent = fmt();
|
|
setInterval(() => { nowEl.textContent = fmt(); }, 60_000);
|
|
}
|
|
})();
|