@mblinkov/whats-missing 20.0.29 → 20.0.31

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"),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=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),o=require("react"),ge=window.origin+"/cloud/speakid/games/whatsmissing/",Y=(r,m)=>r.map(([l,i])=>({src:`${ge}${m}/${i.replace(/\s/g,"%20")}.png`,name:i})),he=[["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"]],fe=[["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"]],pe=[["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"]],P={food:Y(he,"food"),animals:Y(fe,"animals"),toys:Y(pe,"toys")},ye=`
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 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=`
6
+ `;if(typeof document<"u"&&!document.getElementById("spin-keyframes")){const r=document.createElement("style");r.id="spin-keyframes",r.innerHTML=ye,document.head.appendChild(r)}const xe={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",...xe}},be=()=>{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(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=_;
9
+ `,document.head.appendChild(r)},we=(r,m)=>{const l=Array.from({length:r.length+1},()=>Array(m.length+1).fill(0));for(let i=0;i<=r.length;i++)l[i][0]=i;for(let i=0;i<=m.length;i++)l[0][i]=i;for(let i=1;i<=r.length;i++)for(let u=1;u<=m.length;u++)l[i][u]=r[i-1]===m[u-1]?l[i-1][u-1]:Math.min(l[i-1][u-1],l[i][u-1],l[i-1][u])+1;return l[r.length][m.length]};function je(r,m={minDesktopWidth:1200,forceResize:!1}){const l=o.useRef(null),i=m.minDesktopWidth??1200,u=!!m.forceResize;o.useLayoutEffect(()=>{if(typeof window>"u"||!r||!r.current)return;const d=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 p=document.createElement("div");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);const y=p.getBoundingClientRect();if(document.documentElement.removeChild(p),y&&y.width>0){const M=y.width/100;if(!isNaN(M)&&M>0)return M}}catch{}return 1},j=()=>{if(i&&window.innerWidth<i){z();return}const a=T();if(!a||a===1){z();return}l.current||(l.current={transform:d.style.transform||null,transformOrigin:d.style.transformOrigin||null,width:d.style.width||null,height:d.style.height||null,willChange:d.style.willChange||null});const g=1/a;u&&(d.style.width=`${a*100}%`,d.style.height=`${a*100}%`),d.style.transformOrigin="50% 50%",d.style.transform=`scale(${g})`,d.style.willChange="transform"},z=()=>{if(!l.current)return;const a=l.current;d.style.transform=a.transform??"",d.style.transformOrigin=a.transformOrigin??"",d.style.width=a.width??"",d.style.height=a.height??"",d.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,i,u])}function Se({gameCubeSize:r,screenHeight:m,screenWidth:l}){const i=o.useRef(null),u=o.useRef(null),[d,T]=o.useState(null);je(i,{minDesktopWidth:1024,forceResize:!1}),o.useEffect(()=>(be(),()=>{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,p]=o.useState(1),[y,M]=o.useState(null),[x,H]=o.useState("ready"),[U,V]=o.useState(3),[E,A]=o.useState(10),[W,Z]=o.useState(20),[ie,F]=o.useState(0),[B,$]=o.useState(!1),[L,_]=o.useState(""),[R,G]=o.useState(!1),[N,K]=o.useState(!1),[J,I]=o.useState(null),[re,O]=o.useState([]),[le,Q]=o.useState([]),[h,ae]=o.useState(!1);o.useEffect(()=>{if(typeof window>"u")return;const t=()=>{const s=l??window.innerWidth,c=window.matchMedia&&window.matchMedia("(pointer: coarse)").matches;ae(s<=768||c)};return t(),window.addEventListener("resize",t),window.addEventListener("orientationchange",t),()=>{window.removeEventListener("resize",t),window.removeEventListener("orientationchange",t)}},[l]),o.useLayoutEffect(()=>{const t=u.current;if(!t||typeof window>"u")return;let s=null;try{s=new ResizeObserver(c=>{for(const f of c){const k=f.contentRect;T(Math.round(Math.min(k.width,k.height)))}}),s.observe(t),T(Math.round(Math.min(t.clientWidth,t.clientHeight)))}catch{T(Math.round(Math.min(t.clientWidth,t.clientHeight)))}return()=>s?.disconnect()},[h]);const X=t=>[...t].sort(()=>Math.random()-.5).slice(0,6),ee=()=>{if(!j)return;const t=X(P[j]);S(t),C(!0),$(!1),p(1),F(0),O([]),Q([]),te(t,[],!0)},te=(t=b,s=le,c=!1)=>{const f=X(t.length?t:P[j]);let k=Math.floor(Math.random()*f.length),q=f[k].name,se=0;for(;s.includes(q)&&se<20;)k=Math.floor(Math.random()*f.length),q=f[k].name,se++;S(f),M(k),Q([...s,q]),G(!1),_(""),Z(20),I(null),c?(H("ready"),V(3),A(10)):(H("memorize"),A(10))};o.useEffect(()=>{if(!(!g||B||R)){if(x==="ready")if(U<=0)H("memorize");else{const t=setTimeout(()=>V(s=>s-1),1e3);return()=>clearTimeout(t)}if(x==="memorize")if(E<=0)H("guess");else{const t=setTimeout(()=>A(s=>s-1),1e3);return()=>clearTimeout(t)}if(x==="guess"){if(W<=0){G(!0),I("wrong");const s=b[y].name;O(c=>[...c,{round:w,answer:L,correct:s,result:"wrong"}]);return}const t=setTimeout(()=>Z(s=>s-1),1e3);return()=>clearTimeout(t)}}},[x,U,E,W,g,B,R,b,y,w,L]);const de=()=>{if(y===null||N)return;const t=b[y].name,s=L.toLowerCase().trim();let c="wrong";s===t?(F(f=>f+1),I("correct"),c="correct"):we(s,t)===1?(F(f=>f+.5),I("almost"),c="almost"):(I("wrong"),c="wrong"),O(f=>[...f,{round:w,answer:s,correct:t,result:c}]),K(!0),setTimeout(()=>{K(!1),G(!0)},600)},ce=()=>w<v?(p(t=>t+1),te()):$(!0),me=()=>{C(!1),$(!1),z(null)},ue=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"})]})}),[]),ne=1200,oe=700,D=o.useMemo(()=>{const t=l??(typeof window<"u"?window.innerWidth:ne),s=m??(typeof window<"u"?window.innerHeight:oe),c=Math.min(t/ne,s/oe);return Math.min(1.15,Math.max(.92,c))},[l,m,h]);return e.jsx("div",{ref:i,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:u,style:{width:h?"100%":`${Math.min(r??1e3,l??1e3,m??1e3)}px`,height:h?"100%":`${Math.min(r??1e3,l??1e3,m??1e3)}px`,borderRadius:h?0:"20px",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",position:"relative",overflow:"hidden",boxShadow:h?"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(${D})`,transformOrigin:"center center",transition:"transform 0.2s ease-out",width:`${100/D}%`,height:`${100/D}%`,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[!h&&ue,!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:ee,children:"▶ Start game"})]}),B&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsx("h1",{style:n.gmHeadline1,children:"Results"}),e.jsxs("h2",{style:n.gmHeadline3,children:["Your score: ",ie," / ",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:re.map((t,s)=>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"})]},s))})]}),e.jsxs("div",{style:{display:"flex",gap:12,marginTop:24},children:[e.jsx("button",{style:n.gmButton,onClick:ee,children:"🔁 Play again"}),e.jsx("button",{style:n.gmButton,onClick:me,children:"⬅️ Choose theme"})]})]}),g&&!B&&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"&&!R&&e.jsxs("p",{style:n.gmBodyM,children:["⏳ Time left: ",W,"s"]})]}),x!=="ready"&&e.jsx("div",{style:{...n.gmGrid,display:"grid",gridTemplateColumns:`repeat(${h?2:3}, 1fr)`,gridTemplateRows:`repeat(${h?3:2}, 1fr)`,gap:h?12:20,justifyContent:"center",alignContent:"center",padding:h?8:16,width:"100%",height:"100%",maxWidth:h?"100%":600,maxHeight:h?"100%":400,boxSizing:"border-box"},children:b.map((t,s)=>{const c=y===s&&x==="guess"&&!R;return e.jsx("div",{style:{...n.gmCard,width:"100%",height:"100%",...J==="correct"&&y===s?n.gmCorrect:{},...J==="wrong"&&y===s?n.gmWrong:{}},children:!c&&e.jsx("img",{src:t.src,alt:t.name,style:{width:"100%",height:"100%",objectFit:"cover",display:"block"}})},s)})}),e.jsxs("div",{style:{marginTop:16,height:80},children:[x==="guess"&&!R&&e.jsxs("div",{children:[e.jsx("input",{type:"text",placeholder:"Type the missing word",value:L,onChange:t=>_(t.target.value),style:n.gmInput}),e.jsx("button",{style:{...n.gmButton,marginLeft:8},onClick:de,disabled:N,children:N?"...":"Check"})]}),R&&e.jsx("button",{type:"button",style:n.gmButton,onClick:ce,children:"Next round"})]})]})]})})})}exports.Game=Se;exports.themes=P;
@@ -1,9 +1,9 @@
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
- name: o
6
- })), Se = [
1
+ import { jsx as n, jsxs as l, Fragment as be } from "react/jsx-runtime";
2
+ import { useRef as V, useState as a, useEffect as P, useLayoutEffect as de, useMemo as le } from "react";
3
+ const we = window.origin + "/cloud/speakid/games/whatsmissing/", U = (r, g) => r.map(([s, i]) => ({
4
+ src: `${we}${g}/${i.replace(/\s/g, "%20")}.png`,
5
+ name: i
6
+ })), xe = [
7
7
  ["apple", "apple"],
8
8
  ["banana", "banana"],
9
9
  ["bread", "bread"],
@@ -29,7 +29,7 @@ const Me = window.origin + "/cloud/speakid/games/whatsmissing/", K = (r, u) => r
29
29
  ["strawberry", "strawberry"],
30
30
  ["tomato", "tomato"],
31
31
  ["watermelon", "watermelon"]
32
- ], Te = [
32
+ ], ve = [
33
33
  ["bear", "bear"],
34
34
  ["cat", "cat"],
35
35
  ["crocodile", "crocodile"],
@@ -49,7 +49,7 @@ const Me = window.origin + "/cloud/speakid/games/whatsmissing/", K = (r, u) => r
49
49
  ["tortoise", "tortoise"],
50
50
  ["wolf", "wolf"],
51
51
  ["zebra", "zebra"]
52
- ], Re = [
52
+ ], Ce = [
53
53
  ["ball", "ball"],
54
54
  ["balloon", "balloon"],
55
55
  ["blocks", "blocks"],
@@ -69,11 +69,11 @@ const Me = window.origin + "/cloud/speakid/games/whatsmissing/", K = (r, u) => r
69
69
  ["teddy_bear", "teddy bear"],
70
70
  ["yo-yo", "yo-yo"],
71
71
  ["crayons", "crayons"]
72
- ], ce = {
73
- food: K(Se, "food"),
74
- animals: K(Te, "animals"),
75
- toys: K(Re, "toys")
76
- }, Ie = `
72
+ ], ae = {
73
+ food: U(xe, "food"),
74
+ animals: U(ve, "animals"),
75
+ toys: U(Ce, "toys")
76
+ }, ke = `
77
77
  @keyframes spin {
78
78
  from { transform: rotate(0deg); }
79
79
  to { transform: rotate(360deg); }
@@ -81,9 +81,9 @@ const Me = window.origin + "/cloud/speakid/games/whatsmissing/", K = (r, u) => r
81
81
  `;
82
82
  if (typeof document < "u" && !document.getElementById("spin-keyframes")) {
83
83
  const r = document.createElement("style");
84
- r.id = "spin-keyframes", r.innerHTML = Ie, document.head.appendChild(r);
84
+ r.id = "spin-keyframes", r.innerHTML = ke, document.head.appendChild(r);
85
85
  }
86
- const He = {
86
+ const ze = {
87
87
  animation: "spin 1.4s linear infinite"
88
88
  }, t = {
89
89
  gmCenterScreen: {
@@ -239,66 +239,66 @@ const He = {
239
239
  },
240
240
  gmHourglass: {
241
241
  fontSize: "42px",
242
- ...He
242
+ ...ze
243
243
  }
244
- }, Be = () => {
244
+ }, Se = () => {
245
245
  const r = document.createElement("style");
246
246
  r.textContent = `
247
247
  #whats-missing-root, #whats-missing-root * { box-sizing: border-box; }
248
248
  #whats-missing-root img { max-width:100%; height:auto; display:block; user-select:none; }
249
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;
253
- for (let o = 0; o <= u.length; o++) s[0][o] = o;
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];
250
+ }, Te = (r, g) => {
251
+ const s = Array.from({ length: r.length + 1 }, () => Array(g.length + 1).fill(0));
252
+ for (let i = 0; i <= r.length; i++) s[i][0] = i;
253
+ for (let i = 0; i <= g.length; i++) s[0][i] = i;
254
+ for (let i = 1; i <= r.length; i++)
255
+ for (let u = 1; u <= g.length; u++)
256
+ s[i][u] = r[i - 1] === g[u - 1] ? s[i - 1][u - 1] : Math.min(s[i - 1][u - 1], s[i][u - 1], s[i - 1][u]) + 1;
257
+ return s[r.length][g.length];
258
258
  };
