// pages.jsx — all public pages for Gamingo Labs const { useState, useEffect } = React; // ── HOME ────────────────────────────────────────────────────────────────────── function PHome({ data, goto }) { const studio = data?.studio || {}; const games = data?.games || []; const services= data?.services || []; const featured = games.filter(g => g.featured); return ( <> {/* HERO */}
{studio.eyebrow || 'Mobile Game Studio & Publisher'}

GAMES
MAKE US!

{studio.subTagline}

{studio.stats?.length > 0 && (
{studio.stats.map((s, i) => (
{s.value}
{s.label}
))}
)}
{/* Featured Games */}
{featured.map(g => )}
{/* Services preview */}
{services.slice(0, 3).map((s, i) => )}
); } // ── GAMES ───────────────────────────────────────────────────────────────────── function PGames({ data }) { const [filter, setFilter] = useState('All'); const games = data?.games || []; const genres = ['All', ...new Set(games.map(g => g.genre))]; const filtered = filter === 'All' ? games : games.filter(g => g.genre === filter); return (
{genres.map(g => ( ))}
{filtered.map(g => )}
); } // ── ABOUT ───────────────────────────────────────────────────────────────────── function PAbout({ data }) { const s = data?.studio || {}; const paras = Array.isArray(s.aboutParagraphs) ? s.aboutParagraphs : [s.description || '']; const values = Array.isArray(s.values) ? s.values : []; return (
{/* Visual */}
GL
Games Make Us!
{/* Copy */}
About Us

WE LIVE & BREATHE GAMES

{paras.filter(Boolean).map((p, i) => (

{p}

))}
{values.map((v, i) => (
{v.title}
{v.desc}
))}
); } // ── SERVICES ────────────────────────────────────────────────────────────────── function PServices({ data, goto }) { const services = data?.services || []; return (
{services.map((s, i) => )}
{/* CTA */}
Publishing Partnership

GOT A GREAT GAME IDEA?

We partner with indie developers to fund, polish, publish, and grow mobile games. Let's talk.

); } // ── BLOG ────────────────────────────────────────────────────────────────────── function PBlog({ data, goto }) { const posts = data?.blog || []; return (
{posts.length === 0 ?

No posts yet — check back soon.

:
{posts.map(p => goto('post', { slug: p.slug || p.id })} />)}
}
); } // ── BLOG POST ───────────────────────────────────────────────────────────────── function PPost({ data, goto, slug }) { const [post, setPost] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { if (!slug) { setLoading(false); return; } // Find in local data first const found = (data?.blog || []).find(p => (p.slug || p.id) === slug); if (found) { setPost(found); setLoading(false); return; } // Try API fetch('/api/blog.php?action=get&slug=' + encodeURIComponent(slug)) .then(r => r.json()) .then(j => { if (j.success && j.post) setPost(j.post); }) .catch(() => {}) .finally(() => setLoading(false)); }, [slug]); if (loading) return
Loading…
; if (!post) return (

Post not found.

); const words = ((post.content || '') + ' ' + (post.excerpt || '')).split(/\s+/).length; const readMin = Math.max(1, Math.ceil(words / 200)); const others = (data?.blog || []).filter(p => (p.slug || p.id) !== slug).slice(0, 3); return (
{post.category}

{post.title}

{glDate(post.published_at || post.date)} · {readMin} min read
{post.image && (
{post.title} e.target.style.display='none'} />
)}
{others.length > 0 && (
More Posts
{others.map(p => goto('post', { slug: p.slug || p.id })} />)}
)}
); } // ── VIDEOS ──────────────────────────────────────────────────────────────────── function PVideos({ data }) { const [gf, setGf] = useState('All'); const [tf, setTf] = useState('All'); const videos = data?.videos || []; const games = data?.games || []; const types = ['All', ...new Set(videos.map(v => v.type))]; const filtered = videos.filter(v => (gf === 'All' || v.gameId === gf) && (tf === 'All' || v.type === tf)); const typeColor = { Gameplay: { bg: 'rgba(0,229,160,.1)', color: 'var(--gl-accent)' }, Tutorial: { bg: 'rgba(255,209,102,.1)', color: 'var(--gl-yellow)' }, Tips: { bg: 'rgba(99,179,237,.1)', color: 'var(--gl-blue)' } }; return (
{games.map(g => )} {types.map(t => )}
{filtered.length === 0 ?

No videos for this filter.

:
{filtered.map(v => { const game = games.find(g => g.id === v.gameId); const tc = typeColor[v.type] || typeColor.Gameplay; return (