const { useState, useEffect, useCallback, useRef } = React; const SK_GAMES = "jar-games-v4"; const SK_LOGO = "jar-logo-v3"; const SK_FAVS = "jar-favs-v1"; const SK_PLAYS = "jar-plays-v1"; const SAMPLE = [ { id:"1", title:"Asphalt Urban GT", synopsis:"Corridas de rua pelas mais famosas metrópoles do mundo. Pilote carros exóticos, desvie do tráfego e ultrapasse seus rivais.", content:"Asphalt Urban GT marcou a fase em que jogos de corrida começaram a parecer mais ambiciosos nos celulares Java. Esta página reúne informações para catalogação, memória afetiva e preservação histórica: estilo de jogo, ano aproximado, gênero, observações de compatibilidade e espaço para imagens do acervo. Antes de publicar um arquivo jogável, confirme se você possui direito de distribuição ou se ele foi liberado oficialmente.", jarUrl:"", coverBase64:"", genre:"Corrida", year:"2004", gallery:[] }, { id:"2", title:"Bomberman", synopsis:"O lendário Bomberman chegou ao celular! Posicione bombas para eliminar inimigos e abrir passagens nos labirintos.", content:"Bomberman é lembrado por partidas rápidas, labirintos simples e decisões de posicionamento. No celular, a experiência dependia muito do teclado numérico e da resolução da tela. Use este espaço para registrar versão, fabricante, controles, idioma, resolução recomendada e observações sobre desempenho no emulador.", jarUrl:"", coverBase64:"", genre:"Ação", year:"2003", gallery:[] }, { id:"3", title:"Snake II", synopsis:"O eterno clássico do Nokia. Guie sua cobra para devorar pontos sem colidir com as paredes ou com seu próprio corpo.", content:"Snake II representa uma das formas mais reconhecíveis de jogo mobile clássico: regras simples, dificuldade crescente e partidas curtas. Esta entrada pode servir como ficha histórica, com descrição de mecânicas, curiosidades, pontuação, versões conhecidas e diferenças entre aparelhos.", jarUrl:"", coverBase64:"", genre:"Clássico",year:"2002", gallery:[] }, { id:"4", title:"Real Football 2006", synopsis:"Futebol completo na palma da mão. Jogos, ligas, campeonatos e times reais numa experiência incrível para celular.", content:"Real Football 2006 faz parte de uma geração de jogos esportivos Java que tentava adaptar campeonatos, passes, chutes e escalações para telas pequenas. Ao cadastrar uma versão, inclua informações sobre resolução, idioma, modo de jogo, compatibilidade e origem autorizada do arquivo.", jarUrl:"", coverBase64:"", genre:"Esporte", year:"2005", gallery:[] }, { id:"5", title:"Zuma", synopsis:"Atire esferas coloridas para eliminar cadeias antes que cheguem ao fim. Viciante e cheio de fases desafiadoras.", content:"Zuma combina raciocínio rápido, mira e combinação de cores. Em celulares antigos, jogos desse tipo se destacavam por sessões curtas e controles simples. Esta ficha pode reunir dicas, descrição de fases, observações de jogabilidade e imagens próprias enviadas pelo administrador.", jarUrl:"", coverBase64:"", genre:"Puzzle", year:"2005", gallery:[] }, ]; const LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); const NUMS = "0123456789".split(""); const ALPHA = ["TODOS",...LETTERS,"0-9","#"]; const GCOLORS = { Corrida:"#e52020",Ação:"#e52020",Clássico:"#ffd23f",RPG:"#a78bfa",Esporte:"#34d399",Puzzle:"#60a5fa",Aventura:"#f97316",Luta:"#fb7185",Estratégia:"#22d3ee",Outro:"#94a3b8" }; const GENRES = Object.keys(GCOLORS); const R="#e52020", R2="#b81818"; const ra = o=>`rgba(229,32,32,${o})`; const gc = g=>GCOLORS[g]||GCOLORS.Outro; const uid= ()=>Math.random().toString(36).slice(2,10); const fl = t=>(t?.[0]||"?").toUpperCase(); function charGroup(t){ const c=fl(t); if(LETTERS.includes(c)) return c; if(NUMS.includes(c)) return "0-9"; return "#"; } async function uploadFile(file){ if(window.uploadAsset) return window.uploadAsset(file); return new Promise((res,rej)=>{const r=new FileReader();r.onload=()=>res(r.result);r.onerror=rej;r.readAsDataURL(file);}); } const inp={width:"100%",background:"rgba(255,255,255,0.03)",border:`1px solid ${ra(0.15)}`,borderRadius:8,padding:"10px 12px",color:"#e2e8f0",fontSize:12,outline:"none",boxSizing:"border-box",fontFamily:"'IBM Plex Mono',monospace"}; const lbl={fontSize:9,letterSpacing:"0.2em",color:R,marginBottom:6,display:"block"}; function UploadBtn({accept,onFile,children}){ const ref=useRef(); return(<>{if(e.target.files[0]){try{const b=await uploadFile(e.target.files[0]);onFile(b);}catch(err){alert(err.message||"Nao foi possivel enviar o arquivo.");}e.target.value="";}}}/>); } // ── HEADER ───────────────────────────────────────────────────────────────── const DEFAULT_LOGO="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"; function Header({logo,onAdmin,onHome,favCount}){ const src=logo||`data:image/png;base64,${DEFAULT_LOGO}`; return(
{favCount>0&&
♥ {favCount}
}
); } // ── GAME CARD ────────────────────────────────────────────────────────────── function Card({game,onClick,isFav,onToggleFav,playCount}){ const [hov,setHov]=useState(false); const c=gc(game.genre); return(
setHov(true)} onMouseLeave={()=>setHov(false)} style={{cursor:"pointer",background:hov?ra(0.06):"rgba(255,255,255,0.02)",border:`1px solid ${hov?ra(0.4):"rgba(255,255,255,0.07)"}`,borderRadius:12,overflow:"hidden",transition:"all 0.25s",transform:hov?"translateY(-3px)":"none",boxShadow:hov?`0 8px 32px ${ra(0.15)}`:"none",position:"relative"}}>
onClick(game)} style={{height:140,background:`linear-gradient(135deg,${ra(0.08)},rgba(6,6,14,0.9))`,display:"flex",alignItems:"center",justifyContent:"center",position:"relative",borderBottom:"1px solid rgba(255,255,255,0.05)"}}> {game.coverBase64?{game.title} :
{fl(game.title)}
} {game.genre&&
{game.genre.toUpperCase()}
} {playCount>0&&
▶ {playCount}x
} {game.year&&
{game.year}
}
onClick(game)} style={{padding:"12px 14px 14px"}}>
{game.title}
{game.synopsis||"Sem sinopse."}
VER JOGO
); } // ── HORIZONTAL SCROLL ROW ────────────────────────────────────────────────── function HScroll({games,onClick,favs,onToggleFav,plays}){ return(
{games.map(g=>(
))}
); } // ── LIBRARY ──────────────────────────────────────────────────────────────── function Library({games,favs,plays,onSelect,onToggleFav}){ const [q,setQ]=useState(""); const [letter,setLetter]=useState("TODOS"); const [showFilters,setShowFilters]=useState(false); const [genreFilter,setGenreFilter]=useState("TODOS"); const [sortBy,setSortBy]=useState("az"); const [yearFrom,setYearFrom]=useState(""); const [yearTo,setYearTo]=useState(""); const [showFavs,setShowFavs]=useState(false); // Most played top 5 const topPlayed=[...games].filter(g=>(plays[g.id]||0)>0).sort((a,b)=>(plays[b.id]||0)-(plays[a.id]||0)).slice(0,8); // By genre groups for featured section const featuredGenres=[...new Set(games.map(g=>g.genre).filter(Boolean))].slice(0,6); const activeFilters=[genreFilter!=="TODOS",yearFrom,yearTo,showFavs,q].filter(Boolean).length; let filtered=[...games]; if(showFavs) filtered=filtered.filter(g=>favs.includes(g.id)); if(q) filtered=filtered.filter(g=>g.title.toLowerCase().includes(q.toLowerCase())||g.genre?.toLowerCase().includes(q.toLowerCase())||g.synopsis?.toLowerCase().includes(q.toLowerCase())); if(letter!=="TODOS") filtered=filtered.filter(g=>charGroup(g.title)===letter); if(genreFilter!=="TODOS") filtered=filtered.filter(g=>g.genre===genreFilter); if(yearFrom) filtered=filtered.filter(g=>parseInt(g.year||0)>=parseInt(yearFrom)); if(yearTo) filtered=filtered.filter(g=>parseInt(g.year||9999)<=parseInt(yearTo)); filtered.sort((a,b)=>{ if(sortBy==="az") return a.title.localeCompare(b.title); if(sortBy==="za") return b.title.localeCompare(a.title); if(sortBy==="popular") return (plays[b.id]||0)-(plays[a.id]||0); if(sortBy==="recent") return parseInt(b.year||0)-parseInt(a.year||0); if(sortBy==="old") return parseInt(a.year||0)-parseInt(b.year||0); if(sortBy==="favs") return favs.includes(b.id)?1:favs.includes(a.id)?-1:0; return 0; }); const grouped=filtered.reduce((acc,g)=>{ const l=charGroup(g.title);if(!acc[l])acc[l]=[];acc[l].push(g);return acc; },{}); const sortedGroups=Object.keys(grouped).sort((a,b)=>{ if(sortBy!=="az"&&sortBy!=="za") return 0; if(a=="#")return 1;if(b=="#")return -1; if(a==="0-9")return b=="#"?-1:1;if(b==="0-9")return a=="#"?1:-1; return a.localeCompare(b); }); const resetFilters=()=>{setGenreFilter("TODOS");setYearFrom("");setYearTo("");setShowFavs(false);setSortBy("az");setLetter("TODOS");setQ("");}; return(
{/* HERO */}
● ONLINE ● {games.length} JOGOS DISPONÍVEIS

