import { useEffect, useMemo, useState } from 'react' import PublicLayout from '../../components/PublicLayout.jsx' import HeroElement from '../../components/HeroElement.jsx' import { useSite } from '../../contexts/SiteContext.jsx' import { api } from '../../api/client.js' import { defaultLayout, parseLayout, heroBackground } from '../../lib/heroLayout.js' // Admin "Preview" opens the portal with ?preview=1 to render the unpublished draft. const PREVIEW = typeof window !== 'undefined' && new URLSearchParams(window.location.search).get('preview') === '1' export default function Portal() { const { settings } = useSite() const teaser = settings.homepage_teaser || 'Mysticmoon is still being shaped beneath a midnight sky — a quiet preview for the news, screenshots, guides, and community notes to come as the world wakes.' // Published layout (public). Falls back to the pre-populated default if missing, // malformed, the wrong version, or empty — so the hero is never blank. const published = useMemo(() => parseLayout(settings.hero_layout), [settings.hero_layout]) // In preview mode, pull the draft via the admin endpoint (requires a logged-in // admin cookie); falls back silently to the published/default layout otherwise. const [draft, setDraft] = useState(null) useEffect(() => { if (!PREVIEW) return let active = true api.admin .getSettings() .then((s) => active && setDraft(parseLayout(s.hero_layout_draft))) .catch(() => {}) return () => { active = false } }, []) const active = (PREVIEW && draft) || (published && published.elements.length ? published : null) const layout = active || defaultLayout(teaser) const isDefault = !active const bgStyle = heroBackground(layout, { isDefault }) const elements = [...layout.elements].sort((a, b) => (a.z || 0) - (b.z || 0)) return (
{PREVIEW && draft && (
Preview — showing unpublished draft
)}
{elements.map((el) => ( ))}
) }