/* PANEL SAAS · Orgullo Millonario — React + Tailwind · Liquid Glass Conectado a OM-DB: lo que se edita aquí se refleja EN VIVO en la página principal (site.html). */ const {useState,useEffect,useRef,useMemo,useSyncExternalStore,createContext,useContext}=React; const useDB=()=>useSyncExternalStore(OMDB.subscribe,OMDB.get); /* ============ ICONS ============ */ const I={ dash:, card:<>, squad:<>, spark:, gift:<>, heart:, play:<>, chat:, grid:<>, bell:, search:<>, x:, down:, eye:<>, drag:<>, users:<>, trophy:<>, video:<>, plus:, trash:<>, }; const Ic=({n,s=18,c=""})=>{I[n]}; /* ============ TOAST ============ */ const ToastCtx=createContext(()=>{}); function ToastHost({children}){ const [msg,setMsg]=useState(null);const t=useRef(); const toast=m=>{setMsg(m);clearTimeout(t.current);t.current=setTimeout(()=>setMsg(null),2400);}; return {children}
{msg}
; } /* ============ SHARED ============ */ const Sec=({label,children,right})=>(
{label}{right}
); const Bar=({pct,cls})=>(
); /* ============ MODULES ============ */ function KpiModule(){ const db=useDB();const k=db.kpis; const kpis=[[k.viajes,"VIAJES PUBLICADOS","#2f7df6","🚌"],[k.reservas,"RESERVAS","#22c55e","📅"],[k.socios,"SOCIOS","#ffcf3e","👤"],[k.visitas,"VISITAS TOTALES","#ff2e3e","👁"]]; return
{kpis.map(([n,l,c,e],i)=>(
{n}{e}
{l}
))}
; } /* ============ SITIO & HERO — controla la página principal EN VIVO ============ */ function SiteModule(){ const db=useDB();const toast=useContext(ToastCtx);const c=db.config; const heroRef=useRef(); const [drag,setDrag]=useState(null); const secs=c.sections||[]; const modular=!!c.modular; const [ak,setAk]=useState('');const [al,setAl]=useState('128');const [at,setAt]=useState('435');const [asn,setAsn]=useState('2025'); const [live,setLive]=useState(()=>!!(window.OMDB&&OMDB.isLive&&OMDB.isLive())); const conectarAPI=async()=>{if(!ak.trim()){toast('Pegá tu API key de API-Football');return;}toast('Conectando con la API…');const ok=await OMDB.setAPI({key:ak.trim(),league:+al,season:+asn,team:+at});setLive(ok);toast(ok?'✔ Datos EN VIVO desde la API':'No se pudo conectar · sigue en DEMO');}; const F=({label,val,onChange,mono})=>( ); const onHero=e=>{const f=e.target.files&&e.target.files[0];if(!f)return;if(f.size>4.5e6){toast('Imagen muy grande (máx 4.5MB)');return;}const r=new FileReader();r.onload=()=>{OMDB.set('config.hero_img',r.result);toast('Imagen del hero actualizada en el sitio');};r.readAsDataURL(f);}; const move=(from,to)=>{if(from===to||to<0||to>=secs.length)return;OMDB.update(s=>{const a=s.config.sections;const [it]=a.splice(from,1);a.splice(to,0,it);});}; const toggleSec=i=>OMDB.update(s=>{s.config.sections[i].on=!s.config.sections[i].on;}); const toggleBlk=(i,j)=>OMDB.update(s=>{s.config.sections[i].blocks[j].on=!s.config.sections[i].blocks[j].on;}); const allOn=v=>OMDB.update(s=>{s.config.sections.forEach(x=>{x.on=v;(x.blocks||[]).forEach(b=>b.on=v);});}); return <> ABRIR SITIO ↗}/>
OMDB.set('config.hero_titulo',v)}/> OMDB.set('config.hero_subtitulo',v)}/>
OMDB.set('config.whatsapp',v)} mono/> OMDB.set('config.mp_link',v)} mono/>
IMAGEN DEL HERO
TEMA DEL SITIO
{[['dark','Oscuro'],['light','Claro']].map(([t,l])=>( ))}
{/* ===== MODULARIZACIÓN (master switch · solo desde el panel) ===== */}
{/* ===== DATOS REALES · API-FOOTBALL ===== */}
{live?'● EN VIVO':'● DEMO'}}/>

Liga 128 = Liga Profesional Argentina · Equipo 435 = River Plate · sin key funciona en DEMO

