// Hero — 4 layouts (mega / split / stamp / ticker) // Exports window.Hero, window.Header, window.Marquee const { useEffect, useState, useRef } = React; // ---------- helper: render JSX from data tokens like {red: "x"} ---------- function renderTokens(arr, accentClass = "red") { return arr.map((tok, i) => { if (typeof tok === "string") return {tok}; if (tok.red) return {tok.red}; if (tok.yellow) return {tok.yellow}; return null; }); } // ---------- Header ---------- function Header({ content, lang, setLang, scrolled }) { const [menuOpen, setMenuOpen] = useState(false); return (
{lang === "ja" ? "株式会社うまプロ" : "Umapro Inc."}
); } // ---------- Marquee strip ---------- function Marquee({ words, variant = "default" }) { const items = []; for (let i = 0; i < 4; i++) { words.forEach((w, j) => { items.push( {w} ); }); } return (
{items}
); } // ---------- Hero ---------- function Hero({ content, layout, lang, parallaxY }) { const heroRef = useRef(null); const photosRef = useRef(null); // Random crossfading food-photo backdrop useEffect(() => { const wrap = photosRef.current; if (!wrap) return; const slides = Array.prototype.slice.call(wrap.children); if (!slides.length) return; const reduced = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; let cur = Math.floor(Math.random() * slides.length); slides[cur].classList.add("show"); if (reduced) return; const id = setInterval(function () { let next = Math.floor(Math.random() * slides.length); if (next === cur) next = (cur + 1) % slides.length; slides[cur].classList.remove("show"); slides[next].classList.add("show"); cur = next; }, 5200); return function () { clearInterval(id); }; }, []); const PHOTOS = ["assets/hero-1.jpg", "assets/hero-2.jpg", "assets/hero-3.jpg", "assets/hero-4.jpg"]; return (
{layout === "mega" && } {layout === "split" && } {layout === "stamp" && } {layout === "ticker" && }
); } function HeroCTAs({ content }) { return (
{content.hero.ctaPrimary} → {content.hero.ctaSecondary}
); } // MEGA — big centered type, stickers floating around with parallax function HeroMega({ content, lang, parallaxY }) { const words = content.hero.titleWords; return (
{content.hero.eyebrow &&
{content.hero.eyebrow}
}

{words.map((w, i) => { const cls = i === 0 ? "word red" : i === words.length - 1 ? "word outline" : "word"; return {w}; })}

{content.hero.sub}

); } // SPLIT — text left, image stack right function HeroSplit({ content, lang, parallaxY }) { const words = content.hero.titleWords; return (
{content.hero.eyebrow &&
{content.hero.eyebrow}
}

{words.map((w, i) => ( {i === 1 ? {w} : i === words.length - 1 ? {w} : w} {i < words.length - 1 && (lang === "en" ? " " : "")} {i === 0 || i === 2 ?
: null}
))}

{content.hero.sub}

); } // STAMP — overlapping rotated kanji words function HeroStamp({ content, lang, parallaxY }) { const words = content.hero.titleWords; return (
{content.hero.eyebrow &&
{content.hero.eyebrow}
}
{words[0]}
{words[2] || words[1]}
{words[3] || words[2]}

{content.hero.sub}

{content.hero.stickers[1].text}
); } // TICKER — three rows of giant scrolling display type function HeroTicker({ content, lang, parallaxY }) { const words = content.hero.titleWords; // build a row of repeating words with separators const buildRow = (text, sep = "★", repeat = 8) => { const items = []; for (let i = 0; i < repeat; i++) { items.push({text}); items.push({sep}); } return items; }; return (
{content.hero.eyebrow &&
{content.hero.eyebrow}
}
{buildRow(words[0])}{buildRow(words[0])}
{buildRow(words[2] || words[1])}{buildRow(words[2] || words[1])}
{buildRow(words[3] || words[2])}{buildRow(words[3] || words[2])}

{content.hero.sub}

); } Object.assign(window, { Header, Hero, Marquee, renderTokens, });