@mblinkov/whats-missing 20.0.28 β†’ 20.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),o=require("react"),me=window.origin+"/cloud/speakid/games/whatsmissing/",P=(i,u)=>i.map(([l,s])=>({src:`${me}${u}/${s.replace(/\s/g,"%20")}.png`,name:s})),ue=[["apple","apple"],["banana","banana"],["bread","bread"],["burger","burger"],["cake","cake"],["carrot","carrot"],["cheese","cheese"],["chicken","chicken"],["chocolate","chocolate"],["corn","corn"],["donut","donut"],["fish","fish"],["fries","fries"],["grapes","grapes"],["ice_cream","ice cream"],["milk","milk"],["orange","orange"],["pear","pear"],["pizza","pizza"],["rice","rice"],["sandwich","sandwich"],["soup","soup"],["strawberry","strawberry"],["tomato","tomato"],["watermelon","watermelon"]],ge=[["bear","bear"],["cat","cat"],["crocodile","crocodile"],["dolphin","dolphin"],["elephant","elephant"],["fox","fox"],["giraffe","giraffe"],["horse","horse"],["kangaroo","kangaroo"],["lion","lion"],["monkey","monkey"],["owl","owl"],["panda","panda"],["penguin","penguin"],["squirrel","squirrel"],["tiger","tiger"],["tortoise","tortoise"],["wolf","wolf"],["zebra","zebra"]],he=[["ball","ball"],["balloon","balloon"],["blocks","blocks"],["car","car"],["doll","doll"],["drum","drum"],["guitar","guitar"],["jump_rope","jump rope"],["kite","kite"],["paints","paints"],["plane","plane"],["puzzle","puzzle"],["rocket","rocket"],["scooter","scooter"],["skateboard","skateboard"],["slide","slide"],["teddy_bear","teddy bear"],["yo-yo","yo-yo"],["crayons","crayons"]],U={food:P(ue,"food"),animals:P(ge,"animals"),toys:P(he,"toys")},fe=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),o=require("react"),be=window.origin+"/cloud/speakid/games/whatsmissing/",Z=(r,m)=>r.map(([l,s])=>({src:`${be}${m}/${s.replace(/\s/g,"%20")}.png`,name:s})),we=[["apple","apple"],["banana","banana"],["bread","bread"],["burger","burger"],["cake","cake"],["carrot","carrot"],["cheese","cheese"],["chicken","chicken"],["chocolate","chocolate"],["corn","corn"],["donut","donut"],["fish","fish"],["fries","fries"],["grapes","grapes"],["ice_cream","ice cream"],["milk","milk"],["orange","orange"],["pear","pear"],["pizza","pizza"],["rice","rice"],["sandwich","sandwich"],["soup","soup"],["strawberry","strawberry"],["tomato","tomato"],["watermelon","watermelon"]],je=[["bear","bear"],["cat","cat"],["crocodile","crocodile"],["dolphin","dolphin"],["elephant","elephant"],["fox","fox"],["giraffe","giraffe"],["horse","horse"],["kangaroo","kangaroo"],["lion","lion"],["monkey","monkey"],["owl","owl"],["panda","panda"],["penguin","penguin"],["squirrel","squirrel"],["tiger","tiger"],["tortoise","tortoise"],["wolf","wolf"],["zebra","zebra"]],Se=[["ball","ball"],["balloon","balloon"],["blocks","blocks"],["car","car"],["doll","doll"],["drum","drum"],["guitar","guitar"],["jump_rope","jump rope"],["kite","kite"],["paints","paints"],["plane","plane"],["puzzle","puzzle"],["rocket","rocket"],["scooter","scooter"],["skateboard","skateboard"],["slide","slide"],["teddy_bear","teddy bear"],["yo-yo","yo-yo"],["crayons","crayons"]],_={food:Z(we,"food"),animals:Z(je,"animals"),toys:Z(Se,"toys")},ve=`
2
2
  @keyframes spin {
3
3
  from { transform: rotate(0deg); }
4
4
  to { transform: rotate(360deg); }
5
5
  }
6
- `;if(typeof document<"u"&&!document.getElementById("spin-keyframes")){const i=document.createElement("style");i.id="spin-keyframes",i.innerHTML=fe,document.head.appendChild(i)}const pe={animation:"spin 1.4s linear infinite"},n={gmCenterScreen:{position:"relative",zIndex:1,minHeight:"100%",width:"100%",display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",textAlign:"center",color:"#1f2937",padding:"24px 16px",boxSizing:"border-box",transform:"translateY(20px)"},gmHeadline1:{fontWeight:700,fontSize:"clamp(28px, 4vw, 40px)",lineHeight:"110%"},gmHeadline3:{fontWeight:600,fontSize:"18px",lineHeight:"130%"},gmBodyM:{fontWeight:400,fontSize:"16px",lineHeight:"140%"},gmBodyS:{fontWeight:400,fontSize:"14px",lineHeight:"140%",color:"#6b7280"},gmButton:{fontFamily:'"Geist", system-ui, -apple-system, "Segoe UI", Roboto, Arial, "Noto Sans"',fontWeight:600,fontSize:"16px",padding:"10px 16px",borderRadius:"12px",border:"1px solid #e5e7eb",background:"#ec4c44",color:"#ffffff",cursor:"pointer",boxShadow:"0 6px 18px rgba(236, 76, 68, .18)",transition:"transform .06s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease"},gmButtonActive:{background:"#333",color:"#fff"},gmGameLayout:{position:"relative",width:"100%",maxWidth:"600px",minHeight:"100%",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",textAlign:"center",color:"#1f2937",padding:"16px 8px",margin:"0 auto"},gmGrid:{width:"100%",maxWidth:"calc(210px * 3 + 20px * 2)",margin:"0 auto",display:"grid",gridTemplateColumns:"repeat(3, 210px)",gridAutoRows:"210px",gap:"20px",justifyContent:"center"},gmCard:{border:"1px solid #e5e7eb",borderRadius:"16px",background:"#f9f9f9",aspectRatio:"1 / 1",display:"flex",alignItems:"center",justifyContent:"center",overflow:"hidden",transition:"transform .2s ease, box-shadow .2s ease, border-color .2s ease"},gmCorrect:{border:"2px solid #10b981",boxShadow:"0 0 18px rgba(16,185,129,.45)",background:"#ecfdf5"},gmWrong:{border:"2px solid #ec4c44",boxShadow:"0 0 18px rgba(236,76,68,.35)",background:"#fef2f2"},gmInput:{padding:"6px 10px",borderRadius:"6px",border:"1px solid #ccc",fontSize:"16px",fontFamily:'"Geist", system-ui',width:"160px"},gmTable:{marginTop:"20px",marginBottom:"32px",borderCollapse:"collapse",width:"100%",maxWidth:"520px",tableLayout:"fixed",textAlign:"center"},gmTableCell:{padding:"8px 12px",borderBottom:"1px solid #e5e7eb",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},gmLogoFixed:{position:"absolute",top:"16px",left:"24px",width:"120px",zIndex:10,pointerEvents:"none",background:"transparent",transform:"none",willChange:"auto"},gmLogoImg:{height:"clamp(28px, 5vw, 40px)",width:"auto",background:"transparent",objectFit:"contain",imageRendering:"auto",transform:"translateZ(0)",backfaceVisibility:"hidden",WebkitFontSmoothing:"antialiased"},gmHourglass:{fontSize:"42px",...pe}},ye=()=>{const i=document.createElement("style");i.textContent=`
6
+ `;if(typeof document<"u"&&!document.getElementById("spin-keyframes")){const r=document.createElement("style");r.id="spin-keyframes",r.innerHTML=ve,document.head.appendChild(r)}const Ce={animation:"spin 1.4s linear infinite"},n={gmCenterScreen:{position:"relative",zIndex:1,minHeight:"100%",width:"100%",display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",textAlign:"center",color:"#1f2937",padding:"24px 16px",boxSizing:"border-box",transform:"translateY(20px)"},gmHeadline1:{fontWeight:700,fontSize:"clamp(28px, 4vw, 40px)",lineHeight:"110%"},gmHeadline3:{fontWeight:600,fontSize:"18px",lineHeight:"130%"},gmBodyM:{fontWeight:400,fontSize:"16px",lineHeight:"140%"},gmBodyS:{fontWeight:400,fontSize:"14px",lineHeight:"140%",color:"#6b7280"},gmButton:{fontFamily:'"Geist", system-ui, -apple-system, "Segoe UI", Roboto, Arial, "Noto Sans"',fontWeight:600,fontSize:"16px",padding:"10px 16px",borderRadius:"12px",border:"1px solid #e5e7eb",background:"#ec4c44",color:"#ffffff",cursor:"pointer",boxShadow:"0 6px 18px rgba(236, 76, 68, .18)",transition:"transform .06s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease"},gmButtonActive:{background:"#333",color:"#fff"},gmGameLayout:{position:"relative",width:"100%",maxWidth:"none",minHeight:"100%",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",textAlign:"center",color:"#1f2937",padding:"16px 8px",margin:"0 auto"},gmGrid:{width:"100%",maxWidth:"none",margin:"0 auto",display:"grid",gridTemplateColumns:"repeat(3, 210px)",gridAutoRows:"210px",gap:"20px",justifyContent:"center"},gmCard:{border:"1px solid #e5e7eb",borderRadius:"16px",background:"#f9f9f9",aspectRatio:"1 / 1",display:"flex",alignItems:"center",justifyContent:"center",overflow:"hidden",transition:"transform .2s ease, box-shadow .2s ease, border-color .2s ease"},gmCorrect:{border:"2px solid #10b981",boxShadow:"0 0 18px rgba(16,185,129,.45)",background:"#ecfdf5"},gmWrong:{border:"2px solid #ec4c44",boxShadow:"0 0 18px rgba(236,76,68,.35)",background:"#fef2f2"},gmInput:{padding:"6px 10px",borderRadius:"6px",border:"1px solid #ccc",fontSize:"16px",fontFamily:'"Geist", system-ui',width:"160px"},gmTable:{marginTop:"20px",marginBottom:"32px",borderCollapse:"collapse",width:"100%",maxWidth:"520px",tableLayout:"fixed",textAlign:"center"},gmTableCell:{padding:"8px 12px",borderBottom:"1px solid #e5e7eb",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},gmLogoFixed:{position:"absolute",top:"16px",left:"24px",width:"120px",zIndex:10,pointerEvents:"none",background:"transparent",transform:"none",willChange:"auto"},gmLogoImg:{height:"clamp(28px, 5vw, 40px)",width:"auto",background:"transparent",objectFit:"contain",imageRendering:"auto",transform:"translateZ(0)",backfaceVisibility:"hidden",WebkitFontSmoothing:"antialiased"},gmHourglass:{fontSize:"42px",...Ce}},ke=()=>{const r=document.createElement("style");r.textContent=`
7
7
  #whats-missing-root, #whats-missing-root * { box-sizing: border-box; }
8
8
  #whats-missing-root img { max-width:100%; height:auto; display:block; user-select:none; }
9
- `,document.head.appendChild(i)},xe=(i,u)=>{const l=Array.from({length:i.length+1},()=>Array(u.length+1).fill(0));for(let s=0;s<=i.length;s++)l[s][0]=s;for(let s=0;s<=u.length;s++)l[0][s]=s;for(let s=1;s<=i.length;s++)for(let c=1;c<=u.length;c++)l[s][c]=i[s-1]===u[c-1]?l[s-1][c-1]:Math.min(l[s-1][c-1],l[s][c-1],l[s-1][c])+1;return l[i.length][u.length]};function be(i,u={minDesktopWidth:1200,forceResize:!1}){const l=o.useRef(null),s=u.minDesktopWidth??1200,c=!!u.forceResize;o.useLayoutEffect(()=>{if(typeof window>"u"||!i||!i.current)return;const m=i.current,I=()=>{try{const a=document.body,g=getComputedStyle(a),C=parseFloat(a.style&&a.style.zoom||"");if(C&&!isNaN(C)&&C>0)return C;const w=parseFloat(g.zoom||"");if(w&&!isNaN(w)&&w>0)return w;const h=document.createElement("div");h.style.position="absolute",h.style.left="0",h.style.top="0",h.style.width="100px",h.style.height="1px",h.style.visibility="hidden",document.documentElement.appendChild(h);const y=h.getBoundingClientRect();if(document.documentElement.removeChild(h),y&&y.width>0){const H=y.width/100;if(!isNaN(H)&&H>0)return H}}catch{}return 1},S=()=>{if(s&&window.innerWidth<s){R();return}const a=I();if(!a||a===1){R();return}l.current||(l.current={transform:m.style.transform||null,transformOrigin:m.style.transformOrigin||null,width:m.style.width||null,height:m.style.height||null,willChange:m.style.willChange||null});const g=1/a;c&&(m.style.width=`${a*100}%`,m.style.height=`${a*100}%`),m.style.transformOrigin="50% 50%",m.style.transform=`scale(${g})`,m.style.willChange="transform"},R=()=>{if(!l.current)return;const a=l.current;m.style.transform=a.transform??"",m.style.transformOrigin=a.transformOrigin??"",m.style.width=a.width??"",m.style.height=a.height??"",m.style.willChange=a.willChange??"",l.current=null};let b=0;const k=()=>{cancelAnimationFrame(b),b=requestAnimationFrame(S)},v=new MutationObserver(a=>{for(const g of a)if(g.type==="attributes"&&(g.attributeName==="style"||g.attributeName==="class")){k();break}});return v.observe(document.body,{attributes:!0,attributeFilter:["style","class"]}),window.addEventListener("resize",k),k(),()=>{cancelAnimationFrame(b),v.disconnect(),window.removeEventListener("resize",k),R()}},[i,s,c])}function we({gameCubeSize:i,screenHeight:u,screenWidth:l}){const s=o.useRef(null),c=o.useRef(null),[m,I]=o.useState(null);be(s,{minDesktopWidth:1200,forceResize:!1}),o.useEffect(()=>(ye(),()=>{document.body.style.overflow=""}),[]);const[S,R]=o.useState(null),[b,k]=o.useState([]),[v,a]=o.useState(4),[g,C]=o.useState(!1),[w,h]=o.useState(1),[y,H]=o.useState(null),[x,A]=o.useState("ready"),[V,Z]=o.useState(3),[E,F]=o.useState(10),[$,_]=o.useState(20),[se,G]=o.useState(0),[W,N]=o.useState(!1),[L,K]=o.useState(""),[T,O]=o.useState(!1),[D,J]=o.useState(!1),[Q,B]=o.useState(null),[oe,q]=o.useState([]),[ie,X]=o.useState([]),[j,je]=o.useState(!1);o.useLayoutEffect(()=>{const t=c.current;if(!t||typeof window>"u")return;let r=null;try{r=new ResizeObserver(f=>{for(const d of f){const p=d.contentRect;I(Math.round(Math.min(p.width,p.height)))}}),r.observe(t),I(Math.round(Math.min(t.clientWidth,t.clientHeight)))}catch{I(Math.round(Math.min(t.clientWidth,t.clientHeight)))}return()=>r?.disconnect()},[j]);const ee=t=>[...t].sort(()=>Math.random()-.5).slice(0,6),te=()=>{if(!S)return;const t=ee(U[S]);k(t),C(!0),N(!1),h(1),G(0),q([]),X([]),ne(t,[],!0)},ne=(t=b,r=ie,f=!1)=>{const d=ee(t.length?t:U[S]);let p=Math.floor(Math.random()*d.length),M=d[p].name,z=0;for(;r.includes(M)&&z<20;)p=Math.floor(Math.random()*d.length),M=d[p].name,z++;k(d),H(p),X([...r,M]),O(!1),K(""),_(20),B(null),f?(A("ready"),Z(3),F(10)):(A("memorize"),F(10))};o.useEffect(()=>{if(!(!g||W||T)){if(x==="ready")if(V<=0)A("memorize");else{const t=setTimeout(()=>Z(r=>r-1),1e3);return()=>clearTimeout(t)}if(x==="memorize")if(E<=0)A("guess");else{const t=setTimeout(()=>F(r=>r-1),1e3);return()=>clearTimeout(t)}if(x==="guess"){if($<=0){O(!0),B("wrong");const r=b[y].name;q(f=>[...f,{round:w,answer:L,correct:r,result:"wrong"}]);return}const t=setTimeout(()=>_(r=>r-1),1e3);return()=>clearTimeout(t)}}},[x,V,E,$,g,W,T,b,y,w,L]);const re=()=>{if(y===null||D)return;const t=b[y].name,r=L.toLowerCase().trim();let f="wrong";r===t?(G(d=>d+1),B("correct"),f="correct"):xe(r,t)===1?(G(d=>d+.5),B("almost"),f="almost"):(B("wrong"),f="wrong"),q(d=>[...d,{round:w,answer:r,correct:t,result:f}]),J(!0),setTimeout(()=>{J(!1),O(!0)},600)},le=()=>w<v?(h(t=>t+1),ne()):N(!0),ae=()=>{C(!1),N(!1),R(null)},de=o.useMemo(()=>e.jsx("div",{style:{...n.gmLogoFixed,position:"absolute",top:16,left:16,zIndex:30},children:e.jsxs("picture",{children:[e.jsx("source",{srcSet:window.origin+"/cloud/speakid/games/whatsmissing/logo.svg",type:"image/svg+xml"}),e.jsx("img",{src:window.origin+"/cloud/speakid/games/whatsmissing/logo.png",alt:"SPEAKID Logo",style:n.gmLogoImg,loading:"lazy"})]})}),[]),Y=typeof window<"u"?Math.min((l??window.innerWidth)/1440,(u??window.innerHeight)/900):1;return e.jsx("div",{ref:s,style:{position:"fixed",inset:0,display:"flex",justifyContent:"center",alignItems:"center",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",overflow:"hidden",zIndex:1},children:e.jsx("div",{ref:c,style:{width:j?"100%":`${Math.min(i??1e3,l??1e3,u??1e3)}px`,height:j?"100%":`${Math.min(i??1e3,l??1e3,u??1e3)}px`,borderRadius:j?0:"20px",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",position:"relative",overflow:"hidden",boxShadow:j?"none":"0 0 40px rgba(0,0,0,0.08)",display:"flex",justifyContent:"center",alignItems:"center"},children:e.jsxs("div",{id:"whats-missing-root",style:{transform:`scale(${Y})`,transformOrigin:"center center",width:`${100/Y}%`,height:`${100/Y}%`,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[!j&&de,!S&&!g&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsx("h1",{style:n.gmHeadline1,children:"WHAT'S MISSING?"}),e.jsx("p",{style:n.gmBodyM,children:"Select a theme:"}),e.jsx("div",{style:{display:"flex",gap:16},children:["animals","food","toys"].map(t=>e.jsx("button",{style:n.gmButton,onClick:()=>R(t),children:t==="animals"?"🐢 Animals":t==="food"?"🍎 Food":"🧸 Toys"},t))}),e.jsxs("div",{style:{marginTop:24},children:[e.jsx("p",{style:n.gmBodyS,children:"Choose number of rounds:"}),e.jsx("div",{style:{display:"flex",gap:12,marginTop:8},children:[3,4,5].map(t=>e.jsx("button",{style:{...n.gmButton,...v===t?n.gmButtonActive:{}},onClick:()=>a(t),children:t},t))})]})]}),S&&!g&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsxs("h1",{style:n.gmHeadline1,children:["Theme selected: ",S]}),e.jsxs("p",{style:n.gmBodyM,children:["Rounds: ",v]}),e.jsx("button",{style:n.gmButton,onClick:te,children:"β–Ά Start game"})]}),W&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsx("h1",{style:n.gmHeadline1,children:"Results"}),e.jsxs("h2",{style:n.gmHeadline3,children:["Your score: ",se," / ",v]}),e.jsx("p",{style:{...n.gmBodyM,color:"#10b981",marginTop:12},children:"Yahoo! You did it! 🍬✨"}),e.jsxs("table",{style:n.gmTable,children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Round"}),e.jsx("th",{children:"Your Answer"}),e.jsx("th",{children:"Correct"}),e.jsx("th",{children:"Result"})]})}),e.jsx("tbody",{children:oe.map((t,r)=>e.jsxs("tr",{children:[e.jsx("td",{style:n.gmTableCell,children:t.round}),e.jsx("td",{style:n.gmTableCell,children:t.answer||"β€”"}),e.jsx("td",{style:n.gmTableCell,children:t.correct}),e.jsx("td",{style:n.gmTableCell,children:t.result==="correct"?"βœ” Correct":t.result==="almost"?"◐ Almost (0.5)":"✘ Wrong"})]},r))})]}),e.jsxs("div",{style:{display:"flex",gap:12,marginTop:24},children:[e.jsx("button",{style:n.gmButton,onClick:te,children:"πŸ” Play again"}),e.jsx("button",{style:n.gmButton,onClick:ae,children:"⬅️ Choose theme"})]})]}),g&&!W&&e.jsxs("div",{style:n.gmGameLayout,children:[e.jsxs("div",{style:{minHeight:160,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[x==="ready"&&e.jsxs(e.Fragment,{children:[e.jsx("h1",{style:{...n.gmHeadline1,color:"#ec4c44"},children:"GET READY"}),e.jsx("div",{style:n.gmHourglass,children:"⏳"})]}),x==="memorize"&&e.jsxs("p",{style:{...n.gmBodyM,color:"#10b981"},children:["MEMORIZE (",E,")"]}),x==="guess"&&!T&&e.jsxs("p",{style:n.gmBodyM,children:["⏳ Time left: ",$,"s"]})]}),x!=="ready"&&(()=>{const t=j?12:20,r=32,f=Math.min(c.current?.clientWidth??i??1e3,c.current?.clientHeight??u??1e3,l??1e3),d=j?2:3,p=Math.max(90,Math.floor((f-r-t*(d-1))/d));return e.jsx("div",{style:{...n.gmGrid,gridTemplateColumns:`repeat(${d}, ${p}px)`,gridAutoRows:`${p}px`,gap:`${t}px`,justifyContent:"center",justifyItems:"center",padding:8,boxSizing:"border-box"},children:b.map((M,z)=>{const ce=y===z&&x==="guess"&&!T;return e.jsx("div",{style:{...n.gmCard,width:`${p}px`,height:`${p}px`,padding:j?8:10,boxSizing:"border-box",...Q==="correct"&&y===z?n.gmCorrect:{},...Q==="wrong"&&y===z?n.gmWrong:{}},children:!ce&&e.jsx("img",{src:M.src,alt:M.name,style:{width:"100%",height:"100%",objectFit:"cover",display:"block"}})},z)})})})(),e.jsxs("div",{style:{marginTop:16,height:80},children:[x==="guess"&&!T&&e.jsxs("div",{children:[e.jsx("input",{type:"text",placeholder:"Type the missing word",value:L,onChange:t=>K(t.target.value),style:n.gmInput}),e.jsx("button",{style:{...n.gmButton,marginLeft:8},onClick:re,disabled:D,children:D?"...":"Check"})]}),T&&e.jsx("button",{type:"button",style:n.gmButton,onClick:le,children:"Next round"})]})]})]})})})}exports.Game=we;exports.themes=U;
9
+ `,document.head.appendChild(r)},ze=(r,m)=>{const l=Array.from({length:r.length+1},()=>Array(m.length+1).fill(0));for(let s=0;s<=r.length;s++)l[s][0]=s;for(let s=0;s<=m.length;s++)l[0][s]=s;for(let s=1;s<=r.length;s++)for(let d=1;d<=m.length;d++)l[s][d]=r[s-1]===m[d-1]?l[s-1][d-1]:Math.min(l[s-1][d-1],l[s][d-1],l[s-1][d])+1;return l[r.length][m.length]};function Me(r,m={minDesktopWidth:1200,forceResize:!1}){const l=o.useRef(null),s=m.minDesktopWidth??1200,d=!!m.forceResize;o.useLayoutEffect(()=>{if(typeof window>"u"||!r||!r.current)return;const c=r.current,T=()=>{try{const a=document.body,g=getComputedStyle(a),C=parseFloat(a.style&&a.style.zoom||"");if(C&&!isNaN(C)&&C>0)return C;const w=parseFloat(g.zoom||"");if(w&&!isNaN(w)&&w>0)return w;const h=document.createElement("div");h.style.position="absolute",h.style.left="0",h.style.top="0",h.style.width="100px",h.style.height="1px",h.style.visibility="hidden",document.documentElement.appendChild(h);const p=h.getBoundingClientRect();if(document.documentElement.removeChild(h),p&&p.width>0){const I=p.width/100;if(!isNaN(I)&&I>0)return I}}catch{}return 1},j=()=>{if(s&&window.innerWidth<s){z();return}const a=T();if(!a||a===1){z();return}l.current||(l.current={transform:c.style.transform||null,transformOrigin:c.style.transformOrigin||null,width:c.style.width||null,height:c.style.height||null,willChange:c.style.willChange||null});const g=1/a;d&&(c.style.width=`${a*100}%`,c.style.height=`${a*100}%`),c.style.transformOrigin="50% 50%",c.style.transform=`scale(${g})`,c.style.willChange="transform"},z=()=>{if(!l.current)return;const a=l.current;c.style.transform=a.transform??"",c.style.transformOrigin=a.transformOrigin??"",c.style.width=a.width??"",c.style.height=a.height??"",c.style.willChange=a.willChange??"",l.current=null};let b=0;const S=()=>{cancelAnimationFrame(b),b=requestAnimationFrame(j)},v=new MutationObserver(a=>{for(const g of a)if(g.type==="attributes"&&(g.attributeName==="style"||g.attributeName==="class")){S();break}});return v.observe(document.body,{attributes:!0,attributeFilter:["style","class"]}),window.addEventListener("resize",S),S(),()=>{cancelAnimationFrame(b),v.disconnect(),window.removeEventListener("resize",S),z()}},[r,s,d])}function Re({gameCubeSize:r,screenHeight:m,screenWidth:l}){const s=o.useRef(null),d=o.useRef(null),[c,T]=o.useState(null);Me(s,{minDesktopWidth:1200,forceResize:!1}),o.useEffect(()=>(ke(),()=>{document.body.style.overflow=""}),[]);const[j,z]=o.useState(null),[b,S]=o.useState([]),[v,a]=o.useState(4),[g,C]=o.useState(!1),[w,h]=o.useState(1),[p,I]=o.useState(null),[y,A]=o.useState("ready"),[K,J]=o.useState(3),[$,G]=o.useState(10),[N,Q]=o.useState(20),[ae,O]=o.useState(0),[E,D]=o.useState(!1),[W,X]=o.useState(""),[M,q]=o.useState(!1),[Y,ee]=o.useState(!1),[te,H]=o.useState(null),[de,P]=o.useState([]),[ce,ne]=o.useState([]),[k,me]=o.useState(!1);o.useEffect(()=>{if(typeof window>"u")return;const t=()=>{const i=l??window.innerWidth;me(i<=768)};return t(),window.addEventListener("resize",t),window.addEventListener("orientationchange",t),()=>{window.removeEventListener("resize",t),window.removeEventListener("orientationchange",t)}},[l]),o.useLayoutEffect(()=>{const t=d.current;if(!t||typeof window>"u")return;let i=null;try{i=new ResizeObserver(f=>{for(const u of f){const x=u.contentRect;T(Math.round(Math.min(x.width,x.height)))}}),i.observe(t),T(Math.round(Math.min(t.clientWidth,t.clientHeight)))}catch{T(Math.round(Math.min(t.clientWidth,t.clientHeight)))}return()=>i?.disconnect()},[k]);const oe=t=>[...t].sort(()=>Math.random()-.5).slice(0,6),se=()=>{if(!j)return;const t=oe(_[j]);S(t),C(!0),D(!1),h(1),O(0),P([]),ne([]),ie(t,[],!0)},ie=(t=b,i=ce,f=!1)=>{const u=oe(t.length?t:_[j]);let x=Math.floor(Math.random()*u.length),R=u[x].name,B=0;for(;i.includes(R)&&B<20;)x=Math.floor(Math.random()*u.length),R=u[x].name,B++;S(u),I(x),ne([...i,R]),q(!1),X(""),Q(20),H(null),f?(A("ready"),J(3),G(10)):(A("memorize"),G(10))};o.useEffect(()=>{if(!(!g||E||M)){if(y==="ready")if(K<=0)A("memorize");else{const t=setTimeout(()=>J(i=>i-1),1e3);return()=>clearTimeout(t)}if(y==="memorize")if($<=0)A("guess");else{const t=setTimeout(()=>G(i=>i-1),1e3);return()=>clearTimeout(t)}if(y==="guess"){if(N<=0){q(!0),H("wrong");const i=b[p].name;P(f=>[...f,{round:w,answer:W,correct:i,result:"wrong"}]);return}const t=setTimeout(()=>Q(i=>i-1),1e3);return()=>clearTimeout(t)}}},[y,K,$,N,g,E,M,b,p,w,W]);const ue=()=>{if(p===null||Y)return;const t=b[p].name,i=W.toLowerCase().trim();let f="wrong";i===t?(O(u=>u+1),H("correct"),f="correct"):ze(i,t)===1?(O(u=>u+.5),H("almost"),f="almost"):(H("wrong"),f="wrong"),P(u=>[...u,{round:w,answer:i,correct:t,result:f}]),ee(!0),setTimeout(()=>{ee(!1),q(!0)},600)},ge=()=>w<v?(h(t=>t+1),ie()):D(!0),he=()=>{C(!1),D(!1),z(null)},fe=o.useMemo(()=>e.jsx("div",{style:{...n.gmLogoFixed,position:"absolute",top:16,left:16,zIndex:30},children:e.jsxs("picture",{children:[e.jsx("source",{srcSet:window.origin+"/cloud/speakid/games/whatsmissing/logo.svg",type:"image/svg+xml"}),e.jsx("img",{src:window.origin+"/cloud/speakid/games/whatsmissing/logo.png",alt:"SPEAKID Logo",style:n.gmLogoImg,loading:"lazy"})]})}),[]),U=typeof window<"u"?Math.min((l??window.innerWidth)/1440,(m??window.innerHeight)/900):1;return e.jsx("div",{ref:s,style:{position:"fixed",inset:0,display:"flex",justifyContent:"center",alignItems:"center",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",overflow:"hidden",zIndex:1},children:e.jsx("div",{ref:d,style:{width:k?"100%":`${Math.min(r??1e3,l??1e3,m??1e3)}px`,height:k?"100%":`${Math.min(r??1e3,l??1e3,m??1e3)}px`,borderRadius:k?0:"20px",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",position:"relative",overflow:"hidden",boxShadow:k?"none":"0 0 40px rgba(0,0,0,0.08)",display:"flex",justifyContent:"center",alignItems:"center"},children:e.jsxs("div",{id:"whats-missing-root",style:{transform:`scale(${U})`,transformOrigin:"center center",width:`${100/U}%`,height:`${100/U}%`,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[!k&&fe,!j&&!g&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsx("h1",{style:n.gmHeadline1,children:"WHAT'S MISSING?"}),e.jsx("p",{style:n.gmBodyM,children:"Select a theme:"}),e.jsx("div",{style:{display:"flex",gap:16},children:["animals","food","toys"].map(t=>e.jsx("button",{style:n.gmButton,onClick:()=>z(t),children:t==="animals"?"🐢 Animals":t==="food"?"🍎 Food":"🧸 Toys"},t))}),e.jsxs("div",{style:{marginTop:24},children:[e.jsx("p",{style:n.gmBodyS,children:"Choose number of rounds:"}),e.jsx("div",{style:{display:"flex",gap:12,marginTop:8},children:[3,4,5].map(t=>e.jsx("button",{style:{...n.gmButton,...v===t?n.gmButtonActive:{}},onClick:()=>a(t),children:t},t))})]})]}),j&&!g&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsxs("h1",{style:n.gmHeadline1,children:["Theme selected: ",j]}),e.jsxs("p",{style:n.gmBodyM,children:["Rounds: ",v]}),e.jsx("button",{style:n.gmButton,onClick:se,children:"β–Ά Start game"})]}),E&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsx("h1",{style:n.gmHeadline1,children:"Results"}),e.jsxs("h2",{style:n.gmHeadline3,children:["Your score: ",ae," / ",v]}),e.jsx("p",{style:{...n.gmBodyM,color:"#10b981",marginTop:12},children:"Yahoo! You did it! 🍬✨"}),e.jsxs("table",{style:n.gmTable,children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Round"}),e.jsx("th",{children:"Your Answer"}),e.jsx("th",{children:"Correct"}),e.jsx("th",{children:"Result"})]})}),e.jsx("tbody",{children:de.map((t,i)=>e.jsxs("tr",{children:[e.jsx("td",{style:n.gmTableCell,children:t.round}),e.jsx("td",{style:n.gmTableCell,children:t.answer||"β€”"}),e.jsx("td",{style:n.gmTableCell,children:t.correct}),e.jsx("td",{style:n.gmTableCell,children:t.result==="correct"?"βœ” Correct":t.result==="almost"?"◐ Almost (0.5)":"✘ Wrong"})]},i))})]}),e.jsxs("div",{style:{display:"flex",gap:12,marginTop:24},children:[e.jsx("button",{style:n.gmButton,onClick:se,children:"πŸ” Play again"}),e.jsx("button",{style:n.gmButton,onClick:he,children:"⬅️ Choose theme"})]})]}),g&&!E&&e.jsxs("div",{style:n.gmGameLayout,children:[e.jsxs("div",{style:{minHeight:160,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[y==="ready"&&e.jsxs(e.Fragment,{children:[e.jsx("h1",{style:{...n.gmHeadline1,color:"#ec4c44"},children:"GET READY"}),e.jsx("div",{style:n.gmHourglass,children:"⏳"})]}),y==="memorize"&&e.jsxs("p",{style:{...n.gmBodyM,color:"#10b981"},children:["MEMORIZE (",$,")"]}),y==="guess"&&!M&&e.jsxs("p",{style:n.gmBodyM,children:["⏳ Time left: ",N,"s"]})]}),y!=="ready"&&(()=>{const t=k?12:20,i=32,f=d.current?.clientWidth??Math.min(r??1e3,l??1e3),u=d.current?.clientHeight??Math.min(r??1e3,m??1e3),x=Math.min(f,u),R=typeof window<"u"?window.innerWidth:l??1e3,B=R<600?110:R<1024?140:180,pe=4,re=2,V=Math.max(re,Math.min(pe,Math.floor((x-i+t)/(B+t))||re)),ye=Math.floor((x-i-t*(V-1))/V),L=Math.max(B,ye);return e.jsx("div",{style:{...n.gmGrid,gridTemplateColumns:`repeat(${V}, ${L}px)`,gridAutoRows:`${L}px`,gap:`${t}px`,justifyContent:"center",justifyItems:"center",padding:8,boxSizing:"border-box"},children:b.map((le,F)=>{const xe=p===F&&y==="guess"&&!M;return e.jsx("div",{style:{...n.gmCard,width:`${L}px`,height:`${L}px`,padding:L>=160?10:8,boxSizing:"border-box",...te==="correct"&&p===F?n.gmCorrect:{},...te==="wrong"&&p===F?n.gmWrong:{}},children:!xe&&e.jsx("img",{src:le.src,alt:le.name,style:{width:"100%",height:"100%",objectFit:"cover",display:"block"}})},F)})})})(),e.jsxs("div",{style:{marginTop:16,height:80},children:[y==="guess"&&!M&&e.jsxs("div",{children:[e.jsx("input",{type:"text",placeholder:"Type the missing word",value:W,onChange:t=>X(t.target.value),style:n.gmInput}),e.jsx("button",{style:{...n.gmButton,marginLeft:8},onClick:ue,disabled:Y,children:Y?"...":"Check"})]}),M&&e.jsx("button",{type:"button",style:n.gmButton,onClick:ge,children:"Next round"})]})]})]})})})}exports.Game=Re;exports.themes=_;
@@ -1,9 +1,9 @@
1
- import { jsx as n, jsxs as l, Fragment as pe } from "react/jsx-runtime";
2
- import { useRef as V, useState as a, useEffect as ie, useLayoutEffect as se, useMemo as fe } from "react";
3
- const ye = window.origin + "/cloud/speakid/games/whatsmissing/", U = (i, u) => i.map(([s, o]) => ({
4
- src: `${ye}${u}/${o.replace(/\s/g, "%20")}.png`,
1
+ import { jsx as n, jsxs as l, Fragment as ke } from "react/jsx-runtime";
2
+ import { useRef as J, useState as a, useEffect as _, useLayoutEffect as me, useMemo as ze } from "react";
3
+ const Me = window.origin + "/cloud/speakid/games/whatsmissing/", K = (r, u) => r.map(([s, o]) => ({
4
+ src: `${Me}${u}/${o.replace(/\s/g, "%20")}.png`,
5
5
  name: o
6
- })), be = [
6
+ })), Se = [
7
7
  ["apple", "apple"],
8
8
  ["banana", "banana"],
9
9
  ["bread", "bread"],
@@ -29,7 +29,7 @@ const ye = window.origin + "/cloud/speakid/games/whatsmissing/", U = (i, u) => i
29
29
  ["strawberry", "strawberry"],
30
30
  ["tomato", "tomato"],
31
31
  ["watermelon", "watermelon"]
32
- ], xe = [
32
+ ], Te = [
33
33
  ["bear", "bear"],
34
34
  ["cat", "cat"],
35
35
  ["crocodile", "crocodile"],
@@ -49,7 +49,7 @@ const ye = window.origin + "/cloud/speakid/games/whatsmissing/", U = (i, u) => i
49
49
  ["tortoise", "tortoise"],
50
50
  ["wolf", "wolf"],
51
51
  ["zebra", "zebra"]
52
- ], we = [
52
+ ], Re = [
53
53
  ["ball", "ball"],
54
54
  ["balloon", "balloon"],
55
55
  ["blocks", "blocks"],
@@ -69,21 +69,21 @@ const ye = window.origin + "/cloud/speakid/games/whatsmissing/", U = (i, u) => i
69
69
  ["teddy_bear", "teddy bear"],
70
70
  ["yo-yo", "yo-yo"],
71
71
  ["crayons", "crayons"]
72
- ], re = {
73
- food: U(be, "food"),
74
- animals: U(xe, "animals"),
75
- toys: U(we, "toys")
76
- }, ke = `
72
+ ], ce = {
73
+ food: K(Se, "food"),
74
+ animals: K(Te, "animals"),
75
+ toys: K(Re, "toys")
76
+ }, Ie = `
77
77
  @keyframes spin {
78
78
  from { transform: rotate(0deg); }
79
79
  to { transform: rotate(360deg); }
80
80
  }
81
81
  `;
82
82
  if (typeof document < "u" && !document.getElementById("spin-keyframes")) {
83
- const i = document.createElement("style");
84
- i.id = "spin-keyframes", i.innerHTML = ke, document.head.appendChild(i);
83
+ const r = document.createElement("style");
84
+ r.id = "spin-keyframes", r.innerHTML = Ie, document.head.appendChild(r);
85
85
  }
86
- const Ce = {
86
+ const He = {
87
87
  animation: "spin 1.4s linear infinite"
88
88
  }, t = {
89
89
  gmCenterScreen: {
@@ -145,7 +145,8 @@ const Ce = {
145
145
  gmGameLayout: {
146
146
  position: "relative",
147
147
  width: "100%",
148
- maxWidth: "600px",
148
+ // allow the layout to expand within the square container for tablets/laptops
149
+ maxWidth: "none",
149
150
  // should fill the parent square, not the full viewport
150
151
  minHeight: "100%",
151
152
  display: "flex",
@@ -159,9 +160,11 @@ const Ce = {
159
160
  },
160
161
  gmGrid: {
161
162
  width: "100%",
162
- maxWidth: "calc(210px * 3 + 20px * 2)",
163
+ // let the grid use all available space; sizing is controlled in Game.tsx
164
+ maxWidth: "none",
163
165
  margin: "0 auto",
164
166
  display: "grid",
167
+ // defaults; overridden responsively in Game.tsx
165
168
  gridTemplateColumns: "repeat(3, 210px)",
166
169
  gridAutoRows: "210px",
167
170
  gap: "20px",
@@ -236,158 +239,167 @@ const Ce = {
236
239
  },
237
240
  gmHourglass: {
238
241
  fontSize: "42px",
239
- ...Ce
242
+ ...He
240
243
  }
241
- }, ve = () => {
242
- const i = document.createElement("style");
243
- i.textContent = `
244
+ }, Be = () => {
245
+ const r = document.createElement("style");
246
+ r.textContent = `
244
247
  #whats-missing-root, #whats-missing-root * { box-sizing: border-box; }
245
248
  #whats-missing-root img { max-width:100%; height:auto; display:block; user-select:none; }
246
- `, document.head.appendChild(i);
247
- }, ze = (i, u) => {
248
- const s = Array.from({ length: i.length + 1 }, () => Array(u.length + 1).fill(0));
249
- for (let o = 0; o <= i.length; o++) s[o][0] = o;
249
+ `, document.head.appendChild(r);
250
+ }, Ae = (r, u) => {
251
+ const s = Array.from({ length: r.length + 1 }, () => Array(u.length + 1).fill(0));
252
+ for (let o = 0; o <= r.length; o++) s[o][0] = o;
250
253
  for (let o = 0; o <= u.length; o++) s[0][o] = o;
251
- for (let o = 1; o <= i.length; o++)
252
- for (let m = 1; m <= u.length; m++)
253
- s[o][m] = i[o - 1] === u[m - 1] ? s[o - 1][m - 1] : Math.min(s[o - 1][m - 1], s[o][m - 1], s[o - 1][m]) + 1;
254
- return s[i.length][u.length];
254
+ for (let o = 1; o <= r.length; o++)
255
+ for (let c = 1; c <= u.length; c++)
256
+ s[o][c] = r[o - 1] === u[c - 1] ? s[o - 1][c - 1] : Math.min(s[o - 1][c - 1], s[o][c - 1], s[o - 1][c]) + 1;
257
+ return s[r.length][u.length];
255
258
  };
256
- function Se(i, u = { minDesktopWidth: 1200, forceResize: !1 }) {
257
- const s = V(null), o = u.minDesktopWidth ?? 1200, m = !!u.forceResize;
258
- se(() => {
259
- if (typeof window > "u" || !i || !i.current) return;
260
- const g = i.current, B = () => {
259
+ function Le(r, u = { minDesktopWidth: 1200, forceResize: !1 }) {
260
+ const s = J(null), o = u.minDesktopWidth ?? 1200, c = !!u.forceResize;
261
+ me(() => {
262
+ if (typeof window > "u" || !r || !r.current) return;
263
+ const m = r.current, H = () => {
261
264
  try {
262
- const d = document.body, h = getComputedStyle(d), T = parseFloat(d.style && d.style.zoom || "");
263
- if (T && !isNaN(T) && T > 0) return T;
264
- const k = parseFloat(h.zoom || "");
265
- if (k && !isNaN(k) && k > 0) return k;
266
- const p = document.createElement("div");
267
- p.style.position = "absolute", p.style.left = "0", p.style.top = "0", p.style.width = "100px", p.style.height = "1px", p.style.visibility = "hidden", document.documentElement.appendChild(p);
268
- const b = p.getBoundingClientRect();
269
- if (document.documentElement.removeChild(p), b && b.width > 0) {
270
- const A = b.width / 100;
271
- if (!isNaN(A) && A > 0) return A;
265
+ const d = document.body, h = getComputedStyle(d), M = parseFloat(d.style && d.style.zoom || "");
266
+ if (M && !isNaN(M) && M > 0) return M;
267
+ const v = parseFloat(h.zoom || "");
268
+ if (v && !isNaN(v) && v > 0) return v;
269
+ const f = document.createElement("div");
270
+ f.style.position = "absolute", f.style.left = "0", f.style.top = "0", f.style.width = "100px", f.style.height = "1px", f.style.visibility = "hidden", document.documentElement.appendChild(f);
271
+ const y = f.getBoundingClientRect();
272
+ if (document.documentElement.removeChild(f), y && y.width > 0) {
273
+ const B = y.width / 100;
274
+ if (!isNaN(B) && B > 0) return B;
272
275
  }
273
276
  } catch {
274
277
  }
275
278
  return 1;
276
- }, v = () => {
279
+ }, C = () => {
277
280
  if (o && window.innerWidth < o) {
278
- M();
281
+ T();
279
282
  return;
280
283
  }
281
- const d = B();
284
+ const d = H();
282
285
  if (!d || d === 1) {
283
- M();
286
+ T();
284
287
  return;
285
288
  }
286
289
  s.current || (s.current = {
287
- transform: g.style.transform || null,
288
- transformOrigin: g.style.transformOrigin || null,
289
- width: g.style.width || null,
290
- height: g.style.height || null,
291
- willChange: g.style.willChange || null
290
+ transform: m.style.transform || null,
291
+ transformOrigin: m.style.transformOrigin || null,
292
+ width: m.style.width || null,
293
+ height: m.style.height || null,
294
+ willChange: m.style.willChange || null
292
295
  });
293
296
  const h = 1 / d;
294
- m && (g.style.width = `${d * 100}%`, g.style.height = `${d * 100}%`), g.style.transformOrigin = "50% 50%", g.style.transform = `scale(${h})`, g.style.willChange = "transform";
295
- }, M = () => {
297
+ c && (m.style.width = `${d * 100}%`, m.style.height = `${d * 100}%`), m.style.transformOrigin = "50% 50%", m.style.transform = `scale(${h})`, m.style.willChange = "transform";
298
+ }, T = () => {
296
299
  if (!s.current) return;
297
300
  const d = s.current;
298
- g.style.transform = d.transform ?? "", g.style.transformOrigin = d.transformOrigin ?? "", g.style.width = d.width ?? "", g.style.height = d.height ?? "", g.style.willChange = d.willChange ?? "", s.current = null;
301
+ m.style.transform = d.transform ?? "", m.style.transformOrigin = d.transformOrigin ?? "", m.style.width = d.width ?? "", m.style.height = d.height ?? "", m.style.willChange = d.willChange ?? "", s.current = null;
299
302
  };
300
- let w = 0;
301
- const z = () => {
302
- cancelAnimationFrame(w), w = requestAnimationFrame(v);
303
- }, S = new MutationObserver((d) => {
303
+ let x = 0;
304
+ const k = () => {
305
+ cancelAnimationFrame(x), x = requestAnimationFrame(C);
306
+ }, z = new MutationObserver((d) => {
304
307
  for (const h of d)
305
308
  if (h.type === "attributes" && (h.attributeName === "style" || h.attributeName === "class")) {
306
- z();
309
+ k();
307
310
  break;
308
311
  }
309
312
  });
310
- return S.observe(document.body, { attributes: !0, attributeFilter: ["style", "class"] }), window.addEventListener("resize", z), z(), () => {
311
- cancelAnimationFrame(w), S.disconnect(), window.removeEventListener("resize", z), M();
313
+ return z.observe(document.body, { attributes: !0, attributeFilter: ["style", "class"] }), window.addEventListener("resize", k), k(), () => {
314
+ cancelAnimationFrame(x), z.disconnect(), window.removeEventListener("resize", k), T();
312
315
  };
313
- }, [i, o, m]);
316
+ }, [r, o, c]);
314
317
  }
315
- function Be({
316
- gameCubeSize: i,
318
+ function Ge({
319
+ gameCubeSize: r,
317
320
  screenHeight: u,
318
321
  screenWidth: s
319
322
  }) {
320
- const o = V(null), m = V(null), [g, B] = a(null);
321
- Se(o, { minDesktopWidth: 1200, forceResize: !1 }), ie(() => (ve(), () => {
323
+ const o = J(null), c = J(null), [m, H] = a(null);
324
+ Le(o, { minDesktopWidth: 1200, forceResize: !1 }), _(() => (Be(), () => {
322
325
  document.body.style.overflow = "";
323
326
  }), []);
324
- const [v, M] = a(null), [w, z] = a([]), [S, d] = a(4), [h, T] = a(!1), [k, p] = a(1), [b, A] = a(null), [x, L] = a("ready"), [Z, _] = a(3), [$, E] = a(10), [G, K] = a(20), [le, N] = a(0), [j, D] = a(!1), [F, J] = a(""), [I, O] = a(!1), [q, Q] = a(!1), [X, W] = a(null), [ae, Y] = a([]), [de, ee] = a([]), [C, Te] = a(!1);
325
- se(() => {
326
- const e = m.current;
327
+ const [C, T] = a(null), [x, k] = a([]), [z, d] = a(4), [h, M] = a(!1), [v, f] = a(1), [y, B] = a(null), [b, E] = a("ready"), [Q, X] = a(3), [G, N] = a(10), [D, ee] = a(20), [ue, O] = a(0), [j, q] = a(!1), [F, te] = a(""), [R, Y] = a(!1), [P, ne] = a(!1), [oe, A] = a(null), [ge, U] = a([]), [he, ie] = a([]), [S, fe] = a(!1);
328
+ _(() => {
329
+ if (typeof window > "u") return;
330
+ const e = () => {
331
+ const i = s ?? window.innerWidth;
332
+ fe(i <= 768);
333
+ };
334
+ return e(), window.addEventListener("resize", e), window.addEventListener("orientationchange", e), () => {
335
+ window.removeEventListener("resize", e), window.removeEventListener("orientationchange", e);
336
+ };
337
+ }, [s]), me(() => {
338
+ const e = c.current;
327
339
  if (!e || typeof window > "u") return;
328
- let r = null;
340
+ let i = null;
329
341
  try {
330
- r = new ResizeObserver((f) => {
331
- for (const c of f) {
332
- const y = c.contentRect;
333
- B(Math.round(Math.min(y.width, y.height)));
342
+ i = new ResizeObserver((p) => {
343
+ for (const g of p) {
344
+ const w = g.contentRect;
345
+ H(Math.round(Math.min(w.width, w.height)));
334
346
  }
335
- }), r.observe(e), B(Math.round(Math.min(e.clientWidth, e.clientHeight)));
347
+ }), i.observe(e), H(Math.round(Math.min(e.clientWidth, e.clientHeight)));
336
348
  } catch {
337
- B(Math.round(Math.min(e.clientWidth, e.clientHeight)));
349
+ H(Math.round(Math.min(e.clientWidth, e.clientHeight)));
338
350
  }
339
- return () => r?.disconnect();
340
- }, [C]);
341
- const te = (e) => [...e].sort(() => Math.random() - 0.5).slice(0, 6), ne = () => {
342
- if (!v) return;
343
- const e = te(re[v]);
344
- z(e), T(!0), D(!1), p(1), N(0), Y([]), ee([]), oe(e, [], !0);
345
- }, oe = (e = w, r = de, f = !1) => {
346
- const c = te(e.length ? e : re[v]);
347
- let y = Math.floor(Math.random() * c.length), H = c[y].name, R = 0;
348
- for (; r.includes(H) && R < 20; )
349
- y = Math.floor(Math.random() * c.length), H = c[y].name, R++;
350
- z(c), A(y), ee([...r, H]), O(!1), J(""), K(20), W(null), f ? (L("ready"), _(3), E(10)) : (L("memorize"), E(10));
351
+ return () => i?.disconnect();
352
+ }, [S]);
353
+ const re = (e) => [...e].sort(() => Math.random() - 0.5).slice(0, 6), se = () => {
354
+ if (!C) return;
355
+ const e = re(ce[C]);
356
+ k(e), M(!0), q(!1), f(1), O(0), U([]), ie([]), le(e, [], !0);
357
+ }, le = (e = x, i = he, p = !1) => {
358
+ const g = re(e.length ? e : ce[C]);
359
+ let w = Math.floor(Math.random() * g.length), I = g[w].name, L = 0;
360
+ for (; i.includes(I) && L < 20; )
361
+ w = Math.floor(Math.random() * g.length), I = g[w].name, L++;
362
+ k(g), B(w), ie([...i, I]), Y(!1), te(""), ee(20), A(null), p ? (E("ready"), X(3), N(10)) : (E("memorize"), N(10));
351
363
  };
352
- ie(() => {
353
- if (!(!h || j || I)) {
354
- if (x === "ready")
355
- if (Z <= 0) L("memorize");
364
+ _(() => {
365
+ if (!(!h || j || R)) {
366
+ if (b === "ready")
367
+ if (Q <= 0) E("memorize");
356
368
  else {
357
- const e = setTimeout(() => _((r) => r - 1), 1e3);
369
+ const e = setTimeout(() => X((i) => i - 1), 1e3);
358
370
  return () => clearTimeout(e);
359
371
  }
360
- if (x === "memorize")
361
- if ($ <= 0) L("guess");
372
+ if (b === "memorize")
373
+ if (G <= 0) E("guess");
362
374
  else {
363
- const e = setTimeout(() => E((r) => r - 1), 1e3);
375
+ const e = setTimeout(() => N((i) => i - 1), 1e3);
364
376
  return () => clearTimeout(e);
365
377
  }
366
- if (x === "guess") {
367
- if (G <= 0) {
368
- O(!0), W("wrong");
369
- const r = w[b].name;
370
- Y((f) => [
371
- ...f,
372
- { round: k, answer: F, correct: r, result: "wrong" }
378
+ if (b === "guess") {
379
+ if (D <= 0) {
380
+ Y(!0), A("wrong");
381
+ const i = x[y].name;
382
+ U((p) => [
383
+ ...p,
384
+ { round: v, answer: F, correct: i, result: "wrong" }
373
385
  ]);
374
386
  return;
375
387
  }
376
- const e = setTimeout(() => K((r) => r - 1), 1e3);
388
+ const e = setTimeout(() => ee((i) => i - 1), 1e3);
377
389
  return () => clearTimeout(e);
378
390
  }
379
391
  }
380
- }, [x, Z, $, G, h, j, I, w, b, k, F]);
381
- const ce = () => {
382
- if (b === null || q) return;
383
- const e = w[b].name, r = F.toLowerCase().trim();
384
- let f = "wrong";
385
- r === e ? (N((c) => c + 1), W("correct"), f = "correct") : ze(r, e) === 1 ? (N((c) => c + 0.5), W("almost"), f = "almost") : (W("wrong"), f = "wrong"), Y((c) => [...c, { round: k, answer: r, correct: e, result: f }]), Q(!0), setTimeout(() => {
386
- Q(!1), O(!0);
392
+ }, [b, Q, G, D, h, j, R, x, y, v, F]);
393
+ const pe = () => {
394
+ if (y === null || P) return;
395
+ const e = x[y].name, i = F.toLowerCase().trim();
396
+ let p = "wrong";
397
+ i === e ? (O((g) => g + 1), A("correct"), p = "correct") : Ae(i, e) === 1 ? (O((g) => g + 0.5), A("almost"), p = "almost") : (A("wrong"), p = "wrong"), U((g) => [...g, { round: v, answer: i, correct: e, result: p }]), ne(!0), setTimeout(() => {
398
+ ne(!1), Y(!0);
387
399
  }, 600);
388
- }, me = () => k < S ? (p((e) => e + 1), oe()) : D(!0), ge = () => {
389
- T(!1), D(!1), M(null);
390
- }, ue = fe(
400
+ }, ye = () => v < z ? (f((e) => e + 1), le()) : q(!0), be = () => {
401
+ M(!1), q(!1), T(null);
402
+ }, we = ze(
391
403
  () => /* @__PURE__ */ n("div", { style: { ...t.gmLogoFixed, position: "absolute", top: 16, left: 16, zIndex: 30 }, children: /* @__PURE__ */ l("picture", { children: [
392
404
  /* @__PURE__ */ n(
393
405
  "source",
@@ -407,7 +419,7 @@ function Be({
407
419
  )
408
420
  ] }) }),
409
421
  []
410
- ), P = typeof window < "u" ? Math.min(
422
+ ), V = typeof window < "u" ? Math.min(
411
423
  (s ?? window.innerWidth) / 1440,
412
424
  (u ?? window.innerHeight) / 900
413
425
  ) : 1;
@@ -428,15 +440,15 @@ function Be({
428
440
  children: /* @__PURE__ */ n(
429
441
  "div",
430
442
  {
431
- ref: m,
443
+ ref: c,
432
444
  style: {
433
- width: C ? "100%" : `${Math.min(i ?? 1e3, s ?? 1e3, u ?? 1e3)}px`,
434
- height: C ? "100%" : `${Math.min(i ?? 1e3, s ?? 1e3, u ?? 1e3)}px`,
435
- borderRadius: C ? 0 : "20px",
445
+ width: S ? "100%" : `${Math.min(r ?? 1e3, s ?? 1e3, u ?? 1e3)}px`,
446
+ height: S ? "100%" : `${Math.min(r ?? 1e3, s ?? 1e3, u ?? 1e3)}px`,
447
+ borderRadius: S ? 0 : "20px",
436
448
  background: "linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",
437
449
  position: "relative",
438
450
  overflow: "hidden",
439
- boxShadow: C ? "none" : "0 0 40px rgba(0,0,0,0.08)",
451
+ boxShadow: S ? "none" : "0 0 40px rgba(0,0,0,0.08)",
440
452
  display: "flex",
441
453
  justifyContent: "center",
442
454
  alignItems: "center"
@@ -446,21 +458,21 @@ function Be({
446
458
  {
447
459
  id: "whats-missing-root",
448
460
  style: {
449
- transform: `scale(${P})`,
461
+ transform: `scale(${V})`,
450
462
  transformOrigin: "center center",
451
- width: `${100 / P}%`,
452
- height: `${100 / P}%`,
463
+ width: `${100 / V}%`,
464
+ height: `${100 / V}%`,
453
465
  display: "flex",
454
466
  flexDirection: "column",
455
467
  justifyContent: "center",
456
468
  alignItems: "center"
457
469
  },
458
470
  children: [
459
- !C && ue,
460
- !v && !h && /* @__PURE__ */ l("div", { style: t.gmCenterScreen, children: [
471
+ !S && we,
472
+ !C && !h && /* @__PURE__ */ l("div", { style: t.gmCenterScreen, children: [
461
473
  /* @__PURE__ */ n("h1", { style: t.gmHeadline1, children: "WHAT'S MISSING?" }),
462
474
  /* @__PURE__ */ n("p", { style: t.gmBodyM, children: "Select a theme:" }),
463
- /* @__PURE__ */ n("div", { style: { display: "flex", gap: 16 }, children: ["animals", "food", "toys"].map((e) => /* @__PURE__ */ n("button", { style: t.gmButton, onClick: () => M(e), children: e === "animals" ? "🐢 Animals" : e === "food" ? "🍎 Food" : "🧸 Toys" }, e)) }),
475
+ /* @__PURE__ */ n("div", { style: { display: "flex", gap: 16 }, children: ["animals", "food", "toys"].map((e) => /* @__PURE__ */ n("button", { style: t.gmButton, onClick: () => T(e), children: e === "animals" ? "🐢 Animals" : e === "food" ? "🍎 Food" : "🧸 Toys" }, e)) }),
464
476
  /* @__PURE__ */ l("div", { style: { marginTop: 24 }, children: [
465
477
  /* @__PURE__ */ n("p", { style: t.gmBodyS, children: "Choose number of rounds:" }),
466
478
  /* @__PURE__ */ n("div", { style: { display: "flex", gap: 12, marginTop: 8 }, children: [3, 4, 5].map((e) => /* @__PURE__ */ n(
@@ -468,7 +480,7 @@ function Be({
468
480
  {
469
481
  style: {
470
482
  ...t.gmButton,
471
- ...S === e ? t.gmButtonActive : {}
483
+ ...z === e ? t.gmButtonActive : {}
472
484
  },
473
485
  onClick: () => d(e),
474
486
  children: e
@@ -477,24 +489,24 @@ function Be({
477
489
  )) })
478
490
  ] })
479
491
  ] }),
480
- v && !h && /* @__PURE__ */ l("div", { style: t.gmCenterScreen, children: [
492
+ C && !h && /* @__PURE__ */ l("div", { style: t.gmCenterScreen, children: [
481
493
  /* @__PURE__ */ l("h1", { style: t.gmHeadline1, children: [
482
494
  "Theme selected: ",
483
- v
495
+ C
484
496
  ] }),
485
497
  /* @__PURE__ */ l("p", { style: t.gmBodyM, children: [
486
498
  "Rounds: ",
487
- S
499
+ z
488
500
  ] }),
489
- /* @__PURE__ */ n("button", { style: t.gmButton, onClick: ne, children: "β–Ά Start game" })
501
+ /* @__PURE__ */ n("button", { style: t.gmButton, onClick: se, children: "β–Ά Start game" })
490
502
  ] }),
491
503
  j && /* @__PURE__ */ l("div", { style: t.gmCenterScreen, children: [
492
504
  /* @__PURE__ */ n("h1", { style: t.gmHeadline1, children: "Results" }),
493
505
  /* @__PURE__ */ l("h2", { style: t.gmHeadline3, children: [
494
506
  "Your score: ",
495
- le,
507
+ ue,
496
508
  " / ",
497
- S
509
+ z
498
510
  ] }),
499
511
  /* @__PURE__ */ n("p", { style: { ...t.gmBodyM, color: "#10b981", marginTop: 12 }, children: "Yahoo! You did it! 🍬✨" }),
500
512
  /* @__PURE__ */ l("table", { style: t.gmTable, children: [
@@ -504,16 +516,16 @@ function Be({
504
516
  /* @__PURE__ */ n("th", { children: "Correct" }),
505
517
  /* @__PURE__ */ n("th", { children: "Result" })
506
518
  ] }) }),
507
- /* @__PURE__ */ n("tbody", { children: ae.map((e, r) => /* @__PURE__ */ l("tr", { children: [
519
+ /* @__PURE__ */ n("tbody", { children: ge.map((e, i) => /* @__PURE__ */ l("tr", { children: [
508
520
  /* @__PURE__ */ n("td", { style: t.gmTableCell, children: e.round }),
509
521
  /* @__PURE__ */ n("td", { style: t.gmTableCell, children: e.answer || "β€”" }),
510
522
  /* @__PURE__ */ n("td", { style: t.gmTableCell, children: e.correct }),
511
523
  /* @__PURE__ */ n("td", { style: t.gmTableCell, children: e.result === "correct" ? "βœ” Correct" : e.result === "almost" ? "◐ Almost (0.5)" : "✘ Wrong" })
512
- ] }, r)) })
524
+ ] }, i)) })
513
525
  ] }),
514
526
  /* @__PURE__ */ l("div", { style: { display: "flex", gap: 12, marginTop: 24 }, children: [
515
- /* @__PURE__ */ n("button", { style: t.gmButton, onClick: ne, children: "πŸ” Play again" }),
516
- /* @__PURE__ */ n("button", { style: t.gmButton, onClick: ge, children: "⬅️ Choose theme" })
527
+ /* @__PURE__ */ n("button", { style: t.gmButton, onClick: se, children: "πŸ” Play again" }),
528
+ /* @__PURE__ */ n("button", { style: t.gmButton, onClick: be, children: "⬅️ Choose theme" })
517
529
  ] })
518
530
  ] }),
519
531
  h && !j && /* @__PURE__ */ l("div", { style: t.gmGameLayout, children: [
@@ -528,64 +540,63 @@ function Be({
528
540
  alignItems: "center"
529
541
  },
530
542
  children: [
531
- x === "ready" && /* @__PURE__ */ l(pe, { children: [
543
+ b === "ready" && /* @__PURE__ */ l(ke, { children: [
532
544
  /* @__PURE__ */ n("h1", { style: { ...t.gmHeadline1, color: "#ec4c44" }, children: "GET READY" }),
533
545
  /* @__PURE__ */ n("div", { style: t.gmHourglass, children: "⏳" })
534
546
  ] }),
535
- x === "memorize" && /* @__PURE__ */ l("p", { style: { ...t.gmBodyM, color: "#10b981" }, children: [
547
+ b === "memorize" && /* @__PURE__ */ l("p", { style: { ...t.gmBodyM, color: "#10b981" }, children: [
536
548
  "MEMORIZE (",
537
- $,
549
+ G,
538
550
  ")"
539
551
  ] }),
540
- x === "guess" && !I && /* @__PURE__ */ l("p", { style: t.gmBodyM, children: [
552
+ b === "guess" && !R && /* @__PURE__ */ l("p", { style: t.gmBodyM, children: [
541
553
  "⏳ Time left: ",
542
- G,
554
+ D,
543
555
  "s"
544
556
  ] })
545
557
  ]
546
558
  }
547
559
  ),
548
- x !== "ready" && (() => {
549
- const e = C ? 12 : 20, r = 32, f = Math.min(
550
- m.current?.clientWidth ?? i ?? 1e3,
551
- m.current?.clientHeight ?? u ?? 1e3,
552
- s ?? 1e3
553
- ), c = C ? 2 : 3, y = Math.max(
554
- 90,
555
- Math.floor((f - r - e * (c - 1)) / c)
556
- );
560
+ b !== "ready" && (() => {
561
+ const e = S ? 12 : 20, i = 32, p = c.current?.clientWidth ?? Math.min(r ?? 1e3, s ?? 1e3), g = c.current?.clientHeight ?? Math.min(r ?? 1e3, u ?? 1e3), w = Math.min(p, g), I = typeof window < "u" ? window.innerWidth : s ?? 1e3, L = I < 600 ? 110 : I < 1024 ? 140 : 180, xe = 4, ae = 2, Z = Math.max(
562
+ ae,
563
+ Math.min(
564
+ xe,
565
+ Math.floor((w - i + e) / (L + e)) || ae
566
+ )
567
+ ), ve = Math.floor((w - i - e * (Z - 1)) / Z), W = Math.max(L, ve);
557
568
  return /* @__PURE__ */ n(
558
569
  "div",
559
570
  {
560
571
  style: {
561
572
  ...t.gmGrid,
562
- gridTemplateColumns: `repeat(${c}, ${y}px)`,
563
- gridAutoRows: `${y}px`,
573
+ gridTemplateColumns: `repeat(${Z}, ${W}px)`,
574
+ gridAutoRows: `${W}px`,
564
575
  gap: `${e}px`,
565
576
  justifyContent: "center",
566
577
  justifyItems: "center",
567
578
  padding: 8,
568
579
  boxSizing: "border-box"
569
580
  },
570
- children: w.map((H, R) => {
571
- const he = b === R && x === "guess" && !I;
581
+ children: x.map((de, $) => {
582
+ const Ce = y === $ && b === "guess" && !R;
572
583
  return /* @__PURE__ */ n(
573
584
  "div",
574
585
  {
575
586
  style: {
576
587
  ...t.gmCard,
577
- width: `${y}px`,
578
- height: `${y}px`,
579
- padding: C ? 8 : 10,
588
+ width: `${W}px`,
589
+ height: `${W}px`,
590
+ padding: W >= 160 ? 10 : 8,
580
591
  boxSizing: "border-box",
581
- ...X === "correct" && b === R ? t.gmCorrect : {},
582
- ...X === "wrong" && b === R ? t.gmWrong : {}
592
+ ...oe === "correct" && y === $ ? t.gmCorrect : {},
593
+ ...oe === "wrong" && y === $ ? t.gmWrong : {}
583
594
  },
584
- children: !he && /* @__PURE__ */ n(
595
+ children: !Ce && /* @__PURE__ */ n(
585
596
  "img",
586
597
  {
587
- src: H.src,
588
- alt: H.name,
598
+ src: de.src,
599
+ alt: de.name,
589
600
  style: {
590
601
  width: "100%",
591
602
  height: "100%",
@@ -595,21 +606,21 @@ function Be({
595
606
  }
596
607
  )
597
608
  },
598
- R
609
+ $
599
610
  );
600
611
  })
601
612
  }
602
613
  );
603
614
  })(),
604
615
  /* @__PURE__ */ l("div", { style: { marginTop: 16, height: 80 }, children: [
605
- x === "guess" && !I && /* @__PURE__ */ l("div", { children: [
616
+ b === "guess" && !R && /* @__PURE__ */ l("div", { children: [
606
617
  /* @__PURE__ */ n(
607
618
  "input",
608
619
  {
609
620
  type: "text",
610
621
  placeholder: "Type the missing word",
611
622
  value: F,
612
- onChange: (e) => J(e.target.value),
623
+ onChange: (e) => te(e.target.value),
613
624
  style: t.gmInput
614
625
  }
615
626
  ),
@@ -617,13 +628,13 @@ function Be({
617
628
  "button",
618
629
  {
619
630
  style: { ...t.gmButton, marginLeft: 8 },
620
- onClick: ce,
621
- disabled: q,
622
- children: q ? "..." : "Check"
631
+ onClick: pe,
632
+ disabled: P,
633
+ children: P ? "..." : "Check"
623
634
  }
624
635
  )
625
636
  ] }),
626
- I && /* @__PURE__ */ n("button", { type: "button", style: t.gmButton, onClick: me, children: "Next round" })
637
+ R && /* @__PURE__ */ n("button", { type: "button", style: t.gmButton, onClick: ye, children: "Next round" })
627
638
  ] })
628
639
  ] })
629
640
  ]
@@ -635,6 +646,6 @@ function Be({
635
646
  );
636
647
  }
637
648
  export {
638
- Be as Game,
639
- re as themes
649
+ Ge as Game,
650
+ ce as themes
640
651
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mblinkov/whats-missing",
3
- "version": "20.0.28",
3
+ "version": "20.0.29",
4
4
  "main": "dist/whats-missing.umd.js",
5
5
  "module": "dist/whats-missing.es.js",
6
6
  "types": "dist/index.d.ts",
@@ -101,7 +101,8 @@ export const styles: Record<string, CSSProperties> = {
101
101
  gmGameLayout: {
102
102
  position: "relative",
103
103
  width: "100%",
104
- maxWidth: "600px",
104
+ // allow the layout to expand within the square container for tablets/laptops
105
+ maxWidth: "none",
105
106
  // should fill the parent square, not the full viewport
106
107
  minHeight: "100%",
107
108
  display: "flex",
@@ -116,9 +117,11 @@ export const styles: Record<string, CSSProperties> = {
116
117
 
117
118
  gmGrid: {
118
119
  width: "100%",
119
- maxWidth: "calc(210px * 3 + 20px * 2)",
120
+ // let the grid use all available space; sizing is controlled in Game.tsx
121
+ maxWidth: "none",
120
122
  margin: "0 auto",
121
123
  display: "grid",
124
+ // defaults; overridden responsively in Game.tsx
122
125
  gridTemplateColumns: "repeat(3, 210px)",
123
126
  gridAutoRows: "210px",
124
127
  gap: "20px",
package/src/Game.tsx CHANGED
@@ -186,6 +186,22 @@ export default function Game({
186
186
  const [usedHidden, setUsedHidden] = useState<string[]>([]);
187
187
  const [isMobile, setIsMobile] = useState(false);
188
188
 
189
+ // simple responsive flag; we still compute exact sizes from the measured square
190
+ useEffect(() => {
191
+ if (typeof window === "undefined") return;
192
+ const update = () => {
193
+ const w = screenWidth ?? window.innerWidth;
194
+ setIsMobile(w <= 768);
195
+ };
196
+ update();
197
+ window.addEventListener("resize", update);
198
+ window.addEventListener("orientationchange", update);
199
+ return () => {
200
+ window.removeEventListener("resize", update);
201
+ window.removeEventListener("orientationchange", update);
202
+ };
203
+ }, [screenWidth]);
204
+
189
205
  useLayoutEffect(() => {
190
206
  const el = squareRef.current;
191
207
  if (!el || typeof window === "undefined") return;
@@ -513,18 +529,30 @@ export default function Game({
513
529
  {/* Π‘Π΅Ρ‚ΠΊΠ° ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡Π΅ΠΊ */}
514
530
  {phase !== "ready" && (() => {
515
531
  const gap = isMobile ? 12 : 20;
516
- const innerGutters = 32;
517
- const effective = Math.min(
518
- squareRef.current?.clientWidth ?? gameCubeSize ?? 1000,
519
- squareRef.current?.clientHeight ?? screenHeight ?? 1000,
520
- screenWidth ?? 1000
521
- );
522
- const columns = isMobile ? 2 : 3;
523
- const cardSize = Math.max(
524
- 90,
525
- Math.floor((effective - innerGutters - gap * (columns - 1)) / columns)
532
+ const innerGutters = 32; // total padding inside the grid wrapper
533
+ const effW = squareRef.current?.clientWidth ?? Math.min(gameCubeSize ?? 1000, screenWidth ?? 1000);
534
+ const effH = squareRef.current?.clientHeight ?? Math.min(gameCubeSize ?? 1000, screenHeight ?? 1000);
535
+ const effective = Math.min(effW, effH);
536
+
537
+ // choose a comfortable minimum card size per breakpoint
538
+ const vw = typeof window !== "undefined" ? window.innerWidth : (screenWidth ?? 1000);
539
+ const minCardBase = vw < 600 ? 110 : vw < 1024 ? 140 : 180;
540
+
541
+ // compute columns to best fill available space without going below minCardBase
542
+ const maxColumns = 4;
543
+ const minColumns = 2;
544
+ const possibleColumns = Math.max(
545
+ minColumns,
546
+ Math.min(
547
+ maxColumns,
548
+ Math.floor((effective - innerGutters + gap) / (minCardBase + gap)) || minColumns
549
+ )
526
550
  );
527
551
 
552
+ const columns = possibleColumns;
553
+ const computed = Math.floor((effective - innerGutters - gap * (columns - 1)) / columns);
554
+ const cardSize = Math.max(minCardBase, computed);
555
+
528
556
  return (
529
557
  <div
530
558
  style={{
@@ -547,7 +575,7 @@ export default function Game({
547
575
  ...styles.gmCard,
548
576
  width: `${cardSize}px`,
549
577
  height: `${cardSize}px`,
550
- padding: isMobile ? 8 : 10,
578
+ padding: cardSize >= 160 ? 10 : 8,
551
579
  boxSizing: "border-box",
552
580
  ...(result === "correct" && hiddenIndex === i
553
581
  ? styles.gmCorrect