// components.jsx — theme-aware homepage sections for saraslot // Loaded after React + Babel. Exports components on window. const { useState, useEffect, useRef, useCallback } = React; /* ───────────────────────────────────────────────────────────── ICONS — minimal inline SVG/text for reliability ──────────────────────────────────────────────────────────── */ const Icon = ({ name, size = 18, color = "currentColor" }) => { const s = size, c = color; switch (name) { case "soccer": return ; case "trophy": return ; case "crown": return ; case "ticket": return ; case "home": return ; case "history": return ; case "chat": return ; case "settings": return ; case "slot": return ; case "live": return ; case "esport": return ; case "lightning": return ; case "menu": return ; case "invite": return ; case "link": return ; case "downline": return ; case "gift": return ; case "female": return ♀; default: return null; } }; window.Icon = Icon; /* ───────────────────────────────────────────────────────────── Logo — theme-specific ──────────────────────────────────────────────────────────── */ function Logo({ theme }) { const b = window.useBranding ? window.useBranding() : window.BRANDING_DEFAULTS; const w1 = b.brand_word_1, w2 = b.brand_word_2; if (theme === "jade") { return (
寶
{w1}{w2}
); } if (theme === "neon") { return (
{w1}{w2}
); } return (
{w1}{w2}
); } window.Logo = Logo; /* ───────────────────────────────────────────────────────────── AppDownloadBanner — sourced from site_settings('app_banner') ──────────────────────────────────────────────────────────── */ function AppDownloadBanner({ onDismiss }) { const q = window.useSiteSetting ? window.useSiteSetting("app_banner") : { data: null }; const cfg = (q.data && q.data.value) || { title: "App · Download And Play Now!", rating: "4.9", users: "50K+ players", show: true }; if (cfg.show === false) return null; return (
{cfg.title}
★★★★★ {cfg.rating} · {cfg.users}
); } window.AppDownloadBanner = AppDownloadBanner; /* ───────────────────────────────────────────────────────────── Header ──────────────────────────────────────────────────────────── */ function Header({ theme, navigate, onOpenLogin, onOpenRegister }) { const { session } = (window.useSession ? window.useSession() : { session: null }); const profileQuery = window.useProfile ? window.useProfile() : { data: null }; const profile = profileQuery && profileQuery.data; const b = window.useBranding ? window.useBranding() : window.BRANDING_DEFAULTS; const [menuOpen, setMenuOpen] = useState(false); const goHome = () => { if (navigate) navigate("/"); else window.location.hash = "/"; }; const handleLogout = async () => { setMenuOpen(false); if (window.signOut) await window.signOut(); }; return (
{!session && ( <> )} {session && ( )}
{session && menuOpen && (
setMenuOpen(false)}>
)}
); } window.Header = Header; /* ───────────────────────────────────────────────────────────── HeroCarousel — slides from `hero_slides` table ──────────────────────────────────────────────────────────── */ const FALLBACK_HERO_SLIDES = [ { eyebrow: "Welcome", title: "SARASLOT", big: "PLAY NOW", body: "Loading promotions…", cta_label: "Explore", art: "medal" }, ]; function MedalArt({ theme }) { if (theme === "neon") { return ( REBATE 6% ); } if (theme === "jade") { return ( REBATE 6% 福 ); } return ( {/* Outer 8-point star */} REBATE 6% ); } function CoinsArt({ theme }) { const coinColors = theme === "neon" ? ["#39FF14", "#00F0FF", "#FF00C8"] : theme === "jade" ? ["#D4AF37", "#C8102E", "#D4AF37"] : ["#FFD24A", "#FFB800", "#E60012"]; return ( {[[24, 22], [80, 18], [44, 50], [86, 60], [18, 78], [70, 92]].map((p, i) => ( $ ))} ); } function BallArt({ theme }) { if (theme === "neon") { return ( ); } return ( ); } function HeroArtBySlide({ slide, theme }) { if (slide.art === "coins") return ; if (slide.art === "ball") return ; return ; } function HeroCarousel({ theme }) { const q = window.useHeroSlides ? window.useHeroSlides() : { data: null }; const slides = (Array.isArray(q.data) && q.data.length > 0) ? q.data : FALLBACK_HERO_SLIDES; const b = window.useBranding ? window.useBranding() : window.BRANDING_DEFAULTS; const [idx, setIdx] = useState(0); const pausedRef = useRef(false); const total = slides.length; useEffect(() => { if (idx >= total) setIdx(0); }, [total, idx]); useEffect(() => { if (total <= 1) return; const t = setInterval(() => { if (!pausedRef.current) setIdx((i) => (i + 1) % total); }, 5000); return () => clearInterval(t); }, [total]); const slide = slides[Math.min(idx, total - 1)] || FALLBACK_HERO_SLIDES[0]; return (
{ pausedRef.current = true; }} onTouchEnd={() => { pausedRef.current = false; }} onMouseEnter={() => { pausedRef.current = true; }} onMouseLeave={() => { pausedRef.current = false; }} >
{slide.eyebrow}

{slide.title}

{slide.big}

{slide.body}

{slides.map((_, i) => ( setIdx(i)} /> ))}
{b.brand_strip_pre} {b.brand_strip_accent} {b.brand_strip_post}
); } window.HeroCarousel = HeroCarousel; /* ───────────────────────────────────────────────────────────── Marquee — items from `marquee_items` table ──────────────────────────────────────────────────────────── */ function MarqueeStrip() { const q = window.useMarqueeItems ? window.useMarqueeItems() : { data: [] }; const items = (Array.isArray(q.data) ? q.data : []).map((r) => r.body); if (items.length === 0) return null; const content = ( {items.map((t, i) => ( {t} · ))} ); return (
{content} {content}
); } window.MarqueeStrip = MarqueeStrip; /* ───────────────────────────────────────────────────────────── FeatureCardRow — feature_cards table ──────────────────────────────────────────────────────────── */ function FeatureCardRow({ theme }) { const q = window.useFeatureCards ? window.useFeatureCards() : { data: [] }; const cards = Array.isArray(q.data) ? q.data : []; if (cards.length === 0) return null; return (
{cards.map((c) => (
{c.label}
{c.sub}
{c.icon}
))}
); } window.FeatureCardRow = FeatureCardRow; /* ───────────────────────────────────────────────────────────── ReferralBar — copy from site_settings('referral_copy') ──────────────────────────────────────────────────────────── */ function ReferralBar({ theme }) { const q = window.useSiteSetting ? window.useSiteSetting("referral_copy") : { data: null }; const cfg = (q.data && q.data.value) || { title: "Referral", sub: "Share to Earn More!" }; return (
{cfg.title}
{cfg.sub}
); } window.ReferralBar = ReferralBar; Object.assign(window, { Icon, Logo, AppDownloadBanner, Header, HeroCarousel, MarqueeStrip, FeatureCardRow, ReferralBar });