259
- function Le(r, u = { minDesktopWidth: 1200, forceResize: !1 }) {
260
- const s = J(null), o = u.minDesktopWidth ?? 1200, c = !!u.forceResize;
261
- me(() => {
259
+ function Re(r, g = { minDesktopWidth: 1200, forceResize: !1 }) {
260
+ const s = V(null), i = g.minDesktopWidth ?? 1200, u = !!g.forceResize;
261
+ de(() => {
262
262
  if (typeof window > "u" || !r || !r.current) return;
263
- const m = r.current, H = () => {
263
+ const c = r.current, I = () => {
264
264
  try {
265
- const d = document.body, h = getComputedStyle(d), M = parseFloat(d.style && d.style.zoom || "");
266
- if (M && !isNaN(M) && M > 0) return M;
265
+ const d = document.body, h = getComputedStyle(d), S = parseFloat(d.style && d.style.zoom || "");
266
+ if (S && !isNaN(S) && S > 0) return S;
267
267
  const v = parseFloat(h.zoom || "");
268
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;
269
+ const y = document.createElement("div");
270
+ y.style.position = "absolute", y.style.left = "0", y.style.top = "0", y.style.width = "100px", y.style.height = "1px", y.style.visibility = "hidden", document.documentElement.appendChild(y);
271
+ const b = y.getBoundingClientRect();
272
+ if (document.documentElement.removeChild(y), b && b.width > 0) {
273
+ const H = b.width / 100;
274
+ if (!isNaN(H) && H > 0) return H;
275
275
  }
276
276
  } catch {
277
277
  }
278
278
  return 1;
279
279
  }, C = () => {
280
- if (o && window.innerWidth < o) {
281
- T();
280
+ if (i && window.innerWidth < i) {
281
+ R();
282
282
  return;
283
283
  }
284
- const d = H();
284
+ const d = I();
285
285
  if (!d || d === 1) {
286
- T();
286
+ R();
287
287
  return;
288
288
  }
289
289
  s.current || (s.current = {
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
290
+ transform: c.style.transform || null,
291
+ transformOrigin: c.style.transformOrigin || null,
292
+ width: c.style.width || null,
293
+ height: c.style.height || null,
294
+ willChange: c.style.willChange || null
295
295
  });
296
296
  const h = 1 / d;
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 = () => {
297
+ u && (c.style.width = `${d * 100}%`, c.style.height = `${d * 100}%`), c.style.transformOrigin = "50% 50%", c.style.transform = `scale(${h})`, c.style.willChange = "transform";
298
+ }, R = () => {
299
299
  if (!s.current) return;
300
300
  const d = s.current;
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;
301
+ c.style.transform = d.transform ?? "", c.style.transformOrigin = d.transformOrigin ?? "", c.style.width = d.width ?? "", c.style.height = d.height ?? "", c.style.willChange = d.willChange ?? "", s.current = null;
302
302
  };
303
303
  let x = 0;
304
304
  const k = () => {
@@ -311,95 +311,95 @@ function Le(r, u = { minDesktopWidth: 1200, forceResize: !1 }) {
311
311
  }
312
312
  });
313
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();
314
+ cancelAnimationFrame(x), z.disconnect(), window.removeEventListener("resize", k), R();
315
315
  };
316
- }, [r, o, c]);
316
+ }, [r, i, u]);
317
317
  }
318
- function Ge({
318
+ function He({
319
319
  gameCubeSize: r,
320
- screenHeight: u,
320
+ screenHeight: g,
321
321
  screenWidth: s
322
322
  }) {
323
- const o = J(null), c = J(null), [m, H] = a(null);
324
- Le(o, { minDesktopWidth: 1200, forceResize: !1 }), _(() => (Be(), () => {
323
+ const i = V(null), u = V(null), [c, I] = a(null);
324
+ Re(i, { minDesktopWidth: 1024, forceResize: !1 }), P(() => (Se(), () => {
325
325
  document.body.style.overflow = "";
326
326
  }), []);
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
- _(() => {
327
+ const [C, R] = a(null), [x, k] = a([]), [z, d] = a(4), [h, S] = a(!1), [v, y] = a(1), [b, H] = a(null), [w, L] = a("ready"), [Z, _] = a(3), [W, j] = a(10), [F, K] = a(20), [ce, $] = a(0), [A, N] = a(!1), [E, J] = a(""), [M, G] = a(!1), [D, Q] = a(!1), [X, B] = a(null), [me, O] = a([]), [ge, ee] = a([]), [f, ue] = a(!1);
328
+ P(() => {
329
329
  if (typeof window > "u") return;
330
330
  const e = () => {
331
- const i = s ?? window.innerWidth;
332
- fe(i <= 768);
331
+ const o = s ?? window.innerWidth, m = window.matchMedia && window.matchMedia("(pointer: coarse)").matches;
332
+ ue(o <= 768 || m);
333
333
  };
334
334
  return e(), window.addEventListener("resize", e), window.addEventListener("orientationchange", e), () => {
335
335
  window.removeEventListener("resize", e), window.removeEventListener("orientationchange", e);
336
336
  };
337
- }, [s]), me(() => {
338
- const e = c.current;
337
+ }, [s]), de(() => {
338
+ const e = u.current;
339
339
  if (!e || typeof window > "u") return;
340
- let i = null;
340
+ let o = null;
341
341
  try {
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)));
342
+ o = new ResizeObserver((m) => {
343
+ for (const p of m) {
344
+ const T = p.contentRect;
345
+ I(Math.round(Math.min(T.width, T.height)));
346
346
  }
347
- }), i.observe(e), H(Math.round(Math.min(e.clientWidth, e.clientHeight)));
347
+ }), o.observe(e), I(Math.round(Math.min(e.clientWidth, e.clientHeight)));
348
348
  } catch {
349
- H(Math.round(Math.min(e.clientWidth, e.clientHeight)));
349
+ I(Math.round(Math.min(e.clientWidth, e.clientHeight)));
350
350
  }
351
- return () => i?.disconnect();
352
- }, [S]);
353
- const re = (e) => [...e].sort(() => Math.random() - 0.5).slice(0, 6), se = () => {
351
+ return () => o?.disconnect();
352
+ }, [f]);
353
+ const te = (e) => [...e].sort(() => Math.random() - 0.5).slice(0, 6), ne = () => {
354
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));
355
+ const e = te(ae[C]);
356
+ k(e), S(!0), N(!1), y(1), $(0), O([]), ee([]), oe(e, [], !0);
357
+ }, oe = (e = x, o = ge, m = !1) => {
358
+ const p = te(e.length ? e : ae[C]);
359
+ let T = Math.floor(Math.random() * p.length), Y = p[T].name, se = 0;
360
+ for (; o.includes(Y) && se < 20; )
361
+ T = Math.floor(Math.random() * p.length), Y = p[T].name, se++;
362
+ k(p), H(T), ee([...o, Y]), G(!1), J(""), K(20), B(null), m ? (L("ready"), _(3), j(10)) : (L("memorize"), j(10));
363
363
  };
364
- _(() => {
365
- if (!(!h || j || R)) {
366
- if (b === "ready")
367
- if (Q <= 0) E("memorize");
364
+ P(() => {
365
+ if (!(!h || A || M)) {
366
+ if (w === "ready")
367
+ if (Z <= 0) L("memorize");
368
368
  else {
369
- const e = setTimeout(() => X((i) => i - 1), 1e3);
369
+ const e = setTimeout(() => _((o) => o - 1), 1e3);
370
370
  return () => clearTimeout(e);
371
371
  }
372
- if (b === "memorize")
373
- if (G <= 0) E("guess");
372
+ if (w === "memorize")
373
+ if (W <= 0) L("guess");
374
374
  else {
375
- const e = setTimeout(() => N((i) => i - 1), 1e3);
375
+ const e = setTimeout(() => j((o) => o - 1), 1e3);
376
376
  return () => clearTimeout(e);
377
377
  }
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" }
378
+ if (w === "guess") {
379
+ if (F <= 0) {
380
+ G(!0), B("wrong");
381
+ const o = x[b].name;
382
+ O((m) => [
383
+ ...m,
384
+ { round: v, answer: E, correct: o, result: "wrong" }
385
385
  ]);
386
386
  return;
387
387
  }
388
- const e = setTimeout(() => ee((i) => i - 1), 1e3);
388
+ const e = setTimeout(() => K((o) => o - 1), 1e3);
389
389
  return () => clearTimeout(e);
390
390
  }
391
391
  }
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);
392
+ }, [w, Z, W, F, h, A, M, x, b, v, E]);
393
+ const he = () => {
394
+ if (b === null || D) return;
395
+ const e = x[b].name, o = E.toLowerCase().trim();
396
+ let m = "wrong";
397
+ o === e ? ($((p) => p + 1), B("correct"), m = "correct") : Te(o, e) === 1 ? ($((p) => p + 0.5), B("almost"), m = "almost") : (B("wrong"), m = "wrong"), O((p) => [...p, { round: v, answer: o, correct: e, result: m }]), Q(!0), setTimeout(() => {
398
+ Q(!1), G(!0);
399
399
  }, 600);
400
- }, ye = () => v < z ? (f((e) => e + 1), le()) : q(!0), be = () => {
401
- M(!1), q(!1), T(null);
402
- }, we = ze(
400
+ }, fe = () => v < z ? (y((e) => e + 1), oe()) : N(!0), pe = () => {
401
+ S(!1), N(!1), R(null);
402
+ }, ye = le(
403
403
  () => /* @__PURE__ */ n("div", { style: { ...t.gmLogoFixed, position: "absolute", top: 16, left: 16, zIndex: 30 }, children: /* @__PURE__ */ l("picture", { children: [
404
404
  /* @__PURE__ */ n(
405
405
  "source",
@@ -419,14 +419,14 @@ function Ge({
419
419
  )
420
420
  ] }) }),
421
421
  []
422
- ), V = typeof window < "u" ? Math.min(
423
- (s ?? window.innerWidth) / 1440,
424
- (u ?? window.innerHeight) / 900
425
- ) : 1;
422
+ ), ie = 1200, re = 700, q = le(() => {
423
+ const e = s ?? (typeof window < "u" ? window.innerWidth : ie), o = g ?? (typeof window < "u" ? window.innerHeight : re), m = Math.min(e / ie, o / re);
424
+ return Math.min(1.15, Math.max(0.92, m));
425
+ }, [s, g, f]);
426
426
  return /* @__PURE__ */ n(
427
427
  "div",
428
428
  {
429
- ref: o,
429
+ ref: i,
430
430
  style: {
431
431
  position: "fixed",
432
432
  inset: 0,
@@ -440,15 +440,15 @@ function Ge({
440
440
  children: /* @__PURE__ */ n(
441
441
  "div",
442
442
  {
443
- ref: c,
443
+ ref: u,
444
444
  style: {
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",
445
+ width: f ? "100%" : `${Math.min(r ?? 1e3, s ?? 1e3, g ?? 1e3)}px`,
446
+ height: f ? "100%" : `${Math.min(r ?? 1e3, s ?? 1e3, g ?? 1e3)}px`,
447
+ borderRadius: f ? 0 : "20px",
448
448
  background: "linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",
449
449
  position: "relative",
450
450
  overflow: "hidden",
451
- boxShadow: S ? "none" : "0 0 40px rgba(0,0,0,0.08)",
451
+ boxShadow: f ? "none" : "0 0 40px rgba(0,0,0,0.08)",
452
452
  display: "flex",
453
453
  justifyContent: "center",
454
454
  alignItems: "center"
@@ -458,21 +458,22 @@ function Ge({
458
458
  {
459
459
  id: "whats-missing-root",
460
460
  style: {
461
- transform: `scale(${V})`,
461
+ transform: `scale(${q})`,
462
462
  transformOrigin: "center center",
463
- width: `${100 / V}%`,
464
- height: `${100 / V}%`,
463
+ transition: "transform 0.2s ease-out",
464
+ width: `${100 / q}%`,
465
+ height: `${100 / q}%`,
465
466
  display: "flex",
466
467
  flexDirection: "column",
467
468
  justifyContent: "center",
468
469
  alignItems: "center"
469
470
  },
470
471
  children: [
471
- !S && we,
472
+ !f && ye,
472
473
  !C && !h && /* @__PURE__ */ l("div", { style: t.gmCenterScreen, children: [
473
474
  /* @__PURE__ */ n("h1", { style: t.gmHeadline1, children: "WHAT'S MISSING?" }),
474
475
  /* @__PURE__ */ n("p", { style: t.gmBodyM, children: "Select a theme:" }),
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)) }),
476
+ /* @__PURE__ */ n("div", { style: { display: "flex", gap: 16 }, children: ["animals", "food", "toys"].map((e) => /* @__PURE__ */ n("button", { style: t.gmButton, onClick: () => R(e), children: e === "animals" ? "🐶 Animals" : e === "food" ? "🍎 Food" : "🧸 Toys" }, e)) }),
476
477
  /* @__PURE__ */ l("div", { style: { marginTop: 24 }, children: [
477
478
  /* @__PURE__ */ n("p", { style: t.gmBodyS, children: "Choose number of rounds:" }),
478
479
  /* @__PURE__ */ n("div", { style: { display: "flex", gap: 12, marginTop: 8 }, children: [3, 4, 5].map((e) => /* @__PURE__ */ n(
@@ -498,13 +499,13 @@ function Ge({
498
499
  "Rounds: ",
499
500
  z
500
501
  ] }),
501
- /* @__PURE__ */ n("button", { style: t.gmButton, onClick: se, children: "▶ Start game" })
502
+ /* @__PURE__ */ n("button", { style: t.gmButton, onClick: ne, children: "▶ Start game" })
502
503
  ] }),
503
- j && /* @__PURE__ */ l("div", { style: t.gmCenterScreen, children: [
504
+ A && /* @__PURE__ */ l("div", { style: t.gmCenterScreen, children: [
504
505
  /* @__PURE__ */ n("h1", { style: t.gmHeadline1, children: "Results" }),
505
506
  /* @__PURE__ */ l("h2", { style: t.gmHeadline3, children: [
506
507
  "Your score: ",
507
- ue,
508
+ ce,
508
509
  " / ",
509
510
  z
510
511
  ] }),
@@ -516,19 +517,19 @@ function Ge({
516
517
  /* @__PURE__ */ n("th", { children: "Correct" }),
517
518
  /* @__PURE__ */ n("th", { children: "Result" })
518
519
  ] }) }),
519
- /* @__PURE__ */ n("tbody", { children: ge.map((e, i) => /* @__PURE__ */ l("tr", { children: [
520
+ /* @__PURE__ */ n("tbody", { children: me.map((e, o) => /* @__PURE__ */ l("tr", { children: [
520
521
  /* @__PURE__ */ n("td", { style: t.gmTableCell, children: e.round }),
521
522
  /* @__PURE__ */ n("td", { style: t.gmTableCell, children: e.answer || "—" }),
522
523
  /* @__PURE__ */ n("td", { style: t.gmTableCell, children: e.correct }),
523
524
  /* @__PURE__ */ n("td", { style: t.gmTableCell, children: e.result === "correct" ? "✔ Correct" : e.result === "almost" ? "◐ Almost (0.5)" : "✘ Wrong" })
524
- ] }, i)) })
525
+ ] }, o)) })
525
526
  ] }),
526
527
  /* @__PURE__ */ l("div", { style: { display: "flex", gap: 12, marginTop: 24 }, children: [
527
- /* @__PURE__ */ n("button", { style: t.gmButton, onClick: se, children: "🔁 Play again" }),
528
- /* @__PURE__ */ n("button", { style: t.gmButton, onClick: be, children: "⬅️ Choose theme" })
528
+ /* @__PURE__ */ n("button", { style: t.gmButton, onClick: ne, children: "🔁 Play again" }),
529
+ /* @__PURE__ */ n("button", { style: t.gmButton, onClick: pe, children: "⬅️ Choose theme" })
529
530
  ] })
530
531
  ] }),
531
- h && !j && /* @__PURE__ */ l("div", { style: t.gmGameLayout, children: [
532
+ h && !A && /* @__PURE__ */ l("div", { style: t.gmGameLayout, children: [
532
533
  /* @__PURE__ */ l(
533
534
  "div",
534
535
  {
@@ -540,87 +541,81 @@ function Ge({
540
541
  alignItems: "center"
541
542
  },
542
543
  children: [
543
- b === "ready" && /* @__PURE__ */ l(ke, { children: [
544
+ w === "ready" && /* @__PURE__ */ l(be, { children: [
544
545
  /* @__PURE__ */ n("h1", { style: { ...t.gmHeadline1, color: "#ec4c44" }, children: "GET READY" }),
545
546
  /* @__PURE__ */ n("div", { style: t.gmHourglass, children: "⏳" })
546
547
  ] }),
547
- b === "memorize" && /* @__PURE__ */ l("p", { style: { ...t.gmBodyM, color: "#10b981" }, children: [
548
+ w === "memorize" && /* @__PURE__ */ l("p", { style: { ...t.gmBodyM, color: "#10b981" }, children: [
548
549
  "MEMORIZE (",
549
- G,
550
+ W,
550
551
  ")"
551
552
  ] }),
552
- b === "guess" && !R && /* @__PURE__ */ l("p", { style: t.gmBodyM, children: [
553
+ w === "guess" && !M && /* @__PURE__ */ l("p", { style: t.gmBodyM, children: [
553
554
  "⏳ Time left: ",
554
- D,
555
+ F,
555
556
  "s"
556
557
  ] })
557
558
  ]
558
559
  }
559
560
  ),
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);
568
- return /* @__PURE__ */ n(
569
- "div",
570
- {
571
- style: {
572
- ...t.gmGrid,
573
- gridTemplateColumns: `repeat(${Z}, ${W}px)`,
574
- gridAutoRows: `${W}px`,
575
- gap: `${e}px`,
576
- justifyContent: "center",
577
- justifyItems: "center",
578
- padding: 8,
579
- boxSizing: "border-box"
580
- },
581
- children: x.map((de, $) => {
582
- const Ce = y === $ && b === "guess" && !R;
583
- return /* @__PURE__ */ n(
584
- "div",
585
- {
586
- style: {
587
- ...t.gmCard,
588
- width: `${W}px`,
589
- height: `${W}px`,
590
- padding: W >= 160 ? 10 : 8,
591
- boxSizing: "border-box",
592
- ...oe === "correct" && y === $ ? t.gmCorrect : {},
593
- ...oe === "wrong" && y === $ ? t.gmWrong : {}
594
- },
595
- children: !Ce && /* @__PURE__ */ n(
596
- "img",
597
- {
598
- src: de.src,
599
- alt: de.name,
600
- style: {
601
- width: "100%",
602
- height: "100%",
603
- objectFit: "cover",
604
- display: "block"
605
- }
606
- }
607
- )
561
+ w !== "ready" && /* @__PURE__ */ n(
562
+ "div",
563
+ {
564
+ style: {
565
+ ...t.gmGrid,
566
+ display: "grid",
567
+ gridTemplateColumns: `repeat(${f ? 2 : 3}, 1fr)`,
568
+ gridTemplateRows: `repeat(${f ? 3 : 2}, 1fr)`,
569
+ gap: f ? 12 : 20,
570
+ justifyContent: "center",
571
+ alignContent: "center",
572
+ padding: f ? 8 : 16,
573
+ width: "100%",
574
+ height: "100%",
575
+ maxWidth: f ? "100%" : 600,
576
+ maxHeight: f ? "100%" : 400,
577
+ boxSizing: "border-box"
578
+ },
579
+ children: x.map((e, o) => {
580
+ const m = b === o && w === "guess" && !M;
581
+ return /* @__PURE__ */ n(
582
+ "div",
583
+ {
584
+ style: {
585
+ ...t.gmCard,
586
+ width: "100%",
587
+ height: "100%",
588
+ ...X === "correct" && b === o ? t.gmCorrect : {},
589
+ ...X === "wrong" && b === o ? t.gmWrong : {}
608
590
  },
609
- $
610
- );
611
- })
612
- }
613
- );
614
- })(),
591
+ children: !m && /* @__PURE__ */ n(
592
+ "img",
593
+ {
594
+ src: e.src,
595
+ alt: e.name,
596
+ style: {
597
+ width: "100%",
598
+ height: "100%",
599
+ objectFit: "cover",
600
+ display: "block"
601
+ }
602
+ }
603
+ )
604
+ },
605
+ o
606
+ );
607
+ })
608
+ }
609
+ ),
615
610
  /* @__PURE__ */ l("div", { style: { marginTop: 16, height: 80 }, children: [
616
- b === "guess" && !R && /* @__PURE__ */ l("div", { children: [
611
+ w === "guess" && !M && /* @__PURE__ */ l("div", { children: [
617
612
  /* @__PURE__ */ n(
618
613
  "input",
619
614
  {
620
615
  type: "text",
621
616
  placeholder: "Type the missing word",
622
- value: F,
623
- onChange: (e) => te(e.target.value),
617
+ value: E,
618
+ onChange: (e) => J(e.target.value),
624
619
  style: t.gmInput
625
620
  }
626
621
  ),
@@ -628,13 +623,13 @@ function Ge({
628
623
  "button",
629
624
  {
630
625
  style: { ...t.gmButton, marginLeft: 8 },
631
- onClick: pe,
632
- disabled: P,
633
- children: P ? "..." : "Check"
626
+ onClick: he,
627
+ disabled: D,
628
+ children: D ? "..." : "Check"
634
629
  }
635
630
  )
636
631
  ] }),
637
- R && /* @__PURE__ */ n("button", { type: "button", style: t.gmButton, onClick: ye, children: "Next round" })
632
+ M && /* @__PURE__ */ n("button", { type: "button", style: t.gmButton, onClick: fe, children: "Next round" })
638
633
  ] })
639
634
  ] })
640
635
  ]
@@ -646,6 +641,6 @@ function Ge({
646
641
  );
647
642
  }
648
643
  export {
649
- Ge as Game,
650
- ce as themes
644
+ He as Game,
645
+ ae as themes
651
646
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mblinkov/whats-missing",
3
- "version": "20.0.29",
3
+ "version": "20.0.31",
4
4
  "main": "dist/whats-missing.umd.js",
5
5
  "module": "dist/whats-missing.es.js",
6
6
  "types": "dist/index.d.ts",
package/src/Game.tsx CHANGED
@@ -157,7 +157,7 @@ export default function Game({
157
157
  const containerRef = useRef<HTMLDivElement | null>(null);
158
158
  const squareRef = useRef<HTMLDivElement | null>(null);
159
159
  const [squareSize, setSquareSize] = useState<number | null>(null);
160
- useNeutralizeBodyZoom(containerRef, { minDesktopWidth: 1200, forceResize: false });
160
+ useNeutralizeBodyZoom(containerRef, { minDesktopWidth: 1024, forceResize: false });
161
161
 
162
162
  useEffect(() => {
163
163
  globalReset();
@@ -191,7 +191,8 @@ export default function Game({
191
191
  if (typeof window === "undefined") return;
192
192
  const update = () => {
193
193
  const w = screenWidth ?? window.innerWidth;
194
- setIsMobile(w <= 768);
194
+ const hasCoarsePointer = window.matchMedia && window.matchMedia('(pointer: coarse)').matches;
195
+ setIsMobile(w <= 768 || hasCoarsePointer);
195
196
  };
196
197
  update();
197
198
  window.addEventListener("resize", update);
@@ -349,16 +350,17 @@ export default function Game({
349
350
  []
350
351
  );
351
352
 
352
- // ✅ масштаб интерфейса под реальное разрешение
353
- const baseWidth = 1440;
354
- const baseHeight = 900;
355
- const scale =
356
- typeof window !== "undefined"
357
- ? Math.min(
358
- (screenWidth ?? window.innerWidth) / baseWidth,
359
- (screenHeight ?? window.innerHeight) / baseHeight
360
- )
361
- : 1;
353
+ // ✅ масштаб интерфейса под размеры окна — с мягкими лимитами и кэшированием
354
+ // оптимизированные базовые размеры для лучшего покрытия экрана на десктопах
355
+ const baseWidth = 1200;
356
+ const baseHeight = 700;
357
+ const scale = useMemo(() => {
358
+ const effectiveWidth = screenWidth ?? (typeof window !== "undefined" ? window.innerWidth : baseWidth);
359
+ const effectiveHeight = screenHeight ?? (typeof window !== "undefined" ? window.innerHeight : baseHeight);
360
+ const rawScale = Math.min(effectiveWidth / baseWidth, effectiveHeight / baseHeight);
361
+ // мягкие границы роста/сжатия
362
+ return Math.min(1.15, Math.max(0.92, rawScale));
363
+ }, [screenWidth, screenHeight, isMobile]);
362
364
 
363
365
  return (
364
366
  <div
@@ -398,6 +400,7 @@ export default function Game({
398
400
  style={{
399
401
  transform: `scale(${scale})`,
400
402
  transformOrigin: "center center",
403
+ transition: "transform 0.2s ease-out",
401
404
  width: `${100 / scale}%`,
402
405
  height: `${100 / scale}%`,
403
406
  display: "flex",
@@ -526,83 +529,55 @@ export default function Game({
526
529
  )}
527
530
  </div>
528
531
 
529
- {/* Сетка карточек */}
530
- {phase !== "ready" && (() => {
531
- const gap = isMobile ? 12 : 20;
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
- )
550
- );
551
-
552
- const columns = possibleColumns;
553
- const computed = Math.floor((effective - innerGutters - gap * (columns - 1)) / columns);
554
- const cardSize = Math.max(minCardBase, computed);
555
-
556
- return (
557
- <div
558
- style={{
559
- ...styles.gmGrid,
560
- gridTemplateColumns: `repeat(${columns}, ${cardSize}px)`,
561
- gridAutoRows: `${cardSize}px`,
562
- gap: `${gap}px`,
563
- justifyContent: "center",
564
- justifyItems: "center",
565
- padding: 8,
566
- boxSizing: "border-box",
567
- }}
568
- >
569
- {files.map((file, i) => {
570
- const isHidden = hiddenIndex === i && phase === "guess" && !answered;
571
- return (
572
- <div
573
- key={i}
574
- style={{
575
- ...styles.gmCard,
576
- width: `${cardSize}px`,
577
- height: `${cardSize}px`,
578
- padding: cardSize >= 160 ? 10 : 8,
579
- boxSizing: "border-box",
580
- ...(result === "correct" && hiddenIndex === i
581
- ? styles.gmCorrect
582
- : {}),
583
- ...(result === "wrong" && hiddenIndex === i
584
- ? styles.gmWrong
585
- : {}),
586
- }}
587
- >
588
- {!isHidden && (
589
- <img
590
- src={file.src}
591
- alt={file.name}
592
- style={{
593
- width: "100%",
594
- height: "100%",
595
- objectFit: "cover",
596
- display: "block",
597
- }}
598
- />
599
- )}
600
- </div>
601
- );
602
- })}
603
- </div>
604
- );
605
- })()}
532
+ {/* ===== Сетка карточек (фикс 3×2 на десктопе, 2×3 на мобилках) ===== */}
533
+ {phase !== "ready" && (
534
+ <div
535
+ style={{
536
+ ...styles.gmGrid,
537
+ display: "grid",
538
+ gridTemplateColumns: `repeat(${isMobile ? 2 : 3}, 1fr)`,
539
+ gridTemplateRows: `repeat(${isMobile ? 3 : 2}, 1fr)`,
540
+ gap: isMobile ? 12 : 20,
541
+ justifyContent: "center",
542
+ alignContent: "center",
543
+ padding: isMobile ? 8 : 16,
544
+ width: "100%",
545
+ height: "100%",
546
+ maxWidth: isMobile ? "100%" : 600,
547
+ maxHeight: isMobile ? "100%" : 400,
548
+ boxSizing: "border-box",
549
+ }}
550
+ >
551
+ {files.map((file, i) => {
552
+ const isHidden = hiddenIndex === i && phase === "guess" && !answered;
553
+ return (
554
+ <div
555
+ key={i}
556
+ style={{
557
+ ...styles.gmCard,
558
+ width: "100%",
559
+ height: "100%",
560
+ ...(result === "correct" && hiddenIndex === i ? styles.gmCorrect : {}),
561
+ ...(result === "wrong" && hiddenIndex === i ? styles.gmWrong : {}),
562
+ }}
563
+ >
564
+ {!isHidden && (
565
+ <img
566
+ src={file.src}
567
+ alt={file.name}
568
+ style={{
569
+ width: "100%",
570
+ height: "100%",
571
+ objectFit: "cover",
572
+ display: "block",
573
+ }}
574
+ />
575
+ )}
576
+ </div>
577
+ );
578
+ })}
579
+ </div>
580
+ )}
606
581
 
607
582
  {/* Инпут и кнопки */}
608
583
  <div style={{ marginTop: 16, height: 80 }}>