BIBLIOTECA
.Jar

JOGOS CLÁSSICOS DE CELULAR EM SEU NAVEGADOR

{/* MAIS POPULARES */} {topPlayed.length>0&&(
🔥 MAIS JOGADOS
)} {/* CATEGORIAS EM DESTAQUE */} {featuredGenres.length>0&&!showFavs&&!q&&letter==="TODOS"&&genreFilter==="TODOS"&&(
🎮 CATEGORIAS
{featuredGenres.map(g=>{ const c=gc(g); const count=games.filter(gm=>gm.genre===g).length; return( ); })}
)} {/* SEARCH + FILTERS */}
setQ(e.target.value)} placeholder="Buscar por nome, gênero, descrição..." style={{...inp,padding:"11px 14px 11px 38px"}} onFocus={e=>e.target.style.borderColor=ra(0.5)} onBlur={e=>e.target.style.borderColor=ra(0.15)}/>
{/* Advanced filters panel */} {showFilters&&(
setYearFrom(e.target.value)} placeholder="Ex: 2000" style={{...inp,fontSize:11}}/>
setYearTo(e.target.value)} placeholder="Ex: 2010" style={{...inp,fontSize:11}}/>
{activeFilters>0&&(
)}
)}
{/* ALPHABET FILTER */}
{ALPHA.map((l,i)=>( {l==="0-9"&&} ))}
{/* RESULTS HEADER */}
{filtered.length} jogo{filtered.length!==1?"s":""} encontrado{filtered.length!==1?"s":""} {showFavs?" · ♥ favoritos":""} {genreFilter!=="TODOS"?` · ${genreFilter}`:""}
{activeFilters>0&&}
{/* GAMES GRID */} {filtered.length===0 ?
?
NENHUM JOGO ENCONTRADO
:(sortBy==="az"||sortBy==="za" ?sortedGroups.map(l=>(
{l}
{grouped[l].map(g=>)}
)) :
{filtered.map(g=>)}
) }
); } // ── DETAIL ───────────────────────────────────────────────────────────────── function Detail({game,onPlay,onBack,isFav,onToggleFav,playCount}){ const c=gc(game.genre); return(
{game.coverBase64&&{game.title}}
{fl(game.title)}
{game.genre&&
{game.genre.toUpperCase()}
}
{game.year&&{game.year}} {playCount>0&&▶ {playCount} vezes jogado}

{game.title}

// SINOPSE

{game.synopsis||"Sem sinopse."}

{game.content&&(
// SOBRE O JOGO

{game.content}

)} {game.gallery?.length>0&&(
// GALERIA
{game.gallery.map((img,i)=>{`ss${i}`})}
)} {!game.jarUrl ?
⚠ URL do .JAR não configurada — adicione via painel
: }
); } // ── EMULATOR ─────────────────────────────────────────────────────────────── function Emulator({game,onBack}){ return(
{game.title}
{[...Array(6)].map((_,i)=>
)}
{game.jarUrl ?