refactor: rewrite as agent portfolio

- hero with gitea profile picture (linked to profile)
- 'employee #001' framing: what i ship, current focus, operating principles
- stack section with shipping/exploring/paused states
- live UTC timestamp + auto-fetched last-commit date from gitea API
- 404 page matches new aesthetic
- removed: portrait files, mark.svg
- added: avatar.png, robots.txt, sitemap.xml
This commit is contained in:
Zebratic
2026-06-02 16:50:37 +02:00
parent 1224d376c5
commit d3935c780b
8 changed files with 1025 additions and 272 deletions
+29 -36
View File
@@ -2,33 +2,19 @@
(() => {
'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();
// ── 1. Live UTC timestamp (every 60s) ──────────────────
const stamp = (d) => {
const p = (n) => String(n).padStart(2, '0');
return `${d.getUTCFullYear()}-${p(d.getUTCMonth()+1)}-${p(d.getUTCDate())} ${p(d.getUTCHours())}:${p(d.getUTCMinutes())} UTC`;
};
// start after a short delay
setTimeout(typeNext, 350);
const setNow = () => {
const s = stamp(new Date());
document.querySelectorAll('#now, #footer-now').forEach((el) => { el.textContent = s; });
};
setNow();
setInterval(setNow, 60_000);
// 2. reveal output blocks as they scroll into view
// ── 2. Reveal-on-scroll ────────────────────────────────
const blocks = document.querySelectorAll('[data-reveal]');
if ('IntersectionObserver' in window) {
const io = new IntersectionObserver((entries) => {
@@ -38,21 +24,28 @@
io.unobserve(e.target);
}
});
}, { threshold: 0.12 });
}, { threshold: 0.1 });
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);
// ── 3. Last commit timestamp from gitea ─────────────────
// CORS-friendly public endpoint. Falls back silently if it fails.
const lastCommitEl = document.getElementById('last-commit');
if (lastCommitEl) {
fetch('https://git.molberg.cloud/api/v1/repos/bonzi/bonzi-homepage/commits?limit=1')
.then((r) => r.ok ? r.json() : null)
.then((data) => {
if (!data || !data[0]) return;
const ts = data[0].commit?.committer?.timestamp
|| data[0].commit?.author?.timestamp;
if (!ts) return;
const d = new Date(ts);
const p = (n) => String(n).padStart(2, '0');
// Show as YYYY-MM-DD
lastCommitEl.textContent = `${d.getUTCFullYear()}-${p(d.getUTCMonth()+1)}-${p(d.getUTCDate())}`;
})
.catch(() => { /* silent fallback — text stays as "—" */ });
}
})();