// components.jsx — shared primitives for たつた連泊プランLP // HP-style: Noto Serif JP ruled, generous whitespace, hairline dividers, muted earth. function useIsMobile() { const [isMobile, setIsMobile] = React.useState(window.innerWidth <= 768); React.useEffect(() => { const h = () => setIsMobile(window.innerWidth <= 768); window.addEventListener('resize', h, { passive: true }); return () => window.removeEventListener('resize', h); }, []); return isMobile; } // Photo element with caption function Photo({ src, alt, height, ratio, caption, fit = 'cover' }) { const style = ratio ? { width: '100%', aspectRatio: ratio } : { width: '100%', height }; return (
{alt
{caption && (
— {caption}
)}
); } // HP-style section heading: English eyebrow + Japanese title, thin hairlines function SectionHeading({ eyebrow, title, sub, align = 'center', light = false }) { const ink = light ? '#F7F3E8' : '#2B2620'; const muted = light ? 'rgba(247,243,232,0.55)' : 'rgba(60,52,40,0.55)'; const line = light ? 'rgba(247,243,232,0.4)' : 'rgba(60,52,40,0.35)'; return (
{eyebrow}

{title}

{sub && (

{sub}

)}
); } // Top bar — minimal, mix-blend like HP function TopBar() { const isMobile = useIsMobile(); const site = window.SITE_INFO || {}; return (
{site.siteNameJa || '湯ヶ島 たつた'} {site.siteNameEn || 'Yugashima Tatsuta'}
{!isMobile && ( )}
); } const navLink = { color: 'inherit', textDecoration: 'none', opacity: 0.9 }; // Floating reserve button function FloatingCTA() { const site = window.SITE_INFO || {}; const [on, setOn] = React.useState(false); React.useEffect(() => { const h = () => setOn(window.scrollY > 600); h(); window.addEventListener('scroll', h, { passive: true }); return () => window.removeEventListener('scroll', h); }, []); return ( {site.ctaLabel || '連 泊 を 予 約 す る →'} ); } Object.assign(window, { Photo, SectionHeading, TopBar, FloatingCTA, useIsMobile });