{/* ===== CONSTRUCTOR DEL SITIO ===== */}
}/>
{secs.map((sc,i)=>(
setDrag(i)} onDragEnd={()=>setDrag(null)} onDragOver={e=>{e.preventDefault();if(drag!==null&&drag!==i){move(drag,i);setDrag(i);}}} className="flex items-center gap-2.5 px-3 py-2.5 cursor-grab active:cursor-grabbing"> {sc.label} {sc.blocks&&{sc.blocks.filter(b=>b.on).length}/{sc.blocks.length} bloques} #{i+1}
{sc.on&&sc.blocks&&sc.blocks.length>0&&
{sc.blocks.map((b,j)=>(
{b.label}
))}
}
))}
; } function RevenueModule(){ return <> $24.900/mes}/>
{[["$24.900","MES ACTUAL","text-gold2"],["$1.22M","META ANUAL","text-ink"],["20,41%","PROGRESO","text-green-400"],["21","OPERACIONES","text-ink"]].map(([b,s,c],i)=>(
{b}{s}
))}
OBJETIVO ANUAL20,41%
; } function WorldModule(){ const dots=useMemo(()=>{ let seed=77;const rnd=()=>((seed=(seed*1103515245+12345)&0x7fffffff)/0x7fffffff); const zones=[[18,18,55,32,.5],[55,52,28,48,.6],[112,12,40,26,.5],[118,40,32,38,.55],[150,14,60,40,.5],[196,60,26,20,.45]]; const a=[];zones.forEach(z=>{for(let i=0;i EN VIVO}/> {dots.map((d,i)=>)} {hot.map((p,i)=>)}
882VISITAS
138HOY
; } function ReferidosModule(){ const db=useDB();const toast=useContext(ToastCtx);const r=db.referidos; const list=[...r.lista].sort((a,b)=>b.ganancia-a.ganancia); const total=list.reduce((s,x)=>s+x.ganancia,0); const invit=list.reduce((s,x)=>s+x.invitados,0); const activos=list.reduce((s,x)=>s+x.activos,0); const max=Math.max(...list.map(x=>x.ganancia),1); const fmt=n=>'$'+n.toLocaleString('es-AR'); return <> {r.comision_pct}% C/SOCIO}/>
{[[fmt(total),'GANANCIA TOTAL','text-green-400'],[invit,'INVITADOS','text-ink'],[activos,'SOCIOS ACTIVOS','text-gold2']].map(([b,s,cc],i)=>(
{b}{s}
))}
{list.map((x,i)=>(
{i+1}
{x.nombre}{x.codigo}
{fmt(x.ganancia)} {x.invitados} inv · {x.activos} act
))}
; } function FiguritasModule(){ const toast=useContext(ToastCtx); const RZ=[["COMÚN","#9a9aa6"],["PLATA","#c0c0cb"],["ORO","#ffcf3e"],["LEYENDA","#ff2e3e"],["HOLOGRÁFICA","#8b5cf6"],["ULTRA PREMIUM","#22d3ee"]]; const CLUBS=[["River","assets/river.png"],["Boca","assets/boca.png"],["Barracas","assets/barracas.png"],["Racing","assets/racing.png"],["Talleres","assets/talleres.png"],["Argentinos","assets/argentinos.png"]]; const FLAGS=["🇦🇷","🇧🇷","🇺🇾","🇨🇴","🇨🇱","🇵🇾","🇻🇪"]; const [rz,setRz]=useState(4); const [name,setName]=useState("Franco Armani"); const [num,setNum]=useState("23"); const [pos,setPos]=useState("ARQ"); const [club,setClub]=useState(0); const [flag,setFlag]=useState(0); const [photo,setPhoto]=useState("assets/armani.png"); const [imgH,setImgH]=useState(108); const [imgY,setImgY]=useState(0); const fileRef=useRef(); const c=RZ[rz][1]; const onFile=e=>{const f=e.target.files&&e.target.files[0];if(!f)return;if(f.size>4.5e6){toast('Imagen muy grande (máx 4.5MB)');return;}const r=new FileReader();r.onload=()=>{setPhoto(r.result);toast('Imagen del jugador cargada');};r.readAsDataURL(f);}; const crear=()=>{ if(!name.trim()){toast('Poné un nombre');return;} OMDB.update(s=>{s.figuritas=[{clave:'c'+Date.now(),nombre:name.trim(),tier:RZ[rz][0],img:photo,tenida:true,cant:1,num,pos,flag:FLAGS[flag],club:CLUBS[club][1]},...s.figuritas].slice(0,20);}); toast(`✔ ${name} (${RZ[rz][0]}) publicada en el álbum del sitio`); }; const exportPNG=async()=>{ const W=520,H=728,cv=document.createElement('canvas');cv.width=W;cv.height=H;const x=cv.getContext('2d'); const rr=(a,b,w,h,r)=>{x.beginPath();x.moveTo(a+r,b);x.arcTo(a+w,b,a+w,b+h,r);x.arcTo(a+w,b+h,a,b+h,r);x.arcTo(a,b+h,a,b,r);x.arcTo(a,b,a+w,b,r);x.closePath();}; rr(0,0,W,H,40);x.clip(); const g=x.createLinearGradient(0,0,W,H);g.addColorStop(0,c+'55');g.addColorStop(.5,'#1a1226');g.addColorStop(1,'#0b0714');x.fillStyle=g;x.fillRect(0,0,W,H); const load=src=>new Promise(res=>{const im=new Image();im.crossOrigin='anonymous';im.onload=()=>res(im);im.onerror=()=>res(null);im.src=src;}); const pl=await load(photo); if(pl){const ph=H*(imgH/100),pw=ph*(pl.width/pl.height);x.drawImage(pl,(W-pw)/2,H-ph+imgY*3,pw,ph);} const ov=x.createLinearGradient(0,H*0.45,0,H);ov.addColorStop(0,'rgba(0,0,0,0)');ov.addColorStop(1,'rgba(0,0,0,.95)');x.fillStyle=ov;x.fillRect(0,H*0.45,W,H*0.55); // iridescent rainbow (identifica la rareza + holográfico) x.save();x.globalCompositeOperation='overlay';x.globalAlpha=.45;x.translate(W/2,H*0.42);x.rotate(-0.9); const cols=['#ff0078','#00c8ff','#78ff50','#ffdc00']; for(let i=-34;i<34;i++){x.fillStyle=cols[((i%4)+4)%4];x.fillRect(i*24,-H,12,H*2);} x.restore(); x.save();x.globalCompositeOperation='color-dodge';x.globalAlpha=.32;x.translate(W/2,H*0.42);x.rotate(-0.9); for(let i=-34;i<34;i++){x.fillStyle=(i%2?c:'#ffffff');x.fillRect(i*18,-H,7,H*2);} x.restore(); // holo streak const hs=x.createLinearGradient(0,0,W,H);hs.addColorStop(.3,'rgba(255,255,255,0)');hs.addColorStop(.46,'rgba(255,255,255,.5)');hs.addColorStop(.5,c);hs.addColorStop(.54,'rgba(255,255,255,.4)');hs.addColorStop(.68,'rgba(255,255,255,0)');x.fillStyle=hs;x.fillRect(0,0,W,H); // flag + number x.font='40px serif';x.fillText(FLAGS[flag],24,58); x.fillStyle='rgba(255,255,255,.14)';x.font='900 120px Oswald, sans-serif';x.textAlign='right';x.fillText(num,W-28,150); // name + tier x.textAlign='center';x.fillStyle='#fff';x.font='700 46px Oswald, sans-serif';x.fillText(name.toUpperCase().slice(0,16),W/2,H-92); x.fillStyle=c;x.font='700 22px "JetBrains Mono", monospace';x.fillText(RZ[rz][0]+' · #'+num,W/2,H-54); // border x.strokeStyle=c;x.lineWidth=8;rr(4,4,W-8,H-8,36);x.stroke(); const club_im=await load(CLUBS[club][1]);if(club_im){x.drawImage(club_im,W-84,24,56,56);} const a=document.createElement('a');a.download=`figurita-${name.toLowerCase().replace(/\s+/g,'-')||'cromo'}.png`;a.href=cv.toDataURL('image/png');a.click(); toast('PNG descargado ✔'); }; return <>
setName(e.target.value)} className="w-full bg-white/[.06] border border-white/10 rounded-2xl px-4 py-3 text-[13px] font-semibold outline-none focus:border-river/60 transition-colors" placeholder="Nombre del jugador"/>
setNum(e.target.value.slice(0,3))} className="bg-white/[.06] border border-white/10 rounded-xl px-3 py-2 text-[11px] font-mono text-center outline-none focus:border-river/60 min-w-0" placeholder="N°"/>

PNG recortado del jugador · fondo transparente ideal · máx 4.5MB

{RZ.map(([r,cc],i)=>( ))}
{CLUBS.map(([n,src],i)=>)}
{FLAGS.map((f,i)=>)}
ZOOMsetImgH(+e.target.value)} className="flex-1"/>{imgH}%
ALTURAsetImgY(+e.target.value)} className="flex-1"/>{imgY}
VISTA PREVIA EN VIVO
{name} {FLAGS[flag]} {num}
{name.toUpperCase()||'—'} {RZ[rz][0]} · #{num}
; } function PlantillaModule(){ const toast=useContext(ToastCtx); const G=[["① ARQUEROS",[["armani","Armani","#1"]]], ["② DEFENSORES",[["montiel","Montiel","#4"],["pezzella","Pezzella","#6"],["diaz","Paulo Díaz","#17"]]], ["③ MEDIOCAMPISTAS",[["perez","E. Pérez","#24"],["castano","Castaño","#20"],["quintero","Quintero","#10"]]], ["④ FORWARDS",[["borja","Borja","#9"],["colidio","Colidio","#11"],["salas","M. Salas","#7"]]]]; return <> 40 EN PLANTEL}/>
{G.map(([lbl,ps])=>
{lbl}
{ps.map(([img,n,num])=>(
{n}{num}
))}
)}
; } function SponsorsModule(){ const toast=useContext(ToastCtx); const tiers=[["ORO","text-gold2","rgba(212,164,55,.35)",[Betano,"CODERE","GATORADE"]], ["PLATA","text-[#c0c0cb]","rgba(192,192,203,.25)",["STANLEY","KONAMI","MOSTAZA"]], ["BRONCE","text-[#b0763a]","rgba(176,118,58,.3)",["TIENDA RIVER","QUILMES","ASSIST CARD"]]]; return <>
{tiers.map(([t,tc,bc,logos])=>(
{t}
{logos.map((l,i)=>( {l}))}
))}
; } function HistoriasModule(){ const toast=useContext(ToastCtx); const viajes=[["Boca Juniors vs River Plate","La Bombonera · 25/05",["BUS","ENTRADA"]],["River Plate vs Talleres","Más Monumental · 01/06",["BUS","COMIDA"]],["River Plate vs Independiente","Más Monumental · 08/06",["BUS"]]]; return <> ⚡ IA}/>
{viajes.map(([t,s,tags])=>(
{t}{s}
{tags.map(g=>{g})}
))}
{`VAMOS A LA BOMBONERA\nBOCA JRS VS RIVER PLATE\nVIERNES 25/05 · BUS 10:00 HS + ENTRADA\nDESDE EL OBELISCO · RESERVA AL 11 2234-5678\n¡CUPOS LIMITADOS!`}
; } function SorteosModule(){ const toast=useContext(ToastCtx); const db=useDB();const s=db.sorteo;const sold=useMemo(()=>new Set(s.sold),[s.sold]); const toggle=n=>OMDB.update(st=>{const set=new Set(st.sorteo.sold);set.has(n)?set.delete(n):set.add(n);st.sorteo.sold=[...set].sort((a,b)=>a-b);}); return <> ${s.precio} C/U}/>
Premio
{Array.from({length:s.total},(_,n)=>( ))}
■ VENDIDOS {sold.size}□ DISPONIBLES {s.total-sold.size}
; } function ReelsModule(){ const db=useDB();const toast=useContext(ToastCtx); const [txt,setTxt]=useState('');const [url,setUrl]=useState('');const [plat,setPlat]=useState('YOUTUBE'); const add=()=>{ if(!txt.trim()){toast('Poné un título');return;} if(!url.trim()){toast('Pegá el link de YouTube o TikTok');return;} OMDB.update(s=>{s.reels=[{titulo:txt.trim(),vistas:'0',plataforma:plat,url:url.trim()},...s.reels];}); setTxt('');setUrl('');toast('Video publicado en el sitio'); }; const del=i=>OMDB.update(s=>{s.reels.splice(i,1);}); return <>
setTxt(e.target.value)} placeholder="Título del video…" className="bg-white/[.06] border border-white/10 rounded-xl px-3 py-2 text-[11px] outline-none focus:border-river/60 min-w-0"/>
{['YOUTUBE','TIKTOK'].map(p=>( ))}
setUrl(e.target.value)} onKeyDown={e=>e.key==='Enter'&&add()} placeholder="Pegá el link…" className="flex-1 bg-white/[.06] border border-white/10 rounded-xl px-3 py-2 text-[10px] font-mono outline-none focus:border-river/60 min-w-0"/>
{db.reels.map((r,i)=>(
{r.titulo}{r.plataforma} · {r.url?r.url.slice(0,26)+'…':r.vistas+' vistas'}
))}
; } /* ============ MODULE REGISTRY (hiper modular) ============ */ const MODULES=[ {id:'kpi', title:'Dashboard & Métricas', icon:'dash', span:'lg:col-span-6', bare:true, C:KpiModule}, {id:'site', title:'Sitio & Hero', icon:'eye', span:'lg:col-span-3', C:SiteModule}, {id:'rev', title:'Facturación', icon:'down', span:'lg:col-span-3', C:RevenueModule}, {id:'world', title:'Visitas', icon:'eye', span:'lg:col-span-3', C:WorldModule}, {id:'refs', title:'Referidos · Socios', icon:'users', span:'lg:col-span-3', C:ReferidosModule}, {id:'figus', title:'Figuritas Builder', icon:'card', span:'lg:col-span-4', C:FiguritasModule}, {id:'squad', title:'Plantilla', icon:'squad', span:'lg:col-span-2 lg:row-span-2', C:PlantillaModule}, {id:'hist', title:'Historias · Telegram', icon:'chat', span:'lg:col-span-2', C:HistoriasModule}, {id:'sorteo',title:'Sorteos', icon:'gift', span:'lg:col-span-2', C:SorteosModule}, {id:'spons', title:'Sponsors', icon:'heart', span:'lg:col-span-2', C:SponsorsModule}, {id:'reels', title:'Reels TikTok', icon:'play', span:'lg:col-span-2', C:ReelsModule}, ]; const LS_KEY='om-panel-modules-v1'; /* ============ MODULE MANAGER SHEET ============ */ function ModuleSheet({open,onClose,enabled,setEnabled}){ if(!open)return null; return
e.stopPropagation()} className="glass-deep relative rounded-t-glass md:rounded-glass w-full md:w-[420px] p-6 safe-b" style={{animation:'sheetUp .35s cubic-bezier(.22,1,.36,1) both'}}>
MÓDULOS DEL PANEL
{MODULES.map(m=>{ const on=enabled.includes(m.id); return ;})}

