// App root + reveal observer + scroll/parallax/cursor wiring const { useEffect: appUE, useState: appUS, useRef: appUR } = React; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "heroLayout": "mega" }/*EDITMODE-END*/; const HERO_LAYOUTS = [ { value: "mega", label: "MEGA" }, { value: "split", label: "SPLIT" }, { value: "stamp", label: "STAMP" }, { value: "ticker", label: "TICKER" }, ]; // Clean-URL routes (Buddica-style): /service/ etc. <-> section ids const ROUTES = { service: "biz", brands: "brands", message: "ceo", recruit: "careers", contact: "contact", company: "company" }; const ID_TO_PATH = {}; Object.keys(ROUTES).forEach((p) => { ID_TO_PATH[ROUTES[p]] = p; }); window.ID_TO_PATH = ID_TO_PATH; function sectionFromPath() { const seg = (location.pathname || "/").replace(/^\/+|\/+$/g, "").split("/")[0]; return ROUTES[seg] || null; } function scrollToId(id, smooth) { const el = document.getElementById(id); if (!el) return false; const top = el.getBoundingClientRect().top + (window.pageYOffset || 0) - 64; window.scrollTo({ top: Math.max(0, top), behavior: smooth ? "smooth" : "auto" }); return true; } function App() { const [t, setTweak] = window.useTweaks(TWEAK_DEFAULTS); const [lang, setLang] = appUS(() => { try { return localStorage.getItem("umapro-lang") || "ja"; } catch (e) { return "ja"; } }); const [scrolled, setScrolled] = appUS(false); const [parY, setParY] = appUS(0); const [cursor, setCursor] = appUS({ x: -100, y: -100 }); appUE(() => { try { localStorage.setItem("umapro-lang", lang); } catch (e) {} document.body.setAttribute("data-lang", lang); }, [lang]); // Scroll handlers appUE(() => { let raf = 0; const onScroll = () => { if (raf) return; raf = requestAnimationFrame(() => { const y = window.scrollY || 0; setScrolled(y > 24); setParY(Math.min(y, 800)); raf = 0; }); }; window.addEventListener("scroll", onScroll, { passive: true }); onScroll(); return () => window.removeEventListener("scroll", onScroll); }, []); // Reveal observer appUE(() => { const io = new IntersectionObserver( (entries) => { entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } }); }, { threshold: 0.12, rootMargin: "0px 0px -10% 0px" } ); const els = document.querySelectorAll(".reveal"); els.forEach((el) => io.observe(el)); return () => io.disconnect(); }); // Cursor blob appUE(() => { const onMove = (e) => setCursor({ x: e.clientX, y: e.clientY }); window.addEventListener("mousemove", onMove); return () => window.removeEventListener("mousemove", onMove); }, []); // Clean-URL routing (history API) + deep-link scroll on load appUE(() => { const id = sectionFromPath(); if (id) { let tries = 0; const iv = setInterval(() => { if (scrollToId(id, false) || tries++ > 60) clearInterval(iv); }, 50); } const onClick = (e) => { if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey) return; const a = e.target.closest && e.target.closest('a[href^="/"]'); if (!a) return; let url; try { url = new URL(a.getAttribute("href"), location.origin); } catch (err) { return; } if (url.origin !== location.origin) return; const seg = url.pathname.replace(/^\/+|\/+$/g, "").split("/")[0]; const isHome = url.pathname === "/" || url.pathname === ""; if (!isHome && !ROUTES[seg]) return; e.preventDefault(); const target = isHome ? "/" : "/" + seg + "/"; try { if (location.pathname !== target) history.pushState({}, "", target); } catch (err) {} if (isHome) window.scrollTo({ top: 0, behavior: "smooth" }); else scrollToId(ROUTES[seg], true); }; const onPop = () => { const sid = sectionFromPath(); if (sid) scrollToId(sid, true); else window.scrollTo({ top: 0, behavior: "auto" }); }; document.addEventListener("click", onClick); window.addEventListener("popstate", onPop); return () => { document.removeEventListener("click", onClick); window.removeEventListener("popstate", onPop); }; }, []); const content = window.CONTENT[lang]; return ( l.value)} onChange={(v) => setTweak("heroLayout", v)} /> MEGA = 中央巨大タイポ / SPLIT = 画像分割 / STAMP = 重ねスタンプ / TICKER = 巨大マーキー ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render();