147 lines
4.7 KiB
TypeScript
147 lines
4.7 KiB
TypeScript
const mottos = [
|
|
"Good systems should be easy to understand, maintain, and use.",
|
|
"I would rather do something right the first time than work around it later.",
|
|
"Knowing how things work underneath makes it easier to solve problems when they break.",
|
|
"If I have to do something repeatedly, I am probably going to find a way to automate it.",
|
|
"There is always something new to learn and usually a better way to do something.",
|
|
];
|
|
|
|
const glyphs = "01#@$%&*+<>/\\";
|
|
|
|
function prefersReducedMotion(): boolean {
|
|
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
}
|
|
|
|
function initName(): void {
|
|
const button = document.querySelector<HTMLButtonElement>("[data-name-play]");
|
|
if (!button) return;
|
|
const original = button.textContent?.trim() || "Owen Rummage";
|
|
let timer = 0;
|
|
|
|
button.addEventListener("click", () => {
|
|
window.clearInterval(timer);
|
|
if (prefersReducedMotion()) {
|
|
button.classList.toggle("is-glitched");
|
|
return;
|
|
}
|
|
|
|
let frame = 0;
|
|
timer = window.setInterval(() => {
|
|
button.textContent = [...original]
|
|
.map((letter, index) => {
|
|
if (letter === " " || index < frame / 2) return letter;
|
|
return glyphs[Math.floor(Math.random() * glyphs.length)];
|
|
})
|
|
.join("");
|
|
frame += 1;
|
|
if (frame > original.length * 2) {
|
|
window.clearInterval(timer);
|
|
button.textContent = original;
|
|
}
|
|
}, 34);
|
|
});
|
|
}
|
|
|
|
function initRoles(): void {
|
|
document.querySelectorAll<HTMLElement>("[data-role-play]").forEach((role) => {
|
|
const pin = role.querySelector<HTMLButtonElement>("[data-role-pin]");
|
|
const toggle = () => {
|
|
const pinned = role.classList.toggle("is-pinned");
|
|
pin?.setAttribute("aria-pressed", String(pinned));
|
|
};
|
|
role.addEventListener("dblclick", toggle);
|
|
pin?.addEventListener("click", toggle);
|
|
});
|
|
}
|
|
|
|
function initMotto(): void {
|
|
const button = document.querySelector<HTMLButtonElement>("[data-motto-play]");
|
|
if (!button) return;
|
|
let index = 0;
|
|
button.addEventListener("click", () => {
|
|
index = (index + 1) % mottos.length;
|
|
button.classList.remove("is-swapping");
|
|
void button.offsetWidth;
|
|
button.textContent = mottos[index];
|
|
button.classList.add("is-swapping");
|
|
});
|
|
}
|
|
|
|
function initSkillsToggle(): void {
|
|
const button = document.querySelector<HTMLButtonElement>("[data-skills-toggle]");
|
|
const toolset = document.querySelector<HTMLElement>("[data-toolset]");
|
|
if (!button || !toolset) return;
|
|
|
|
button.addEventListener("click", () => {
|
|
const expanded = toolset.hasAttribute("data-show-extra");
|
|
if (expanded) {
|
|
toolset.removeAttribute("data-show-extra");
|
|
} else {
|
|
toolset.setAttribute("data-show-extra", "");
|
|
}
|
|
button.setAttribute("aria-expanded", String(!expanded));
|
|
button.textContent = expanded ? "Show more" : "Show less";
|
|
});
|
|
}
|
|
|
|
function celebrate(): void {
|
|
const layer = document.createElement("div");
|
|
layer.className = "play-layer";
|
|
layer.setAttribute("aria-hidden", "true");
|
|
const count = prefersReducedMotion() ? 8 : 28;
|
|
for (let i = 0; i < count; i += 1) {
|
|
const bit = document.createElement("i");
|
|
bit.textContent = i % 3 === 0 ? "#" : i % 3 === 1 ? "0" : "1";
|
|
bit.style.setProperty("--x", `${Math.random() * 100}vw`);
|
|
bit.style.setProperty("--delay", `${Math.random() * 0.6}s`);
|
|
bit.style.setProperty("--drift", `${Math.random() * 80 - 40}px`);
|
|
layer.appendChild(bit);
|
|
}
|
|
document.body.appendChild(layer);
|
|
window.setTimeout(() => layer.remove(), 2600);
|
|
}
|
|
|
|
function initSecrets(): void {
|
|
document
|
|
.querySelector<HTMLButtonElement>("[data-home-play]")
|
|
?.addEventListener("click", celebrate);
|
|
|
|
const sequence = [
|
|
"ArrowUp",
|
|
"ArrowUp",
|
|
"ArrowDown",
|
|
"ArrowDown",
|
|
"ArrowLeft",
|
|
"ArrowRight",
|
|
"ArrowLeft",
|
|
"ArrowRight",
|
|
"b",
|
|
"a",
|
|
];
|
|
let position = 0;
|
|
window.addEventListener("keydown", (event) => {
|
|
position =
|
|
event.key.toLowerCase() === sequence[position]?.toLowerCase()
|
|
? position + 1
|
|
: 0;
|
|
if (position === sequence.length) {
|
|
celebrate();
|
|
position = 0;
|
|
}
|
|
});
|
|
}
|
|
|
|
function init(): void {
|
|
initName();
|
|
initRoles();
|
|
initMotto();
|
|
initSkillsToggle();
|
|
initSecrets();
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", init, { once: true });
|
|
} else {
|
|
init();
|
|
}
|