redesign the site as a technical minimalist TUI
Replace the glassy hero treatment with a terminal and TUI vocabulary while keeping the layout minimal: - Switch the type stack to JetBrains Mono and flatten every surface: hairline borders, square corners, no blur or glow, and a faint graph-paper grid in place of the radial gradients. - Rebuild the home hero as a terminal window whose output is typed in on load; the old mouse-parallax glow script becomes that typing sequence, and it no-ops under prefers-reduced-motion. - Give the projects, about, and entry panels title bars, and render cards with a metadata strip, status dot, ISO date, and prompt-style links. - Hide the inline nav behind the hamburger on narrow screens; the old rule was outranked by the #menu id selector and never applied. - Add an SVG favicon, which also clears the only 404 on the site. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2e67914fd6
commit
8595290318
10 files changed
+1270
-1167
No files matched your search
@@ -1,62 +1,62 @@
|
||||
(function() {
|
||||
const heroShell = document.querySelector(".hero-main .hero-shell");
|
||||
const stream = document.querySelector(".term__stream");
|
||||
|
||||
if (!heroShell) {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
const coarsePointer = window.matchMedia("(pointer: coarse)").matches;
|
||||
|
||||
if (prefersReducedMotion || coarsePointer) {
|
||||
if (prefersReducedMotion) {
|
||||
return;
|
||||
}
|
||||
|
||||
let targetX = 0;
|
||||
let targetY = 0;
|
||||
let currentX = 0;
|
||||
let currentY = 0;
|
||||
const CHAR_DELAY = 18;
|
||||
const AFTER_COMMAND_DELAY = 90;
|
||||
const AFTER_OUTPUT_DELAY = 130;
|
||||
|
||||
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
||||
// Build the playback script before hiding anything, so a thrown error here
|
||||
// leaves the page in its fully rendered state.
|
||||
const steps = Array.from(stream.children).map((element) => ({
|
||||
element,
|
||||
isCommand: element.classList.contains("cmd"),
|
||||
text: element.textContent
|
||||
}));
|
||||
|
||||
const animate = () => {
|
||||
currentX += (targetX - currentX) * 0.065;
|
||||
currentY += (targetY - currentY) * 0.065;
|
||||
if (!steps.some((step) => step.isCommand)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bgX = 50 + currentX * 6.8;
|
||||
const bgY = 18 + currentY * 5.6;
|
||||
const bgXAlt = 50 - currentX * 5.2;
|
||||
const bgYAlt = 30 - currentY * 4.6;
|
||||
const glowRotate = currentX * 16 + currentY * 10;
|
||||
const glowShiftX = currentX * 54;
|
||||
const glowShiftY = currentY * 42;
|
||||
steps.forEach((step) => {
|
||||
if (step.isCommand) {
|
||||
step.element.textContent = "";
|
||||
return;
|
||||
}
|
||||
|
||||
document.body.style.setProperty("--hero-glow-x", `${bgX}%`);
|
||||
document.body.style.setProperty("--hero-glow-y", `${bgY}%`);
|
||||
document.body.style.setProperty("--hero-glow-alt-x", `${bgXAlt}%`);
|
||||
document.body.style.setProperty("--hero-glow-alt-y", `${bgYAlt}%`);
|
||||
document.body.style.setProperty("--hero-glow-rotate", `${glowRotate}deg`);
|
||||
document.body.style.setProperty("--hero-glow-shift-x", `${glowShiftX}px`);
|
||||
document.body.style.setProperty("--hero-glow-shift-y", `${glowShiftY}px`);
|
||||
step.element.classList.add("is-typing-hidden");
|
||||
});
|
||||
|
||||
heroShell.style.setProperty("--hero-shell-spot-x", `${50 + currentX * 14}%`);
|
||||
heroShell.style.setProperty("--hero-shell-spot-y", `${28 + currentY * 10}%`);
|
||||
const wait = (ms) => new Promise((resolve) => window.setTimeout(resolve, ms));
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
const typeCommand = async (element, text) => {
|
||||
for (let index = 0; index < text.length; index += 1) {
|
||||
element.textContent = text.slice(0, index + 1);
|
||||
await wait(CHAR_DELAY);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("mousemove", (event) => {
|
||||
const x = clamp((event.clientX / window.innerWidth - 0.5) * 2, -1, 1);
|
||||
const y = clamp((event.clientY / window.innerHeight - 0.5) * 2, -1, 1);
|
||||
const play = async () => {
|
||||
for (const step of steps) {
|
||||
if (step.isCommand) {
|
||||
await typeCommand(step.element, step.text);
|
||||
await wait(AFTER_COMMAND_DELAY);
|
||||
continue;
|
||||
}
|
||||
|
||||
targetX = x;
|
||||
targetY = y;
|
||||
});
|
||||
step.element.classList.remove("is-typing-hidden");
|
||||
await wait(AFTER_OUTPUT_DELAY);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("mouseleave", () => {
|
||||
targetX = 0;
|
||||
targetY = 0;
|
||||
});
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
play();
|
||||
})();
|
||||
Reference in new issue
Block a user