@mblinkov/whats-missing 20.0.3 → 20.0.5

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"),n=require("react"),se=window.origin+"/cloud/speakid/games/whatsmissing/",B=(r,c)=>r.map(([l,s])=>({src:`${se}${c}/${s.replace(/\s/g,"%20")}.png`,name:s})),ne=[["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"]],re=[["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"]],ie=[["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"]],M={food:B(ne,"food"),animals:B(re,"animals"),toys:B(ie,"toys")},le=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),n=require("react"),oe=window.origin+"/cloud/speakid/games/whatsmissing/",M=(r,c)=>r.map(([l,o])=>({src:`${oe}${c}/${o.replace(/\s/g,"%20")}.png`,name:o})),ne=[["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"]],re=[["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"]],ie=[["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"]],B={food:M(ne,"food"),animals:M(re,"animals"),toys:M(ie,"toys")},le=`
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=le,document.head.appendChild(r)}const ae={animation:"spin 1.4s linear infinite"},o={gmCenterScreen:{position:"relative",zIndex:1,minHeight:"100vh",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:"100vh",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:"sticky",top:"16px",left:"20px",zIndex:9999,background:"white",padding:"4px 8px",borderRadius:"8px"},gmLogoImg:{height:"clamp(28px, 5vw, 40px)",width:"auto"},gmHourglass:{fontSize:"42px",...ae}},de=window.origin+"/cloud/speakid/games/whatsmissing/logo.png",ce=()=>{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=le,document.head.appendChild(r)}const ae={animation:"spin 1.4s linear infinite"},s={gmCenterScreen:{position:"relative",zIndex:1,minHeight:"100vh",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:"100vh",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"},gmLogoImg:{height:"clamp(28px, 5vw, 40px)",width:"auto",background:"transparent"},gmHourglass:{fontSize:"42px",...ae}},de=window.origin+"/cloud/speakid/games/whatsmissing/logo.png",ce=()=>{const r=document.createElement("style");r.textContent=`
7
7
  html, body, #root {
8
8
  margin: 0;
9
9
  padding: 0;
@@ -33,4 +33,4 @@
33
33
  from { transform: rotate(0deg); }
34
34
  to { transform: rotate(360deg); }
35
35
  }
36
- `,document.head.appendChild(r)},me=(r,c)=>{const l=Array.from({length:r.length+1},()=>Array(c.length+1).fill(0));for(let s=0;s<=r.length;s++)l[s][0]=s;for(let s=0;s<=c.length;s++)l[0][s]=s;for(let s=1;s<=r.length;s++)for(let a=1;a<=c.length;a++)l[s][a]=r[s-1]===c[a-1]?l[s-1][a-1]:Math.min(l[s-1][a-1],l[s][a-1],l[s-1][a])+1;return l[r.length][c.length]};function ge(){n.useEffect(()=>{ce()},[]);const[r,c]=n.useState(null),[l,s]=n.useState([]),[a,$]=n.useState(4),[h,L]=n.useState(!1),[f,W]=n.useState(1),[u,K]=n.useState(null),[m,y]=n.useState("ready"),[E,G]=n.useState(3),[k,C]=n.useState(7),[T,F]=n.useState(20),[V,v]=n.useState(0),[b,R]=n.useState(!1),[w,D]=n.useState(""),[p,z]=n.useState(!1),[I,q]=n.useState(!1),[P,x]=n.useState(null),[Z,A]=n.useState([]),[J,U]=n.useState([]),[j,Q]=n.useState(!1);n.useEffect(()=>{const t=()=>Q(window.innerWidth<768);return t(),window.addEventListener("resize",t),()=>window.removeEventListener("resize",t)},[]);const Y=t=>[...t].sort(()=>Math.random()-.5).slice(0,6),N=()=>{if(!r)return;const t=Y(M[r]);s(t),L(!0),R(!1),W(1),v(0),A([]),U([]),O(t,[],!0)},O=(t=l,i=J,g=!1)=>{const d=Y(t.length?t:M[r]);let S=Math.floor(Math.random()*d.length),H=d[S].name,_=0;for(;i.includes(H)&&_<20;)S=Math.floor(Math.random()*d.length),H=d[S].name,_++;s(d),K(S),U([...i,H]),z(!1),D(""),F(20),x(null),g?(y("ready"),G(3),C(7)):(y("memorize"),C(7))};n.useEffect(()=>{if(!(!h||b||p)){if(m==="ready")if(E<=0)y("memorize");else{const t=setTimeout(()=>G(i=>i-1),1e3);return()=>clearTimeout(t)}if(m==="memorize")if(k<=0)y("guess");else{const t=setTimeout(()=>C(i=>i-1),1e3);return()=>clearTimeout(t)}if(m==="guess"){if(T<=0){z(!0),x("wrong");const i=l[u].name;A(g=>[...g,{round:f,answer:w,correct:i,result:"wrong"}]);return}const t=setTimeout(()=>F(i=>i-1),1e3);return()=>clearTimeout(t)}}},[m,E,k,T,h,b,p,l,u,f,w]);const X=()=>{if(u===null||I)return;const t=l[u].name,i=w.toLowerCase().trim();let g="wrong";i===t?(v(d=>d+1),x("correct"),g="correct"):me(i,t)===1?(v(d=>d+.5),x("almost"),g="almost"):(x("wrong"),g="wrong"),A(d=>[...d,{round:f,answer:i,correct:t,result:g}]),q(!0),setTimeout(()=>{q(!1),z(!0)},600)},ee=()=>f<a?(W(t=>t+1),O()):R(!0),te=()=>{L(!1),R(!1),c(null)},oe=()=>e.jsx("div",{style:o.gmLogoFixed,children:e.jsx("img",{src:de,alt:"SPEAKID Logo",style:o.gmLogoImg})});return e.jsxs(e.Fragment,{children:[!j&&e.jsx(oe,{}),!r&&!h&&e.jsxs("div",{style:o.gmCenterScreen,children:[e.jsx("h1",{style:o.gmHeadline1,children:"WHAT'S MISSING?"}),e.jsx("p",{style:o.gmBodyM,children:"Select a theme:"}),e.jsx("div",{style:{display:"flex",gap:16},children:["animals","food","toys"].map(t=>e.jsx("button",{style:o.gmButton,onClick:()=>c(t),children:t==="animals"?"🐶 Animals":t==="food"?"🍎 Food":"🧸 Toys"},t))}),e.jsxs("div",{style:{marginTop:24},children:[e.jsx("p",{style:o.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:{...o.gmButton,...a===t?o.gmButtonActive:{}},onClick:()=>$(t),children:t},t))})]})]}),r&&!h&&e.jsxs("div",{style:o.gmCenterScreen,children:[e.jsxs("h1",{style:o.gmHeadline1,children:["Theme selected: ",r]}),e.jsxs("p",{style:o.gmBodyM,children:["Rounds: ",a]}),e.jsx("button",{style:o.gmButton,onClick:N,children:"▶ Start game"})]}),b&&e.jsxs("div",{style:o.gmCenterScreen,children:[e.jsx("h1",{style:o.gmHeadline1,children:"Results"}),e.jsxs("h2",{style:o.gmHeadline3,children:["Your score: ",V," / ",a]}),e.jsxs("table",{style:o.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:Z.map((t,i)=>e.jsxs("tr",{children:[e.jsx("td",{style:o.gmTableCell,children:t.round}),e.jsx("td",{style:o.gmTableCell,children:t.answer||"—"}),e.jsx("td",{style:o.gmTableCell,children:t.correct}),e.jsx("td",{style:o.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:o.gmButton,onClick:N,children:"🔁 Play again"}),e.jsx("button",{style:o.gmButton,onClick:te,children:"⬅️ Choose theme"})]})]}),h&&!b&&e.jsxs("div",{style:o.gmGameLayout,children:[e.jsxs("div",{style:{minHeight:160,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[m==="ready"&&e.jsxs(e.Fragment,{children:[e.jsx("h1",{style:{...o.gmHeadline1,color:"#ec4c44"},children:"GET READY"}),e.jsx("div",{style:o.gmHourglass,children:"⏳"})]}),m==="memorize"&&e.jsxs("p",{style:{...o.gmBodyM,color:"#10b981"},children:["MEMORIZE (",k,")"]}),m==="guess"&&!p&&e.jsxs("p",{style:o.gmBodyM,children:["⏳ Time left: ",T,"s"]})]}),m!=="ready"&&e.jsx("div",{style:{...o.gmGrid,gridTemplateColumns:j?"repeat(2, 1fr)":"repeat(3, 210px)",gridAutoRows:j?"150px":"210px",gap:j?"12px":"20px",justifyItems:"center",...window.innerWidth>2e3?{gridTemplateColumns:"repeat(3, 260px)",gridAutoRows:"260px",gap:"28px"}:{},...window.innerWidth>2560?{gridTemplateColumns:"repeat(3, 300px)",gridAutoRows:"300px",gap:"32px"}:{}},children:l.map((t,i)=>{const g=u===i&&m==="guess"&&!p;return e.jsx("div",{style:{...o.gmCard,...P==="correct"&&u===i?o.gmCorrect:{},...P==="wrong"&&u===i?o.gmWrong:{}},children:!g&&e.jsx("img",{src:t.src,alt:t.name,style:{width:"100%",height:"100%",objectFit:"cover"}})},i)})}),e.jsxs("div",{style:{marginTop:16,height:80},children:[m==="guess"&&!p&&e.jsxs("div",{children:[e.jsx("input",{type:"text",placeholder:"Type the missing word",value:w,onChange:t=>D(t.target.value),style:o.gmInput}),e.jsx("button",{style:{...o.gmButton,marginLeft:8},onClick:X,disabled:I,children:I?"...":"Check"})]}),p&&e.jsx("button",{style:o.gmButton,onClick:ee,children:"Next round"})]})]})]})}exports.Game=ge;exports.themes=M;
36
+ `,document.head.appendChild(r)},me=(r,c)=>{const l=Array.from({length:r.length+1},()=>Array(c.length+1).fill(0));for(let o=0;o<=r.length;o++)l[o][0]=o;for(let o=0;o<=c.length;o++)l[0][o]=o;for(let o=1;o<=r.length;o++)for(let a=1;a<=c.length;a++)l[o][a]=r[o-1]===c[a-1]?l[o-1][a-1]:Math.min(l[o-1][a-1],l[o][a-1],l[o-1][a])+1;return l[r.length][c.length]};function ge(){n.useEffect(()=>{ce()},[]);const[r,c]=n.useState(null),[l,o]=n.useState([]),[a,$]=n.useState(4),[h,L]=n.useState(!1),[f,W]=n.useState(1),[u,K]=n.useState(null),[m,y]=n.useState("ready"),[E,G]=n.useState(3),[k,C]=n.useState(7),[T,F]=n.useState(20),[V,v]=n.useState(0),[b,z]=n.useState(!1),[w,D]=n.useState(""),[p,R]=n.useState(!1),[I,q]=n.useState(!1),[P,x]=n.useState(null),[Z,A]=n.useState([]),[J,U]=n.useState([]),[j,Q]=n.useState(!1);n.useEffect(()=>{const t=()=>Q(window.innerWidth<768);return t(),window.addEventListener("resize",t),()=>window.removeEventListener("resize",t)},[]);const Y=t=>[...t].sort(()=>Math.random()-.5).slice(0,6),N=()=>{if(!r)return;const t=Y(B[r]);o(t),L(!0),z(!1),W(1),v(0),A([]),U([]),O(t,[],!0)},O=(t=l,i=J,g=!1)=>{const d=Y(t.length?t:B[r]);let S=Math.floor(Math.random()*d.length),H=d[S].name,_=0;for(;i.includes(H)&&_<20;)S=Math.floor(Math.random()*d.length),H=d[S].name,_++;o(d),K(S),U([...i,H]),R(!1),D(""),F(20),x(null),g?(y("ready"),G(3),C(7)):(y("memorize"),C(7))};n.useEffect(()=>{if(!(!h||b||p)){if(m==="ready")if(E<=0)y("memorize");else{const t=setTimeout(()=>G(i=>i-1),1e3);return()=>clearTimeout(t)}if(m==="memorize")if(k<=0)y("guess");else{const t=setTimeout(()=>C(i=>i-1),1e3);return()=>clearTimeout(t)}if(m==="guess"){if(T<=0){R(!0),x("wrong");const i=l[u].name;A(g=>[...g,{round:f,answer:w,correct:i,result:"wrong"}]);return}const t=setTimeout(()=>F(i=>i-1),1e3);return()=>clearTimeout(t)}}},[m,E,k,T,h,b,p,l,u,f,w]);const X=()=>{if(u===null||I)return;const t=l[u].name,i=w.toLowerCase().trim();let g="wrong";i===t?(v(d=>d+1),x("correct"),g="correct"):me(i,t)===1?(v(d=>d+.5),x("almost"),g="almost"):(x("wrong"),g="wrong"),A(d=>[...d,{round:f,answer:i,correct:t,result:g}]),q(!0),setTimeout(()=>{q(!1),R(!0)},600)},ee=()=>f<a?(W(t=>t+1),O()):z(!0),te=()=>{L(!1),z(!1),c(null)},se=n.useMemo(()=>e.jsx("div",{style:s.gmLogoFixed,children:e.jsx("img",{src:de,alt:"SPEAKID Logo",style:s.gmLogoImg})}),[]);return e.jsx("div",{id:"whats-missing-root",style:{all:"initial",display:"block"},children:e.jsxs("div",{style:{all:"unset"},children:[!j&&se,!r&&!h&&e.jsxs("div",{style:s.gmCenterScreen,children:[e.jsx("h1",{style:s.gmHeadline1,children:"WHAT'S MISSING?"}),e.jsx("p",{style:s.gmBodyM,children:"Select a theme:"}),e.jsx("div",{style:{display:"flex",gap:16},children:["animals","food","toys"].map(t=>e.jsx("button",{style:s.gmButton,onClick:()=>c(t),children:t==="animals"?"🐶 Animals":t==="food"?"🍎 Food":"🧸 Toys"},t))}),e.jsxs("div",{style:{marginTop:24},children:[e.jsx("p",{style:s.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:{...s.gmButton,...a===t?s.gmButtonActive:{}},onClick:()=>$(t),children:t},t))})]})]}),r&&!h&&e.jsxs("div",{style:s.gmCenterScreen,children:[e.jsxs("h1",{style:s.gmHeadline1,children:["Theme selected: ",r]}),e.jsxs("p",{style:s.gmBodyM,children:["Rounds: ",a]}),e.jsx("button",{style:s.gmButton,onClick:N,children:"▶ Start game"})]}),b&&e.jsxs("div",{style:s.gmCenterScreen,children:[e.jsx("h1",{style:s.gmHeadline1,children:"Results"}),e.jsxs("h2",{style:s.gmHeadline3,children:["Your score: ",V," / ",a]}),e.jsxs("table",{style:s.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:Z.map((t,i)=>e.jsxs("tr",{children:[e.jsx("td",{style:s.gmTableCell,children:t.round}),e.jsx("td",{style:s.gmTableCell,children:t.answer||"—"}),e.jsx("td",{style:s.gmTableCell,children:t.correct}),e.jsx("td",{style:s.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:s.gmButton,onClick:N,children:"🔁 Play again"}),e.jsx("button",{style:s.gmButton,onClick:te,children:"⬅️ Choose theme"})]})]}),h&&!b&&e.jsxs("div",{style:s.gmGameLayout,children:[e.jsxs("div",{style:{minHeight:160,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[m==="ready"&&e.jsxs(e.Fragment,{children:[e.jsx("h1",{style:{...s.gmHeadline1,color:"#ec4c44"},children:"GET READY"}),e.jsx("div",{style:s.gmHourglass,children:"⏳"})]}),m==="memorize"&&e.jsxs("p",{style:{...s.gmBodyM,color:"#10b981"},children:["MEMORIZE (",k,")"]}),m==="guess"&&!p&&e.jsxs("p",{style:s.gmBodyM,children:["⏳ Time left: ",T,"s"]})]}),m!=="ready"&&e.jsx("div",{style:{...s.gmGrid,gridTemplateColumns:j?"repeat(2, 1fr)":"repeat(3, 210px)",gridAutoRows:j?"150px":"210px",gap:j?"12px":"20px",justifyItems:"center",...window.innerWidth>2e3?{gridTemplateColumns:"repeat(3, 260px)",gridAutoRows:"260px",gap:"28px"}:{},...window.innerWidth>2560?{gridTemplateColumns:"repeat(3, 300px)",gridAutoRows:"300px",gap:"32px"}:{}},children:l.map((t,i)=>{const g=u===i&&m==="guess"&&!p;return e.jsx("div",{style:{...s.gmCard,...P==="correct"&&u===i?s.gmCorrect:{},...P==="wrong"&&u===i?s.gmWrong:{}},children:!g&&e.jsx("img",{src:t.src,alt:t.name,style:{width:"100%",height:"100%",objectFit:"cover"}})},i)})}),e.jsxs("div",{style:{marginTop:16,height:80},children:[m==="guess"&&!p&&e.jsxs("div",{children:[e.jsx("input",{type:"text",placeholder:"Type the missing word",value:w,onChange:t=>D(t.target.value),style:s.gmInput}),e.jsx("button",{style:{...s.gmButton,marginLeft:8},onClick:X,disabled:I,children:I?"...":"Check"})]}),p&&e.jsx("button",{style:s.gmButton,onClick:ee,children:"Next round"})]})]})]})})}exports.Game=ge;exports.themes=B;
@@ -1,9 +1,9 @@
1
- import { jsxs as s, Fragment as O, jsx as o } from "react/jsx-runtime";
2
- import { useEffect as M, useState as l } from "react";
3
- const ie = window.origin + "/cloud/speakid/games/whatsmissing/", W = (r, m) => r.map(([a, n]) => ({
4
- src: `${ie}${m}/${n.replace(/\s/g, "%20")}.png`,
1
+ import { jsx as o, jsxs as s, Fragment as ie } from "react/jsx-runtime";
2
+ import { useEffect as L, useState as l, useMemo as se } from "react";
3
+ const le = window.origin + "/cloud/speakid/games/whatsmissing/", W = (r, m) => r.map(([a, n]) => ({
4
+ src: `${le}${m}/${n.replace(/\s/g, "%20")}.png`,
5
5
  name: n
6
- })), se = [
6
+ })), ae = [
7
7
  ["apple", "apple"],
8
8
  ["banana", "banana"],
9
9
  ["bread", "bread"],
@@ -29,7 +29,7 @@ const ie = window.origin + "/cloud/speakid/games/whatsmissing/", W = (r, m) => r
29
29
  ["strawberry", "strawberry"],
30
30
  ["tomato", "tomato"],
31
31
  ["watermelon", "watermelon"]
32
- ], le = [
32
+ ], de = [
33
33
  ["bear", "bear"],
34
34
  ["cat", "cat"],
35
35
  ["crocodile", "crocodile"],
@@ -49,7 +49,7 @@ const ie = window.origin + "/cloud/speakid/games/whatsmissing/", W = (r, m) => r
49
49
  ["tortoise", "tortoise"],
50
50
  ["wolf", "wolf"],
51
51
  ["zebra", "zebra"]
52
- ], ae = [
52
+ ], ce = [
53
53
  ["ball", "ball"],
54
54
  ["balloon", "balloon"],
55
55
  ["blocks", "blocks"],
@@ -69,11 +69,11 @@ const ie = window.origin + "/cloud/speakid/games/whatsmissing/", W = (r, m) => r
69
69
  ["teddy_bear", "teddy bear"],
70
70
  ["yo-yo", "yo-yo"],
71
71
  ["crayons", "crayons"]
72
- ], V = {
73
- food: W(se, "food"),
74
- animals: W(le, "animals"),
75
- toys: W(ae, "toys")
76
- }, de = `
72
+ ], O = {
73
+ food: W(ae, "food"),
74
+ animals: W(de, "animals"),
75
+ toys: W(ce, "toys")
76
+ }, me = `
77
77
  @keyframes spin {
78
78
  from { transform: rotate(0deg); }
79
79
  to { transform: rotate(360deg); }
@@ -81,9 +81,9 @@ const ie = window.origin + "/cloud/speakid/games/whatsmissing/", W = (r, m) => 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 = de, document.head.appendChild(r);
84
+ r.id = "spin-keyframes", r.innerHTML = me, document.head.appendChild(r);
85
85
  }
86
- const ce = {
86
+ const ge = {
87
87
  animation: "spin 1.4s linear infinite"
88
88
  }, t = {
89
89
  gmCenterScreen: {
@@ -144,7 +144,6 @@ const ce = {
144
144
  position: "relative",
145
145
  width: "100%",
146
146
  maxWidth: "600px",
147
- // ограничение ширины для мобильных
148
147
  minHeight: "100vh",
149
148
  display: "flex",
150
149
  flexDirection: "column",
@@ -210,24 +209,26 @@ const ce = {
210
209
  overflow: "hidden",
211
210
  textOverflow: "ellipsis"
212
211
  },
212
+ // ✅ Исправленный логотип: без белого фона, не ломает верстку
213
213
  gmLogoFixed: {
214
- position: "sticky",
214
+ position: "absolute",
215
215
  top: "16px",
216
- left: "20px",
217
- zIndex: 9999,
218
- background: "white",
219
- padding: "4px 8px",
220
- borderRadius: "8px"
216
+ left: "24px",
217
+ width: "120px",
218
+ zIndex: 10,
219
+ pointerEvents: "none",
220
+ background: "transparent"
221
221
  },
222
222
  gmLogoImg: {
223
223
  height: "clamp(28px, 5vw, 40px)",
224
- width: "auto"
224
+ width: "auto",
225
+ background: "transparent"
225
226
  },
226
227
  gmHourglass: {
227
228
  fontSize: "42px",
228
- ...ce
229
+ ...ge
229
230
  }
230
- }, me = window.origin + "/cloud/speakid/games/whatsmissing/logo.png", ge = () => {
231
+ }, pe = window.origin + "/cloud/speakid/games/whatsmissing/logo.png", ue = () => {
231
232
  const r = document.createElement("style");
232
233
  r.textContent = `
233
234
  html, body, #root {
@@ -260,7 +261,7 @@ const ce = {
260
261
  to { transform: rotate(360deg); }
261
262
  }
262
263
  `, document.head.appendChild(r);
263
- }, pe = (r, m) => {
264
+ }, he = (r, m) => {
264
265
  const a = Array.from({ length: r.length + 1 }, () => Array(m.length + 1).fill(0));
265
266
  for (let n = 0; n <= r.length; n++) a[n][0] = n;
266
267
  for (let n = 0; n <= m.length; n++) a[0][n] = n;
@@ -269,30 +270,30 @@ const ce = {
269
270
  a[n][d] = r[n - 1] === m[d - 1] ? a[n - 1][d - 1] : Math.min(a[n - 1][d - 1], a[n][d - 1], a[n - 1][d]) + 1;
270
271
  return a[r.length][m.length];
271
272
  };
272
- function ye() {
273
- M(() => {
274
- ge();
273
+ function xe() {
274
+ L(() => {
275
+ ue();
275
276
  }, []);
276
- const [r, m] = l(null), [a, n] = l([]), [d, Z] = l(4), [f, j] = l(!1), [x, G] = l(1), [u, J] = l(null), [g, b] = l("ready"), [E, F] = l(3), [v, S] = l(7), [z, D] = l(20), [Q, R] = l(0), [w, I] = l(!1), [k, U] = l(""), [h, A] = l(!1), [H, Y] = l(!1), [N, y] = l(null), [X, B] = l([]), [ee, P] = l([]), [C, te] = l(!1);
277
- M(() => {
278
- const e = () => te(window.innerWidth < 768);
277
+ const [r, m] = l(null), [a, n] = l([]), [d, V] = l(4), [f, j] = l(!1), [x, E] = l(1), [u, Z] = l(null), [g, b] = l("ready"), [G, F] = l(3), [v, S] = l(7), [z, D] = l(20), [J, R] = l(0), [w, I] = l(!1), [k, U] = l(""), [h, A] = l(!1), [H, Y] = l(!1), [N, y] = l(null), [Q, M] = l([]), [X, P] = l([]), [C, ee] = l(!1);
278
+ L(() => {
279
+ const e = () => ee(window.innerWidth < 768);
279
280
  return e(), window.addEventListener("resize", e), () => window.removeEventListener("resize", e);
280
281
  }, []);
281
282
  const _ = (e) => [...e].sort(() => Math.random() - 0.5).slice(0, 6), $ = () => {
282
283
  if (!r) return;
283
- const e = _(V[r]);
284
- n(e), j(!0), I(!1), G(1), R(0), B([]), P([]), q(e, [], !0);
285
- }, q = (e = a, i = ee, p = !1) => {
286
- const c = _(e.length ? e : V[r]);
287
- let T = Math.floor(Math.random() * c.length), L = c[T].name, K = 0;
288
- for (; i.includes(L) && K < 20; )
289
- T = Math.floor(Math.random() * c.length), L = c[T].name, K++;
290
- n(c), J(T), P([...i, L]), A(!1), U(""), D(20), y(null), p ? (b("ready"), F(3), S(7)) : (b("memorize"), S(7));
284
+ const e = _(O[r]);
285
+ n(e), j(!0), I(!1), E(1), R(0), M([]), P([]), q(e, [], !0);
286
+ }, q = (e = a, i = X, p = !1) => {
287
+ const c = _(e.length ? e : O[r]);
288
+ let T = Math.floor(Math.random() * c.length), B = c[T].name, K = 0;
289
+ for (; i.includes(B) && K < 20; )
290
+ T = Math.floor(Math.random() * c.length), B = c[T].name, K++;
291
+ n(c), Z(T), P([...i, B]), A(!1), U(""), D(20), y(null), p ? (b("ready"), F(3), S(7)) : (b("memorize"), S(7));
291
292
  };
292
- M(() => {
293
+ L(() => {
293
294
  if (!(!f || w || h)) {
294
295
  if (g === "ready")
295
- if (E <= 0)
296
+ if (G <= 0)
296
297
  b("memorize");
297
298
  else {
298
299
  const e = setTimeout(() => F((i) => i - 1), 1e3);
@@ -309,7 +310,7 @@ function ye() {
309
310
  if (z <= 0) {
310
311
  A(!0), y("wrong");
311
312
  const i = a[u].name;
312
- B((p) => [
313
+ M((p) => [
313
314
  ...p,
314
315
  { round: x, answer: k, correct: i, result: "wrong" }
315
316
  ]);
@@ -321,7 +322,7 @@ function ye() {
321
322
  }
322
323
  }, [
323
324
  g,
324
- E,
325
+ G,
325
326
  v,
326
327
  z,
327
328
  f,
@@ -332,25 +333,36 @@ function ye() {
332
333
  x,
333
334
  k
334
335
  ]);
335
- const oe = () => {
336
+ const te = () => {
336
337
  if (u === null || H) return;
337
338
  const e = a[u].name, i = k.toLowerCase().trim();
338
339
  let p = "wrong";
339
- i === e ? (R((c) => c + 1), y("correct"), p = "correct") : pe(i, e) === 1 ? (R((c) => c + 0.5), y("almost"), p = "almost") : (y("wrong"), p = "wrong"), B((c) => [
340
+ i === e ? (R((c) => c + 1), y("correct"), p = "correct") : he(i, e) === 1 ? (R((c) => c + 0.5), y("almost"), p = "almost") : (y("wrong"), p = "wrong"), M((c) => [
340
341
  ...c,
341
342
  { round: x, answer: i, correct: e, result: p }
342
343
  ]), Y(!0), setTimeout(() => {
343
344
  Y(!1), A(!0);
344
345
  }, 600);
345
- }, ne = () => x < d ? (G((e) => e + 1), q()) : I(!0), re = () => {
346
+ }, oe = () => x < d ? (E((e) => e + 1), q()) : I(!0), ne = () => {
346
347
  j(!1), I(!1), m(null);
347
- };
348
- return /* @__PURE__ */ s(O, { children: [
349
- !C && /* @__PURE__ */ o(() => /* @__PURE__ */ o("div", { style: t.gmLogoFixed, children: /* @__PURE__ */ o("img", { src: me, alt: "SPEAKID Logo", style: t.gmLogoImg }) }), {}),
348
+ }, re = se(
349
+ () => /* @__PURE__ */ o("div", { style: t.gmLogoFixed, children: /* @__PURE__ */ o("img", { src: pe, alt: "SPEAKID Logo", style: t.gmLogoImg }) }),
350
+ []
351
+ );
352
+ return /* @__PURE__ */ o("div", { id: "whats-missing-root", style: { all: "initial", display: "block" }, children: /* @__PURE__ */ s("div", { style: { all: "unset" }, children: [
353
+ !C && re,
350
354
  !r && !f && /* @__PURE__ */ s("div", { style: t.gmCenterScreen, children: [
351
355
  /* @__PURE__ */ o("h1", { style: t.gmHeadline1, children: "WHAT'S MISSING?" }),
352
356
  /* @__PURE__ */ o("p", { style: t.gmBodyM, children: "Select a theme:" }),
353
- /* @__PURE__ */ o("div", { style: { display: "flex", gap: 16 }, children: ["animals", "food", "toys"].map((e) => /* @__PURE__ */ o("button", { style: t.gmButton, onClick: () => m(e), children: e === "animals" ? "🐶 Animals" : e === "food" ? "🍎 Food" : "🧸 Toys" }, e)) }),
357
+ /* @__PURE__ */ o("div", { style: { display: "flex", gap: 16 }, children: ["animals", "food", "toys"].map((e) => /* @__PURE__ */ o(
358
+ "button",
359
+ {
360
+ style: t.gmButton,
361
+ onClick: () => m(e),
362
+ children: e === "animals" ? "🐶 Animals" : e === "food" ? "🍎 Food" : "🧸 Toys"
363
+ },
364
+ e
365
+ )) }),
354
366
  /* @__PURE__ */ s("div", { style: { marginTop: 24 }, children: [
355
367
  /* @__PURE__ */ o("p", { style: t.gmBodyS, children: "Choose number of rounds:" }),
356
368
  /* @__PURE__ */ o("div", { style: { display: "flex", gap: 12, marginTop: 8 }, children: [3, 4, 5].map((e) => /* @__PURE__ */ o(
@@ -360,7 +372,7 @@ function ye() {
360
372
  ...t.gmButton,
361
373
  ...d === e ? t.gmButtonActive : {}
362
374
  },
363
- onClick: () => Z(e),
375
+ onClick: () => V(e),
364
376
  children: e
365
377
  },
366
378
  e
@@ -382,7 +394,7 @@ function ye() {
382
394
  /* @__PURE__ */ o("h1", { style: t.gmHeadline1, children: "Results" }),
383
395
  /* @__PURE__ */ s("h2", { style: t.gmHeadline3, children: [
384
396
  "Your score: ",
385
- Q,
397
+ J,
386
398
  " / ",
387
399
  d
388
400
  ] }),
@@ -393,7 +405,7 @@ function ye() {
393
405
  /* @__PURE__ */ o("th", { children: "Correct" }),
394
406
  /* @__PURE__ */ o("th", { children: "Result" })
395
407
  ] }) }),
396
- /* @__PURE__ */ o("tbody", { children: X.map((e, i) => /* @__PURE__ */ s("tr", { children: [
408
+ /* @__PURE__ */ o("tbody", { children: Q.map((e, i) => /* @__PURE__ */ s("tr", { children: [
397
409
  /* @__PURE__ */ o("td", { style: t.gmTableCell, children: e.round }),
398
410
  /* @__PURE__ */ o("td", { style: t.gmTableCell, children: e.answer || "—" }),
399
411
  /* @__PURE__ */ o("td", { style: t.gmTableCell, children: e.correct }),
@@ -402,7 +414,7 @@ function ye() {
402
414
  ] }),
403
415
  /* @__PURE__ */ s("div", { style: { display: "flex", gap: 12, marginTop: 24 }, children: [
404
416
  /* @__PURE__ */ o("button", { style: t.gmButton, onClick: $, children: "🔁 Play again" }),
405
- /* @__PURE__ */ o("button", { style: t.gmButton, onClick: re, children: "⬅️ Choose theme" })
417
+ /* @__PURE__ */ o("button", { style: t.gmButton, onClick: ne, children: "⬅️ Choose theme" })
406
418
  ] })
407
419
  ] }),
408
420
  f && !w && /* @__PURE__ */ s("div", { style: t.gmGameLayout, children: [
@@ -417,7 +429,7 @@ function ye() {
417
429
  alignItems: "center"
418
430
  },
419
431
  children: [
420
- g === "ready" && /* @__PURE__ */ s(O, { children: [
432
+ g === "ready" && /* @__PURE__ */ s(ie, { children: [
421
433
  /* @__PURE__ */ o("h1", { style: { ...t.gmHeadline1, color: "#ec4c44" }, children: "GET READY" }),
422
434
  /* @__PURE__ */ o("div", { style: t.gmHourglass, children: "⏳" })
423
435
  ] }),
@@ -443,7 +455,6 @@ function ye() {
443
455
  gridAutoRows: C ? "150px" : "210px",
444
456
  gap: C ? "12px" : "20px",
445
457
  justifyItems: "center",
446
- // 🔹 увеличение только при >2000px
447
458
  ...window.innerWidth > 2e3 ? {
448
459
  gridTemplateColumns: "repeat(3, 260px)",
449
460
  gridAutoRows: "260px",
@@ -499,18 +510,18 @@ function ye() {
499
510
  "button",
500
511
  {
501
512
  style: { ...t.gmButton, marginLeft: 8 },
502
- onClick: oe,
513
+ onClick: te,
503
514
  disabled: H,
504
515
  children: H ? "..." : "Check"
505
516
  }
506
517
  )
507
518
  ] }),
508
- h && /* @__PURE__ */ o("button", { style: t.gmButton, onClick: ne, children: "Next round" })
519
+ h && /* @__PURE__ */ o("button", { style: t.gmButton, onClick: oe, children: "Next round" })
509
520
  ] })
510
521
  ] })
511
- ] });
522
+ ] }) });
512
523
  }
513
524
  export {
514
- ye as Game,
515
- V as themes
525
+ xe as Game,
526
+ O as themes
516
527
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mblinkov/whats-missing",
3
- "version": "20.0.3",
3
+ "version": "20.0.5",
4
4
  "main": "dist/whats-missing.umd.js",
5
5
  "module": "dist/whats-missing.es.js",
6
6
  "types": "dist/index.d.ts",
@@ -99,7 +99,7 @@ export const styles: Record<string, CSSProperties> = {
99
99
  gmGameLayout: {
100
100
  position: "relative",
101
101
  width: "100%",
102
- maxWidth: "600px", // ограничение ширины для мобильных
102
+ maxWidth: "600px",
103
103
  minHeight: "100vh",
104
104
  display: "flex",
105
105
  flexDirection: "column",
@@ -174,19 +174,21 @@ export const styles: Record<string, CSSProperties> = {
174
174
  textOverflow: "ellipsis",
175
175
  },
176
176
 
177
+ // ✅ Исправленный логотип: без белого фона, не ломает верстку
177
178
  gmLogoFixed: {
178
- position: "sticky",
179
+ position: "absolute",
179
180
  top: "16px",
180
- left: "20px",
181
- zIndex: 9999,
182
- background: "white",
183
- padding: "4px 8px",
184
- borderRadius: "8px",
181
+ left: "24px",
182
+ width: "120px",
183
+ zIndex: 10,
184
+ pointerEvents: "none",
185
+ background: "transparent",
185
186
  },
186
187
 
187
188
  gmLogoImg: {
188
189
  height: "clamp(28px, 5vw, 40px)",
189
190
  width: "auto",
191
+ background: "transparent",
190
192
  },
191
193
 
192
194
  gmReadyWrapper: {
package/src/Game.tsx CHANGED
@@ -1,11 +1,10 @@
1
- import { useState, useEffect } from "react";
2
- // логотип теперь в облаке, локальный импорт удаляем
1
+ import { useState, useEffect, useMemo } from "react";
3
2
  import { themes } from "./themes";
4
3
  import { styles } from "./Game.styles";
5
4
  import type { Theme } from "./themes";
6
5
 
7
- // если логотип всё-таки нужен в интерфейсе
8
6
  const logo = window.origin + "/cloud/speakid/games/whatsmissing/logo.png";
7
+
9
8
  type ImageItem = { src: string; name: string };
10
9
  type RoundResult = {
11
10
  round: number;
@@ -14,7 +13,6 @@ type RoundResult = {
14
13
  result: "correct" | "almost" | "wrong";
15
14
  };
16
15
 
17
- // 🔹 встроенный глобальный reset (вместо index.css)
18
16
  const globalReset = () => {
19
17
  const style = document.createElement("style");
20
18
  style.textContent = `
@@ -226,211 +224,220 @@ export default function Game() {
226
224
  setTheme(null);
227
225
  };
228
226
 
229
- const Logo = () => (
230
- <div style={styles.gmLogoFixed}>
231
- <img src={logo} alt="SPEAKID Logo" style={styles.gmLogoImg} />
232
- </div>
227
+ const MemoizedLogo = useMemo(
228
+ () => (
229
+ <div style={styles.gmLogoFixed}>
230
+ <img src={logo} alt="SPEAKID Logo" style={styles.gmLogoImg} />
231
+ </div>
232
+ ),
233
+ []
233
234
  );
234
235
 
235
236
  return (
236
- <>
237
- {!isMobile && <Logo />}
237
+ <div id="whats-missing-root" style={{ all: "initial", display: "block" }}>
238
+ <div style={{ all: "unset" }}>
239
+ {!isMobile && MemoizedLogo}
238
240
 
239
- {!theme && !started && (
240
- <div style={styles.gmCenterScreen}>
241
- <h1 style={styles.gmHeadline1}>WHAT'S MISSING?</h1>
242
- <p style={styles.gmBodyM}>Select a theme:</p>
243
- <div style={{ display: "flex", gap: 16 }}>
244
- {["animals", "food", "toys"].map((t) => (
245
- <button key={t} style={styles.gmButton} onClick={() => setTheme(t as Theme)}>
246
- {t === "animals" ? "🐶 Animals" : t === "food" ? "🍎 Food" : "🧸 Toys"}
247
- </button>
248
- ))}
249
- </div>
250
- <div style={{ marginTop: 24 }}>
251
- <p style={styles.gmBodyS}>Choose number of rounds:</p>
252
- <div style={{ display: "flex", gap: 12, marginTop: 8 }}>
253
- {[3, 4, 5].map((n) => (
241
+ {!theme && !started && (
242
+ <div style={styles.gmCenterScreen}>
243
+ <h1 style={styles.gmHeadline1}>WHAT'S MISSING?</h1>
244
+ <p style={styles.gmBodyM}>Select a theme:</p>
245
+ <div style={{ display: "flex", gap: 16 }}>
246
+ {["animals", "food", "toys"].map((t) => (
254
247
  <button
255
- key={n}
256
- style={{
257
- ...styles.gmButton,
258
- ...(rounds === n ? styles.gmButtonActive : {}),
259
- }}
260
- onClick={() => setRounds(n)}
248
+ key={t}
249
+ style={styles.gmButton}
250
+ onClick={() => setTheme(t as Theme)}
261
251
  >
262
- {n}
252
+ {t === "animals" ? "🐶 Animals" : t === "food" ? "🍎 Food" : "🧸 Toys"}
263
253
  </button>
264
254
  ))}
265
255
  </div>
256
+ <div style={{ marginTop: 24 }}>
257
+ <p style={styles.gmBodyS}>Choose number of rounds:</p>
258
+ <div style={{ display: "flex", gap: 12, marginTop: 8 }}>
259
+ {[3, 4, 5].map((n) => (
260
+ <button
261
+ key={n}
262
+ style={{
263
+ ...styles.gmButton,
264
+ ...(rounds === n ? styles.gmButtonActive : {}),
265
+ }}
266
+ onClick={() => setRounds(n)}
267
+ >
268
+ {n}
269
+ </button>
270
+ ))}
271
+ </div>
272
+ </div>
266
273
  </div>
267
- </div>
268
- )}
274
+ )}
269
275
 
270
- {theme && !started && (
271
- <div style={styles.gmCenterScreen}>
272
- <h1 style={styles.gmHeadline1}>Theme selected: {theme}</h1>
273
- <p style={styles.gmBodyM}>Rounds: {rounds}</p>
274
- <button style={styles.gmButton} onClick={startGame}>
275
- ▶ Start game
276
- </button>
277
- </div>
278
- )}
279
-
280
- {finished && (
281
- <div style={styles.gmCenterScreen}>
282
- <h1 style={styles.gmHeadline1}>Results</h1>
283
- <h2 style={styles.gmHeadline3}>
284
- Your score: {score} / {rounds}
285
- </h2>
286
- <table style={styles.gmTable}>
287
- <thead>
288
- <tr>
289
- <th>Round</th>
290
- <th>Your Answer</th>
291
- <th>Correct</th>
292
- <th>Result</th>
293
- </tr>
294
- </thead>
295
- <tbody>
296
- {resultsTable.map((r, i) => (
297
- <tr key={i}>
298
- <td style={styles.gmTableCell}>{r.round}</td>
299
- <td style={styles.gmTableCell}>{r.answer || "—"}</td>
300
- <td style={styles.gmTableCell}>{r.correct}</td>
301
- <td style={styles.gmTableCell}>
302
- {r.result === "correct"
303
- ? "✔ Correct"
304
- : r.result === "almost"
305
- ? "◐ Almost (0.5)"
306
- : "✘ Wrong"}
307
- </td>
308
- </tr>
309
- ))}
310
- </tbody>
311
- </table>
312
- <div style={{ display: "flex", gap: 12, marginTop: 24 }}>
276
+ {theme && !started && (
277
+ <div style={styles.gmCenterScreen}>
278
+ <h1 style={styles.gmHeadline1}>Theme selected: {theme}</h1>
279
+ <p style={styles.gmBodyM}>Rounds: {rounds}</p>
313
280
  <button style={styles.gmButton} onClick={startGame}>
314
- 🔁 Play again
315
- </button>
316
- <button style={styles.gmButton} onClick={exitGame}>
317
- ⬅️ Choose theme
281
+ Start game
318
282
  </button>
319
283
  </div>
320
- </div>
321
- )}
284
+ )}
322
285
 
323
- {started && !finished && (
324
- <div style={styles.gmGameLayout}>
325
- <div
326
- style={{
327
- minHeight: 160,
328
- display: "flex",
329
- flexDirection: "column",
330
- justifyContent: "center",
331
- alignItems: "center",
332
- }}
333
- >
334
- {phase === "ready" && (
335
- <>
336
- <h1 style={{ ...styles.gmHeadline1, color: "#ec4c44" }}>GET READY</h1>
337
- <div style={styles.gmHourglass}>⏳</div>
338
- </>
339
- )}
340
- {phase === "memorize" && (
341
- <p style={{ ...styles.gmBodyM, color: "#10b981" }}>
342
- MEMORIZE ({memorizeTime})
343
- </p>
344
- )}
345
- {phase === "guess" && !answered && (
346
- <p style={styles.gmBodyM}>⏳ Time left: {timeLeft}s</p>
347
- )}
286
+ {finished && (
287
+ <div style={styles.gmCenterScreen}>
288
+ <h1 style={styles.gmHeadline1}>Results</h1>
289
+ <h2 style={styles.gmHeadline3}>
290
+ Your score: {score} / {rounds}
291
+ </h2>
292
+ <table style={styles.gmTable}>
293
+ <thead>
294
+ <tr>
295
+ <th>Round</th>
296
+ <th>Your Answer</th>
297
+ <th>Correct</th>
298
+ <th>Result</th>
299
+ </tr>
300
+ </thead>
301
+ <tbody>
302
+ {resultsTable.map((r, i) => (
303
+ <tr key={i}>
304
+ <td style={styles.gmTableCell}>{r.round}</td>
305
+ <td style={styles.gmTableCell}>{r.answer || "—"}</td>
306
+ <td style={styles.gmTableCell}>{r.correct}</td>
307
+ <td style={styles.gmTableCell}>
308
+ {r.result === "correct"
309
+ ? "✔ Correct"
310
+ : r.result === "almost"
311
+ ? "◐ Almost (0.5)"
312
+ : "✘ Wrong"}
313
+ </td>
314
+ </tr>
315
+ ))}
316
+ </tbody>
317
+ </table>
318
+ <div style={{ display: "flex", gap: 12, marginTop: 24 }}>
319
+ <button style={styles.gmButton} onClick={startGame}>
320
+ 🔁 Play again
321
+ </button>
322
+ <button style={styles.gmButton} onClick={exitGame}>
323
+ ⬅️ Choose theme
324
+ </button>
325
+ </div>
348
326
  </div>
327
+ )}
349
328
 
350
- {phase !== "ready" && (
329
+ {started && !finished && (
330
+ <div style={styles.gmGameLayout}>
351
331
  <div
352
332
  style={{
353
- ...styles.gmGrid,
354
- gridTemplateColumns: isMobile ? "repeat(2, 1fr)" : "repeat(3, 210px)",
355
- gridAutoRows: isMobile ? "150px" : "210px",
356
- gap: isMobile ? "12px" : "20px",
357
- justifyItems: "center",
358
- // 🔹 увеличение только при >2000px
359
- ...(window.innerWidth > 2000
360
- ? {
361
- gridTemplateColumns: "repeat(3, 260px)",
362
- gridAutoRows: "260px",
363
- gap: "28px",
364
- }
365
- : {}),
366
- ...(window.innerWidth > 2560
367
- ? {
368
- gridTemplateColumns: "repeat(3, 300px)",
369
- gridAutoRows: "300px",
370
- gap: "32px",
371
- }
372
- : {}),
333
+ minHeight: 160,
334
+ display: "flex",
335
+ flexDirection: "column",
336
+ justifyContent: "center",
337
+ alignItems: "center",
373
338
  }}
374
339
  >
375
- {files.map((file, i) => {
376
- const isHidden = hiddenIndex === i && phase === "guess" && !answered;
377
- return (
378
- <div
379
- key={i}
380
- style={{
381
- ...styles.gmCard,
382
- ...(result === "correct" && hiddenIndex === i
383
- ? styles.gmCorrect
384
- : {}),
385
- ...(result === "wrong" && hiddenIndex === i
386
- ? styles.gmWrong
387
- : {}),
388
- }}
389
- >
390
- {!isHidden && (
391
- <img
392
- src={file.src}
393
- alt={file.name}
394
- style={{
395
- width: "100%",
396
- height: "100%",
397
- objectFit: "cover",
398
- }}
399
- />
400
- )}
401
- </div>
402
- );
403
- })}
340
+ {phase === "ready" && (
341
+ <>
342
+ <h1 style={{ ...styles.gmHeadline1, color: "#ec4c44" }}>GET READY</h1>
343
+ <div style={styles.gmHourglass}>⏳</div>
344
+ </>
345
+ )}
346
+ {phase === "memorize" && (
347
+ <p style={{ ...styles.gmBodyM, color: "#10b981" }}>
348
+ MEMORIZE ({memorizeTime})
349
+ </p>
350
+ )}
351
+ {phase === "guess" && !answered && (
352
+ <p style={styles.gmBodyM}>⏳ Time left: {timeLeft}s</p>
353
+ )}
404
354
  </div>
405
- )}
406
355
 
407
- <div style={{ marginTop: 16, height: 80 }}>
408
- {phase === "guess" && !answered && (
409
- <div>
410
- <input
411
- type="text"
412
- placeholder="Type the missing word"
413
- value={inputValue}
414
- onChange={(e) => setInputValue(e.target.value)}
415
- style={styles.gmInput}
416
- />
417
- <button
418
- style={{ ...styles.gmButton, marginLeft: 8 }}
419
- onClick={checkAnswer}
420
- disabled={animating}
421
- >
422
- {animating ? "..." : "Check"}
423
- </button>
356
+ {phase !== "ready" && (
357
+ <div
358
+ style={{
359
+ ...styles.gmGrid,
360
+ gridTemplateColumns: isMobile ? "repeat(2, 1fr)" : "repeat(3, 210px)",
361
+ gridAutoRows: isMobile ? "150px" : "210px",
362
+ gap: isMobile ? "12px" : "20px",
363
+ justifyItems: "center",
364
+ ...(window.innerWidth > 2000
365
+ ? {
366
+ gridTemplateColumns: "repeat(3, 260px)",
367
+ gridAutoRows: "260px",
368
+ gap: "28px",
369
+ }
370
+ : {}),
371
+ ...(window.innerWidth > 2560
372
+ ? {
373
+ gridTemplateColumns: "repeat(3, 300px)",
374
+ gridAutoRows: "300px",
375
+ gap: "32px",
376
+ }
377
+ : {}),
378
+ }}
379
+ >
380
+ {files.map((file, i) => {
381
+ const isHidden =
382
+ hiddenIndex === i && phase === "guess" && !answered;
383
+ return (
384
+ <div
385
+ key={i}
386
+ style={{
387
+ ...styles.gmCard,
388
+ ...(result === "correct" && hiddenIndex === i
389
+ ? styles.gmCorrect
390
+ : {}),
391
+ ...(result === "wrong" && hiddenIndex === i
392
+ ? styles.gmWrong
393
+ : {}),
394
+ }}
395
+ >
396
+ {!isHidden && (
397
+ <img
398
+ src={file.src}
399
+ alt={file.name}
400
+ style={{
401
+ width: "100%",
402
+ height: "100%",
403
+ objectFit: "cover",
404
+ }}
405
+ />
406
+ )}
407
+ </div>
408
+ );
409
+ })}
424
410
  </div>
425
411
  )}
426
- {answered && (
427
- <button style={styles.gmButton} onClick={nextRound}>
428
- Next round
429
- </button>
430
- )}
412
+
413
+ <div style={{ marginTop: 16, height: 80 }}>
414
+ {phase === "guess" && !answered && (
415
+ <div>
416
+ <input
417
+ type="text"
418
+ placeholder="Type the missing word"
419
+ value={inputValue}
420
+ onChange={(e) => setInputValue(e.target.value)}
421
+ style={styles.gmInput}
422
+ />
423
+ <button
424
+ style={{ ...styles.gmButton, marginLeft: 8 }}
425
+ onClick={checkAnswer}
426
+ disabled={animating}
427
+ >
428
+ {animating ? "..." : "Check"}
429
+ </button>
430
+ </div>
431
+ )}
432
+ {answered && (
433
+ <button style={styles.gmButton} onClick={nextRound}>
434
+ Next round
435
+ </button>
436
+ )}
437
+ </div>
431
438
  </div>
432
- </div>
433
- )}
434
- </>
439
+ )}
440
+ </div>
441
+ </div>
435
442
  );
436
443
  }