/* ============================================================
App — routing, tweaks (English only)
============================================================ */
const { useState, useEffect, useCallback } = React;
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"parallax": true,
"cardStack": true,
"avatarCondense": true,
"motion": "balanced",
"backdrop": "light",
"imgRadius": 14
}/*EDITMODE-END*/;
const MOTION = {
subtle: { dur: "420ms", parallax: 0.5 },
balanced: { dur: "600ms", parallax: 1.0 },
expressive: { dur: "820ms", parallax: 1.7 },
};
function useRoute() {
const parse = () => {
const h = (window.location.hash || "#/").replace(/^#/, "");
const parts = h.split("/").filter(Boolean);
return { name: parts[0] || "home", arg: parts[1] || null };
};
const [route, setRoute] = useState(parse);
useEffect(() => {
const on = () => setRoute(parse());
window.addEventListener("hashchange", on);
return () => window.removeEventListener("hashchange", on);
}, []);
return route;
}
function App() {
const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
const route = useRoute();
const t = I18N.en;
// apply tweaks
useEffect(() => {
const m = MOTION[tweaks.motion] || MOTION.balanced;
document.documentElement.style.setProperty("--dur", m.dur);
document.documentElement.style.setProperty("--img-radius", tweaks.imgRadius + "px");
window.__PARALLAX_AMOUNT = tweaks.parallax ? m.parallax : 0;
document.body.setAttribute("data-backdrop", tweaks.backdrop);
}, [tweaks]);
const nav = useCallback((path) => {
window.location.hash = "#" + path;
window.scrollTo(0, 0);
}, []);
let page;
if (route.name === "project") page =