feat: Clock

This commit is contained in:
2026-03-03 17:38:51 +00:00
parent 225ac5e441
commit 8152072bec
7 changed files with 365 additions and 114 deletions

View File

@@ -1,87 +1,31 @@
(() => {
const OPENING_MS = 420;
document.addEventListener("DOMContentLoaded", () => {
function setupDashboardAnimations() {
const dashboardGrid = document.querySelector(".dashboard-grid");
const dashboardLinks = document.querySelectorAll(".dashboard-link-card[href]");
if (dashboardGrid) {
dashboardLinks.forEach((link, index) => {
link.style.setProperty("--stagger-delay", `${index * 55}ms`);
});
dashboardGrid.classList.add("is-ready");
window.requestAnimationFrame(() => {
dashboardGrid.classList.add("is-animated");
});
if (!dashboardGrid) {
return;
}
dashboardLinks.forEach((link) => {
link.addEventListener("click", (event) => {
if (link.classList.contains("is-opening")) {
event.preventDefault();
return;
}
if (
event.defaultPrevented ||
event.button !== 0 ||
event.metaKey ||
event.ctrlKey ||
event.shiftKey ||
event.altKey
) {
return;
}
const href = link.getAttribute("href");
if (!href || href.startsWith("http")) {
return;
}
event.preventDefault();
if (dashboardGrid) {
dashboardGrid.classList.add("is-focusing");
}
link.classList.add("is-opening");
// Force layout before running the exit animation for consistent playback.
void link.offsetWidth;
let hasNavigated = false;
const navigate = () => {
if (hasNavigated) {
return;
}
hasNavigated = true;
window.location.href = href;
};
if (typeof link.animate === "function") {
const animation = link.animate(
[
{ opacity: 1, transform: "translateY(-6px) scale(1)", filter: "blur(0px)" },
{ opacity: 0, transform: "translateY(-42px) scale(0.982)", filter: "blur(2px)" },
],
{
duration: OPENING_MS,
easing: "cubic-bezier(0.22, 0.61, 0.36, 1)",
fill: "forwards",
}
);
animation.finished.then(navigate).catch(navigate);
} else {
// Fallback if WAAPI is unavailable.
link.style.transition = `transform ${OPENING_MS}ms cubic-bezier(0.22, 0.61, 0.36, 1), opacity ${OPENING_MS}ms cubic-bezier(0.22, 0.61, 0.36, 1), filter ${OPENING_MS}ms cubic-bezier(0.22, 0.61, 0.36, 1)`;
requestAnimationFrame(() => {
link.style.transform = "translateY(-42px) scale(0.982)";
link.style.opacity = "0";
link.style.filter = "blur(2px)";
});
}
window.setTimeout(navigate, OPENING_MS + 240);
});
const dashboardLinks = document.querySelectorAll(".dashboard-link-card[href]");
dashboardLinks.forEach((link, index) => {
link.style.setProperty("--stagger-delay", `${index * 45}ms`);
});
});
dashboardGrid.classList.remove("is-ready", "is-animated", "is-focusing");
dashboardLinks.forEach((link) => {
link.classList.remove("is-opening");
link.style.removeProperty("transition");
link.style.removeProperty("transform");
link.style.removeProperty("opacity");
link.style.removeProperty("filter");
link.style.removeProperty("pointer-events");
});
dashboardGrid.classList.add("is-ready");
window.requestAnimationFrame(() => {
dashboardGrid.classList.add("is-animated");
});
}
document.addEventListener("DOMContentLoaded", setupDashboardAnimations);
window.addEventListener("pageshow", setupDashboardAnimations);
})();