TU CONFIGURACIÓN SE GUARDA AUTOMÁTICAMENTE

; } /* ============ SEARCH FULLSCREEN ============ */ function SearchOverlay({open,onClose,onGo}){ const [q,setQ]=useState(''); const inRef=useRef(); useEffect(()=>{if(open){setQ('');setTimeout(()=>inRef.current&&inRef.current.focus(),80);}},[open]); if(!open)return null; const ql=q.trim().toLowerCase(); const res=MODULES.filter(m=>!ql||m.title.toLowerCase().includes(ql)); return
setQ(e.target.value)} placeholder="Buscar módulos, secciones, herramientas…" className="flex-1 bg-transparent text-[17px] md:text-[20px] font-semibold outline-none placeholder:text-dim min-w-0"/>
{ql?`${res.length} RESULTADO(S)`:'TODOS LOS MÓDULOS'} {res.map(m=>( ))} {res.length===0&&
Sin resultados para “{q}”.
}
; } /* ============ APP ============ */ function App(){ const toast=useContext(ToastCtx); const [enabled,setEnabledRaw]=useState(()=>{const all=MODULES.map(m=>m.id);try{const v=JSON.parse(localStorage.getItem(LS_KEY));if(!Array.isArray(v))return all;return[...v.filter(id=>all.includes(id)),...all.filter(id=>!v.includes(id))];}catch(e){return all;}}); const setEnabled=v=>{setEnabledRaw(v);try{localStorage.setItem(LS_KEY,JSON.stringify(v));}catch(e){}}; const [sheet,setSheet]=useState(false); const [search,setSearch]=useState(false); const [clock,setClock]=useState(''); useEffect(()=>{const f=()=>{const d=new Date(),p=n=>String(n).padStart(2,'0');setClock(`${p(d.getDate())}/${p(d.getMonth()+1)}/${d.getFullYear()} · ${p(d.getHours())}:${p(d.getMinutes())} HS`);};f();const t=setInterval(f,30000);return()=>clearInterval(t);},[]); const mods=MODULES.filter(m=>enabled.includes(m.id)); const navGo=id=>{const el=document.getElementById('mod-'+id);if(el){const y=el.getBoundingClientRect().top+window.scrollY-84;window.scrollTo({top:y,behavior:'smooth'});}else toast('Activá ese módulo desde “Módulos”');}; return <> {/* fondo liquid */}
{/* topbar glass */}
OM
PANEL SAAS ORGULLO MILLONARIO
A
{/* grid de módulos */}
{mods.map((m,i)=>m.bare ?
:
{m.title.toUpperCase()}
)} {mods.length===0&&
No hay módulos activos. Tocá Módulos para activarlos.
}
{/* footer */}
ORGULLO MILLONARIO ® 2026PANEL SAAS v3.0 · LIQUID SERVIDORES: ONLINE ●ACTUALIZADO: {clock}
{/* tab bar móvil */} setSheet(false)} enabled={enabled} setEnabled={setEnabled}/> setSearch(false)} onGo={navGo}/> ; } ReactDOM.createRoot(document.getElementById('root')).render();