@mblinkov/whats-missing 20.0.15 → 20.0.16

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.
@@ -15,4 +15,4 @@
15
15
  user-select: none;
16
16
  }
17
17
  html, body { margin: 0; padding: 0; }
18
- `,document.head.appendChild(r)},ue=(r,a)=>{const l=Array.from({length:r.length+1},()=>Array(a.length+1).fill(0));for(let n=0;n<=r.length;n++)l[n][0]=n;for(let n=0;n<=a.length;n++)l[0][n]=n;for(let n=1;n<=r.length;n++)for(let c=1;c<=a.length;c++)l[n][c]=r[n-1]===a[c-1]?l[n-1][c-1]:Math.min(l[n-1][c-1],l[n][c-1],l[n-1][c])+1;return l[r.length][a.length]};function he(){const r=o.useRef(null);o.useEffect(()=>(ge(),()=>{document.body.style.overflow=""}),[]);const[a,l]=o.useState(null),[n,c]=o.useState([]),[b,K]=o.useState(4),[x,W]=o.useState(!1),[w,E]=o.useState(1),[h,Z]=o.useState(null),[g,j]=o.useState("ready"),[G,F]=o.useState(3),[v,C]=o.useState(10),[T,D]=o.useState(20),[J,z]=o.useState(0),[S,R]=o.useState(!1),[k,Y]=o.useState(""),[p,I]=o.useState(!1),[H,q]=o.useState(!1),[O,y]=o.useState(null),[Q,M]=o.useState([]),[X,P]=o.useState([]),[u,ee]=o.useState(!1),[te,U]=o.useState(1);o.useEffect(()=>{const t=()=>{const i=window.innerWidth<768;if(ee(i),i)U(1);else{const f=Math.min(window.innerWidth/1440,window.innerHeight/768);U(f)}};return t(),window.addEventListener("resize",t),()=>window.removeEventListener("resize",t)},[]);const $=t=>[...t].sort(()=>Math.random()-.5).slice(0,6),N=()=>{if(!a)return;const t=$(L[a]);c(t),W(!0),R(!1),E(1),z(0),M([]),P([]),V(t,[],!0)},V=(t=n,i=X,m=!1)=>{const d=$(t.length?t:L[a]);let f=Math.floor(Math.random()*d.length),A=d[f].name,_=0;for(;i.includes(A)&&_<20;)f=Math.floor(Math.random()*d.length),A=d[f].name,_++;c(d),Z(f),P([...i,A]),I(!1),Y(""),D(20),y(null),m?(j("ready"),F(3),C(10)):(j("memorize"),C(10))};o.useEffect(()=>{if(!(!x||S||p)){if(g==="ready")if(G<=0)j("memorize");else{const t=setTimeout(()=>F(i=>i-1),1e3);return()=>clearTimeout(t)}if(g==="memorize")if(v<=0)j("guess");else{const t=setTimeout(()=>C(i=>i-1),1e3);return()=>clearTimeout(t)}if(g==="guess"){if(T<=0){I(!0),y("wrong");const i=n[h].name;M(m=>[...m,{round:w,answer:k,correct:i,result:"wrong"}]);return}const t=setTimeout(()=>D(i=>i-1),1e3);return()=>clearTimeout(t)}}},[g,G,v,T,x,S,p,n,h,w,k]);const se=()=>{if(h===null||H)return;const t=n[h].name,i=k.toLowerCase().trim();let m="wrong";i===t?(z(d=>d+1),y("correct"),m="correct"):ue(i,t)===1?(z(d=>d+.5),y("almost"),m="almost"):(y("wrong"),m="wrong"),M(d=>[...d,{round:w,answer:i,correct:t,result:m}]),q(!0),setTimeout(()=>{q(!1),I(!0)},600)},ne=()=>w<b?(E(t=>t+1),V()):R(!0),oe=()=>{W(!1),R(!1),l(null)},ie=o.useMemo(()=>e.jsx("div",{style:s.gmLogoFixed,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:s.gmLogoImg,loading:"lazy"})]})}),[]);return e.jsx("div",{ref:r,style:{width:"100%",height:"100vh",display:"flex",justifyContent:"center",alignItems:"center",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",transition:"background 0.3s ease"},children:e.jsx("div",{style:{width:u?"100vw":1440,height:u?"100vh":768,transform:u?"none":`scale(${te})`,transformOrigin:"top center",display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",overflow:"hidden",borderRadius:u?0:"20px",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",boxShadow:u?"none":"0 0 40px rgba(0,0,0,0.1)"},children:e.jsxs("div",{id:"whats-missing-root",children:[!u&&ie,!a&&!x&&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:()=>l(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,...b===t?s.gmButtonActive:{}},onClick:()=>K(t),children:t},t))})]})]}),a&&!x&&e.jsxs("div",{style:s.gmCenterScreen,children:[e.jsxs("h1",{style:s.gmHeadline1,children:["Theme selected: ",a]}),e.jsxs("p",{style:s.gmBodyM,children:["Rounds: ",b]}),e.jsx("button",{style:s.gmButton,onClick:N,children:"▶ Start game"})]}),S&&e.jsxs("div",{style:s.gmCenterScreen,children:[e.jsx("h1",{style:s.gmHeadline1,children:"Results"}),e.jsxs("h2",{style:s.gmHeadline3,children:["Your score: ",J," / ",b]}),e.jsx("p",{style:{...s.gmBodyM,color:"#10b981",marginTop:12},children:"Yahoo! You did it! 🍬✨"}),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:Q.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:oe,children:"⬅️ Choose theme"})]})]}),x&&!S&&e.jsxs("div",{style:s.gmGameLayout,children:[e.jsxs("div",{style:{minHeight:160,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[g==="ready"&&e.jsxs(e.Fragment,{children:[e.jsx("h1",{style:{...s.gmHeadline1,color:"#ec4c44"},children:"GET READY"}),e.jsx("div",{style:s.gmHourglass,children:"⏳"})]}),g==="memorize"&&e.jsxs("p",{style:{...s.gmBodyM,color:"#10b981"},children:["MEMORIZE (",v,")"]}),g==="guess"&&!p&&e.jsxs("p",{style:s.gmBodyM,children:["⏳ Time left: ",T,"s"]})]}),g!=="ready"&&e.jsx("div",{style:{...s.gmGrid,gridTemplateColumns:u?"repeat(2, 1fr)":"repeat(3, 210px)",gridAutoRows:u?"150px":"210px",gap:u?"12px":"20px",justifyItems:"center"},children:n.map((t,i)=>{const m=h===i&&g==="guess"&&!p;return e.jsx("div",{style:{...s.gmCard,...O==="correct"&&h===i?s.gmCorrect:{},...O==="wrong"&&h===i?s.gmWrong:{}},children:!m&&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:[g==="guess"&&!p&&e.jsxs("div",{children:[e.jsx("input",{type:"text",placeholder:"Type the missing word",value:k,onChange:t=>Y(t.target.value),style:s.gmInput}),e.jsx("button",{style:{...s.gmButton,marginLeft:8},onClick:se,disabled:H,children:H?"...":"Check"})]}),p&&e.jsx("button",{style:s.gmButton,onClick:ne,children:"Next round"})]})]})]})})})}exports.Game=he;exports.themes=L;
18
+ `,document.head.appendChild(r)},ue=(r,a)=>{const l=Array.from({length:r.length+1},()=>Array(a.length+1).fill(0));for(let n=0;n<=r.length;n++)l[n][0]=n;for(let n=0;n<=a.length;n++)l[0][n]=n;for(let n=1;n<=r.length;n++)for(let c=1;c<=a.length;c++)l[n][c]=r[n-1]===a[c-1]?l[n-1][c-1]:Math.min(l[n-1][c-1],l[n][c-1],l[n-1][c])+1;return l[r.length][a.length]};function he(){const r=o.useRef(null);o.useEffect(()=>(ge(),()=>{document.body.style.overflow=""}),[]);const[a,l]=o.useState(null),[n,c]=o.useState([]),[b,K]=o.useState(4),[x,W]=o.useState(!1),[w,E]=o.useState(1),[h,Z]=o.useState(null),[g,j]=o.useState("ready"),[G,F]=o.useState(3),[v,C]=o.useState(10),[T,Y]=o.useState(20),[J,z]=o.useState(0),[S,R]=o.useState(!1),[k,D]=o.useState(""),[p,I]=o.useState(!1),[H,q]=o.useState(!1),[O,y]=o.useState(null),[Q,M]=o.useState([]),[X,P]=o.useState([]),[u,ee]=o.useState(!1),[te,U]=o.useState(1);o.useEffect(()=>{const t=()=>{const i=window.innerWidth<768;if(ee(i),i)U(1);else{const f=Math.min(window.innerWidth/1440,window.innerHeight/768);U(f)}};return t(),window.addEventListener("resize",t),()=>window.removeEventListener("resize",t)},[]);const $=t=>[...t].sort(()=>Math.random()-.5).slice(0,6),N=()=>{if(!a)return;const t=$(L[a]);c(t),W(!0),R(!1),E(1),z(0),M([]),P([]),V(t,[],!0)},V=(t=n,i=X,m=!1)=>{const d=$(t.length?t:L[a]);let f=Math.floor(Math.random()*d.length),A=d[f].name,_=0;for(;i.includes(A)&&_<20;)f=Math.floor(Math.random()*d.length),A=d[f].name,_++;c(d),Z(f),P([...i,A]),I(!1),D(""),Y(20),y(null),m?(j("ready"),F(3),C(10)):(j("memorize"),C(10))};o.useEffect(()=>{if(!(!x||S||p)){if(g==="ready")if(G<=0)j("memorize");else{const t=setTimeout(()=>F(i=>i-1),1e3);return()=>clearTimeout(t)}if(g==="memorize")if(v<=0)j("guess");else{const t=setTimeout(()=>C(i=>i-1),1e3);return()=>clearTimeout(t)}if(g==="guess"){if(T<=0){I(!0),y("wrong");const i=n[h].name;M(m=>[...m,{round:w,answer:k,correct:i,result:"wrong"}]);return}const t=setTimeout(()=>Y(i=>i-1),1e3);return()=>clearTimeout(t)}}},[g,G,v,T,x,S,p,n,h,w,k]);const se=()=>{if(h===null||H)return;const t=n[h].name,i=k.toLowerCase().trim();let m="wrong";i===t?(z(d=>d+1),y("correct"),m="correct"):ue(i,t)===1?(z(d=>d+.5),y("almost"),m="almost"):(y("wrong"),m="wrong"),M(d=>[...d,{round:w,answer:i,correct:t,result:m}]),q(!0),setTimeout(()=>{q(!1),I(!0)},600)},ne=()=>w<b?(E(t=>t+1),V()):R(!0),oe=()=>{W(!1),R(!1),l(null)},ie=o.useMemo(()=>e.jsx("div",{style:s.gmLogoFixed,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:s.gmLogoImg,loading:"lazy"})]})}),[]);return e.jsx("div",{ref:r,style:{width:"100%",height:"100vh",display:"flex",justifyContent:"center",alignItems:"center",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",transition:"background 0.3s ease"},children:e.jsx("div",{style:{width:u?"100%":1440,height:u?"100%":768,display:"flex",justifyContent:"center",alignItems:"center",overflow:"hidden",borderRadius:u?0:"20px",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",boxShadow:u?"none":"0 0 40px rgba(0,0,0,0.1)",margin:u?"0 auto":"unset"},children:e.jsx("div",{style:{transform:u?"none":`scale(${te})`,transformOrigin:"center center",width:"100%",height:"100%",display:"flex",justifyContent:"center",alignItems:"center"},children:e.jsxs("div",{id:"whats-missing-root",children:[!u&&ie,!a&&!x&&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:()=>l(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,...b===t?s.gmButtonActive:{}},onClick:()=>K(t),children:t},t))})]})]}),a&&!x&&e.jsxs("div",{style:s.gmCenterScreen,children:[e.jsxs("h1",{style:s.gmHeadline1,children:["Theme selected: ",a]}),e.jsxs("p",{style:s.gmBodyM,children:["Rounds: ",b]}),e.jsx("button",{style:s.gmButton,onClick:N,children:"▶ Start game"})]}),S&&e.jsxs("div",{style:s.gmCenterScreen,children:[e.jsx("h1",{style:s.gmHeadline1,children:"Results"}),e.jsxs("h2",{style:s.gmHeadline3,children:["Your score: ",J," / ",b]}),e.jsx("p",{style:{...s.gmBodyM,color:"#10b981",marginTop:12},children:"Yahoo! You did it! 🍬✨"}),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:Q.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:oe,children:"⬅️ Choose theme"})]})]}),x&&!S&&e.jsxs("div",{style:s.gmGameLayout,children:[e.jsxs("div",{style:{minHeight:160,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[g==="ready"&&e.jsxs(e.Fragment,{children:[e.jsx("h1",{style:{...s.gmHeadline1,color:"#ec4c44"},children:"GET READY"}),e.jsx("div",{style:s.gmHourglass,children:"⏳"})]}),g==="memorize"&&e.jsxs("p",{style:{...s.gmBodyM,color:"#10b981"},children:["MEMORIZE (",v,")"]}),g==="guess"&&!p&&e.jsxs("p",{style:s.gmBodyM,children:["⏳ Time left: ",T,"s"]})]}),g!=="ready"&&e.jsx("div",{style:{...s.gmGrid,gridTemplateColumns:u?"repeat(2, 1fr)":"repeat(3, 210px)",gridAutoRows:u?"150px":"210px",gap:u?"12px":"20px",justifyItems:"center"},children:n.map((t,i)=>{const m=h===i&&g==="guess"&&!p;return e.jsx("div",{style:{...s.gmCard,...O==="correct"&&h===i?s.gmCorrect:{},...O==="wrong"&&h===i?s.gmWrong:{}},children:!m&&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:[g==="guess"&&!p&&e.jsxs("div",{children:[e.jsx("input",{type:"text",placeholder:"Type the missing word",value:k,onChange:t=>D(t.target.value),style:s.gmInput}),e.jsx("button",{style:{...s.gmButton,marginLeft:8},onClick:se,disabled:H,children:H?"...":"Check"})]}),p&&e.jsx("button",{style:s.gmButton,onClick:ne,children:"Next round"})]})]})]})})})})}exports.Game=he;exports.themes=L;
@@ -1,8 +1,8 @@
1
- import { jsx as o, jsxs as r, Fragment as ae } from "react/jsx-runtime";
2
- import { useRef as de, useEffect as W, useState as s, useMemo as ce } from "react";
3
- const me = window.origin + "/cloud/speakid/games/whatsmissing/", j = (l, a) => l.map(([d, n]) => ({
4
- src: `${me}${a}/${n.replace(/\s/g, "%20")}.png`,
5
- name: n
1
+ import { jsx as t, jsxs as r, Fragment as ae } from "react/jsx-runtime";
2
+ import { useRef as de, useEffect as j, useState as s, useMemo as ce } from "react";
3
+ const me = window.origin + "/cloud/speakid/games/whatsmissing/", W = (l, a) => l.map(([d, o]) => ({
4
+ src: `${me}${a}/${o.replace(/\s/g, "%20")}.png`,
5
+ name: o
6
6
  })), ge = [
7
7
  ["apple", "apple"],
8
8
  ["banana", "banana"],
@@ -70,9 +70,9 @@ const me = window.origin + "/cloud/speakid/games/whatsmissing/", j = (l, a) => l
70
70
  ["yo-yo", "yo-yo"],
71
71
  ["crayons", "crayons"]
72
72
  ], Z = {
73
- food: j(ge, "food"),
74
- animals: j(he, "animals"),
75
- toys: j(pe, "toys")
73
+ food: W(ge, "food"),
74
+ animals: W(he, "animals"),
75
+ toys: W(pe, "toys")
76
76
  }, ue = `
77
77
  @keyframes spin {
78
78
  from { transform: rotate(0deg); }
@@ -85,7 +85,7 @@ if (typeof document < "u" && !document.getElementById("spin-keyframes")) {
85
85
  }
86
86
  const fe = {
87
87
  animation: "spin 1.4s linear infinite"
88
- }, t = {
88
+ }, n = {
89
89
  gmCenterScreen: {
90
90
  position: "relative",
91
91
  zIndex: 1,
@@ -252,23 +252,23 @@ const fe = {
252
252
  `, document.head.appendChild(l);
253
253
  }, be = (l, a) => {
254
254
  const d = Array.from({ length: l.length + 1 }, () => Array(a.length + 1).fill(0));
255
- for (let n = 0; n <= l.length; n++) d[n][0] = n;
256
- for (let n = 0; n <= a.length; n++) d[0][n] = n;
257
- for (let n = 1; n <= l.length; n++)
255
+ for (let o = 0; o <= l.length; o++) d[o][0] = o;
256
+ for (let o = 0; o <= a.length; o++) d[0][o] = o;
257
+ for (let o = 1; o <= l.length; o++)
258
258
  for (let m = 1; m <= a.length; m++)
259
- d[n][m] = l[n - 1] === a[m - 1] ? d[n - 1][m - 1] : Math.min(d[n - 1][m - 1], d[n][m - 1], d[n - 1][m]) + 1;
259
+ d[o][m] = l[o - 1] === a[m - 1] ? d[o - 1][m - 1] : Math.min(d[o - 1][m - 1], d[o][m - 1], d[o - 1][m]) + 1;
260
260
  return d[l.length][a.length];
261
261
  };
262
262
  function ke() {
263
263
  const l = de(null);
264
- W(() => (ye(), () => {
264
+ j(() => (ye(), () => {
265
265
  document.body.style.overflow = "";
266
266
  }), []);
267
- const [a, d] = s(null), [n, m] = s([]), [w, J] = s(4), [b, E] = s(!1), [k, G] = s(1), [u, Q] = s(null), [h, v] = s("ready"), [F, D] = s(3), [S, z] = s(10), [R, Y] = s(20), [X, I] = s(0), [C, H] = s(!1), [T, U] = s(""), [f, M] = s(!1), [A, $] = s(!1), [N, x] = s(null), [ee, B] = s([]), [te, O] = s([]), [p, oe] = s(!1), [ne, P] = s(1);
268
- W(() => {
267
+ const [a, d] = s(null), [o, m] = s([]), [w, J] = s(4), [b, E] = s(!1), [k, G] = s(1), [u, Q] = s(null), [h, v] = s("ready"), [F, Y] = s(3), [S, z] = s(10), [R, D] = s(20), [X, I] = s(0), [C, H] = s(!1), [T, U] = s(""), [f, M] = s(!1), [A, $] = s(!1), [N, x] = s(null), [ee, B] = s([]), [te, O] = s([]), [p, ne] = s(!1), [oe, P] = s(1);
268
+ j(() => {
269
269
  const e = () => {
270
270
  const i = window.innerWidth < 768;
271
- if (oe(i), i)
271
+ if (ne(i), i)
272
272
  P(1);
273
273
  else {
274
274
  const y = Math.min(window.innerWidth / 1440, window.innerHeight / 768);
@@ -281,19 +281,19 @@ function ke() {
281
281
  if (!a) return;
282
282
  const e = V(Z[a]);
283
283
  m(e), E(!0), H(!1), G(1), I(0), B([]), O([]), q(e, [], !0);
284
- }, q = (e = n, i = te, g = !1) => {
284
+ }, q = (e = o, i = te, g = !1) => {
285
285
  const c = V(e.length ? e : Z[a]);
286
286
  let y = Math.floor(Math.random() * c.length), L = c[y].name, K = 0;
287
287
  for (; i.includes(L) && K < 20; )
288
288
  y = Math.floor(Math.random() * c.length), L = c[y].name, K++;
289
- m(c), Q(y), O([...i, L]), M(!1), U(""), Y(20), x(null), g ? (v("ready"), D(3), z(10)) : (v("memorize"), z(10));
289
+ m(c), Q(y), O([...i, L]), M(!1), U(""), D(20), x(null), g ? (v("ready"), Y(3), z(10)) : (v("memorize"), z(10));
290
290
  };
291
- W(() => {
291
+ j(() => {
292
292
  if (!(!b || C || f)) {
293
293
  if (h === "ready")
294
294
  if (F <= 0) v("memorize");
295
295
  else {
296
- const e = setTimeout(() => D((i) => i - 1), 1e3);
296
+ const e = setTimeout(() => Y((i) => i - 1), 1e3);
297
297
  return () => clearTimeout(e);
298
298
  }
299
299
  if (h === "memorize")
@@ -305,21 +305,21 @@ function ke() {
305
305
  if (h === "guess") {
306
306
  if (R <= 0) {
307
307
  M(!0), x("wrong");
308
- const i = n[u].name;
308
+ const i = o[u].name;
309
309
  B((g) => [
310
310
  ...g,
311
311
  { round: k, answer: T, correct: i, result: "wrong" }
312
312
  ]);
313
313
  return;
314
314
  }
315
- const e = setTimeout(() => Y((i) => i - 1), 1e3);
315
+ const e = setTimeout(() => D((i) => i - 1), 1e3);
316
316
  return () => clearTimeout(e);
317
317
  }
318
318
  }
319
- }, [h, F, S, R, b, C, f, n, u, k, T]);
319
+ }, [h, F, S, R, b, C, f, o, u, k, T]);
320
320
  const ie = () => {
321
321
  if (u === null || A) return;
322
- const e = n[u].name, i = T.toLowerCase().trim();
322
+ const e = o[u].name, i = T.toLowerCase().trim();
323
323
  let g = "wrong";
324
324
  i === e ? (I((c) => c + 1), x("correct"), g = "correct") : be(i, e) === 1 ? (I((c) => c + 0.5), x("almost"), g = "almost") : (x("wrong"), g = "wrong"), B((c) => [...c, { round: k, answer: i, correct: e, result: g }]), $(!0), setTimeout(() => {
325
325
  $(!1), M(!0);
@@ -327,13 +327,13 @@ function ke() {
327
327
  }, re = () => k < w ? (G((e) => e + 1), q()) : H(!0), se = () => {
328
328
  E(!1), H(!1), d(null);
329
329
  }, le = ce(
330
- () => /* @__PURE__ */ o("div", { style: t.gmLogoFixed, children: /* @__PURE__ */ r("picture", { children: [
331
- /* @__PURE__ */ o("source", { srcSet: window.origin + "/cloud/speakid/games/whatsmissing/logo.svg", type: "image/svg+xml" }),
332
- /* @__PURE__ */ o("img", { src: window.origin + "/cloud/speakid/games/whatsmissing/logo.png", alt: "SPEAKID Logo", style: t.gmLogoImg, loading: "lazy" })
330
+ () => /* @__PURE__ */ t("div", { style: n.gmLogoFixed, children: /* @__PURE__ */ r("picture", { children: [
331
+ /* @__PURE__ */ t("source", { srcSet: window.origin + "/cloud/speakid/games/whatsmissing/logo.svg", type: "image/svg+xml" }),
332
+ /* @__PURE__ */ t("img", { src: window.origin + "/cloud/speakid/games/whatsmissing/logo.png", alt: "SPEAKID Logo", style: n.gmLogoImg, loading: "lazy" })
333
333
  ] }) }),
334
334
  []
335
335
  );
336
- return /* @__PURE__ */ o(
336
+ return /* @__PURE__ */ t(
337
337
  "div",
338
338
  {
339
339
  ref: l,
@@ -346,169 +346,181 @@ function ke() {
346
346
  background: "linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",
347
347
  transition: "background 0.3s ease"
348
348
  },
349
- children: /* @__PURE__ */ o(
349
+ children: /* @__PURE__ */ t(
350
350
  "div",
351
351
  {
352
352
  style: {
353
- width: p ? "100vw" : 1440,
354
- height: p ? "100vh" : 768,
355
- transform: p ? "none" : `scale(${ne})`,
356
- transformOrigin: "top center",
353
+ width: p ? "100%" : 1440,
354
+ height: p ? "100%" : 768,
357
355
  display: "flex",
358
- flexDirection: "column",
359
356
  justifyContent: "center",
360
357
  alignItems: "center",
361
358
  overflow: "hidden",
362
359
  borderRadius: p ? 0 : "20px",
363
360
  background: "linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",
364
- boxShadow: p ? "none" : "0 0 40px rgba(0,0,0,0.1)"
361
+ boxShadow: p ? "none" : "0 0 40px rgba(0,0,0,0.1)",
362
+ margin: p ? "0 auto" : "unset"
365
363
  },
366
- children: /* @__PURE__ */ r("div", { id: "whats-missing-root", children: [
367
- !p && le,
368
- !a && !b && /* @__PURE__ */ r("div", { style: t.gmCenterScreen, children: [
369
- /* @__PURE__ */ o("h1", { style: t.gmHeadline1, children: "WHAT'S MISSING?" }),
370
- /* @__PURE__ */ o("p", { style: t.gmBodyM, children: "Select a theme:" }),
371
- /* @__PURE__ */ o("div", { style: { display: "flex", gap: 16 }, children: ["animals", "food", "toys"].map((e) => /* @__PURE__ */ o("button", { style: t.gmButton, onClick: () => d(e), children: e === "animals" ? "🐶 Animals" : e === "food" ? "🍎 Food" : "🧸 Toys" }, e)) }),
372
- /* @__PURE__ */ r("div", { style: { marginTop: 24 }, children: [
373
- /* @__PURE__ */ o("p", { style: t.gmBodyS, children: "Choose number of rounds:" }),
374
- /* @__PURE__ */ o("div", { style: { display: "flex", gap: 12, marginTop: 8 }, children: [3, 4, 5].map((e) => /* @__PURE__ */ o(
375
- "button",
376
- {
377
- style: {
378
- ...t.gmButton,
379
- ...w === e ? t.gmButtonActive : {}
380
- },
381
- onClick: () => J(e),
382
- children: e
383
- },
384
- e
385
- )) })
386
- ] })
387
- ] }),
388
- a && !b && /* @__PURE__ */ r("div", { style: t.gmCenterScreen, children: [
389
- /* @__PURE__ */ r("h1", { style: t.gmHeadline1, children: [
390
- "Theme selected: ",
391
- a
392
- ] }),
393
- /* @__PURE__ */ r("p", { style: t.gmBodyM, children: [
394
- "Rounds: ",
395
- w
396
- ] }),
397
- /* @__PURE__ */ o("button", { style: t.gmButton, onClick: _, children: "▶ Start game" })
398
- ] }),
399
- C && /* @__PURE__ */ r("div", { style: t.gmCenterScreen, children: [
400
- /* @__PURE__ */ o("h1", { style: t.gmHeadline1, children: "Results" }),
401
- /* @__PURE__ */ r("h2", { style: t.gmHeadline3, children: [
402
- "Your score: ",
403
- X,
404
- " / ",
405
- w
406
- ] }),
407
- /* @__PURE__ */ o("p", { style: { ...t.gmBodyM, color: "#10b981", marginTop: 12 }, children: "Yahoo! You did it! 🍬✨" }),
408
- /* @__PURE__ */ r("table", { style: t.gmTable, children: [
409
- /* @__PURE__ */ o("thead", { children: /* @__PURE__ */ r("tr", { children: [
410
- /* @__PURE__ */ o("th", { children: "Round" }),
411
- /* @__PURE__ */ o("th", { children: "Your Answer" }),
412
- /* @__PURE__ */ o("th", { children: "Correct" }),
413
- /* @__PURE__ */ o("th", { children: "Result" })
414
- ] }) }),
415
- /* @__PURE__ */ o("tbody", { children: ee.map((e, i) => /* @__PURE__ */ r("tr", { children: [
416
- /* @__PURE__ */ o("td", { style: t.gmTableCell, children: e.round }),
417
- /* @__PURE__ */ o("td", { style: t.gmTableCell, children: e.answer || "—" }),
418
- /* @__PURE__ */ o("td", { style: t.gmTableCell, children: e.correct }),
419
- /* @__PURE__ */ o("td", { style: t.gmTableCell, children: e.result === "correct" ? "✔ Correct" : e.result === "almost" ? "◐ Almost (0.5)" : "✘ Wrong" })
420
- ] }, i)) })
421
- ] }),
422
- /* @__PURE__ */ r("div", { style: { display: "flex", gap: 12, marginTop: 24 }, children: [
423
- /* @__PURE__ */ o("button", { style: t.gmButton, onClick: _, children: "🔁 Play again" }),
424
- /* @__PURE__ */ o("button", { style: t.gmButton, onClick: se, children: "⬅️ Choose theme" })
425
- ] })
426
- ] }),
427
- b && !C && /* @__PURE__ */ r("div", { style: t.gmGameLayout, children: [
428
- /* @__PURE__ */ r(
429
- "div",
430
- {
431
- style: {
432
- minHeight: 160,
433
- display: "flex",
434
- flexDirection: "column",
435
- justifyContent: "center",
436
- alignItems: "center"
437
- },
438
- children: [
439
- h === "ready" && /* @__PURE__ */ r(ae, { children: [
440
- /* @__PURE__ */ o("h1", { style: { ...t.gmHeadline1, color: "#ec4c44" }, children: "GET READY" }),
441
- /* @__PURE__ */ o("div", { style: t.gmHourglass, children: "⏳" })
442
- ] }),
443
- h === "memorize" && /* @__PURE__ */ r("p", { style: { ...t.gmBodyM, color: "#10b981" }, children: [
444
- "MEMORIZE (",
445
- S,
446
- ")"
447
- ] }),
448
- h === "guess" && !f && /* @__PURE__ */ r("p", { style: t.gmBodyM, children: [
449
- "⏳ Time left: ",
450
- R,
451
- "s"
452
- ] })
453
- ]
454
- }
455
- ),
456
- h !== "ready" && /* @__PURE__ */ o(
457
- "div",
458
- {
459
- style: {
460
- ...t.gmGrid,
461
- gridTemplateColumns: p ? "repeat(2, 1fr)" : "repeat(3, 210px)",
462
- gridAutoRows: p ? "150px" : "210px",
463
- gap: p ? "12px" : "20px",
464
- justifyItems: "center"
465
- },
466
- children: n.map((e, i) => {
467
- const g = u === i && h === "guess" && !f;
468
- return /* @__PURE__ */ o(
469
- "div",
364
+ children: /* @__PURE__ */ t(
365
+ "div",
366
+ {
367
+ style: {
368
+ transform: p ? "none" : `scale(${oe})`,
369
+ transformOrigin: "center center",
370
+ width: "100%",
371
+ height: "100%",
372
+ display: "flex",
373
+ justifyContent: "center",
374
+ alignItems: "center"
375
+ },
376
+ children: /* @__PURE__ */ r("div", { id: "whats-missing-root", children: [
377
+ !p && le,
378
+ !a && !b && /* @__PURE__ */ r("div", { style: n.gmCenterScreen, children: [
379
+ /* @__PURE__ */ t("h1", { style: n.gmHeadline1, children: "WHAT'S MISSING?" }),
380
+ /* @__PURE__ */ t("p", { style: n.gmBodyM, children: "Select a theme:" }),
381
+ /* @__PURE__ */ t("div", { style: { display: "flex", gap: 16 }, children: ["animals", "food", "toys"].map((e) => /* @__PURE__ */ t("button", { style: n.gmButton, onClick: () => d(e), children: e === "animals" ? "🐶 Animals" : e === "food" ? "🍎 Food" : "🧸 Toys" }, e)) }),
382
+ /* @__PURE__ */ r("div", { style: { marginTop: 24 }, children: [
383
+ /* @__PURE__ */ t("p", { style: n.gmBodyS, children: "Choose number of rounds:" }),
384
+ /* @__PURE__ */ t("div", { style: { display: "flex", gap: 12, marginTop: 8 }, children: [3, 4, 5].map((e) => /* @__PURE__ */ t(
385
+ "button",
470
386
  {
471
387
  style: {
472
- ...t.gmCard,
473
- ...N === "correct" && u === i ? t.gmCorrect : {},
474
- ...N === "wrong" && u === i ? t.gmWrong : {}
388
+ ...n.gmButton,
389
+ ...w === e ? n.gmButtonActive : {}
475
390
  },
476
- children: !g && /* @__PURE__ */ o(
477
- "img",
478
- {
479
- src: e.src,
480
- alt: e.name,
481
- style: {
482
- width: "100%",
483
- height: "100%",
484
- objectFit: "cover"
485
- }
486
- }
487
- )
391
+ onClick: () => J(e),
392
+ children: e
393
+ },
394
+ e
395
+ )) })
396
+ ] })
397
+ ] }),
398
+ a && !b && /* @__PURE__ */ r("div", { style: n.gmCenterScreen, children: [
399
+ /* @__PURE__ */ r("h1", { style: n.gmHeadline1, children: [
400
+ "Theme selected: ",
401
+ a
402
+ ] }),
403
+ /* @__PURE__ */ r("p", { style: n.gmBodyM, children: [
404
+ "Rounds: ",
405
+ w
406
+ ] }),
407
+ /* @__PURE__ */ t("button", { style: n.gmButton, onClick: _, children: "▶ Start game" })
408
+ ] }),
409
+ C && /* @__PURE__ */ r("div", { style: n.gmCenterScreen, children: [
410
+ /* @__PURE__ */ t("h1", { style: n.gmHeadline1, children: "Results" }),
411
+ /* @__PURE__ */ r("h2", { style: n.gmHeadline3, children: [
412
+ "Your score: ",
413
+ X,
414
+ " / ",
415
+ w
416
+ ] }),
417
+ /* @__PURE__ */ t("p", { style: { ...n.gmBodyM, color: "#10b981", marginTop: 12 }, children: "Yahoo! You did it! 🍬✨" }),
418
+ /* @__PURE__ */ r("table", { style: n.gmTable, children: [
419
+ /* @__PURE__ */ t("thead", { children: /* @__PURE__ */ r("tr", { children: [
420
+ /* @__PURE__ */ t("th", { children: "Round" }),
421
+ /* @__PURE__ */ t("th", { children: "Your Answer" }),
422
+ /* @__PURE__ */ t("th", { children: "Correct" }),
423
+ /* @__PURE__ */ t("th", { children: "Result" })
424
+ ] }) }),
425
+ /* @__PURE__ */ t("tbody", { children: ee.map((e, i) => /* @__PURE__ */ r("tr", { children: [
426
+ /* @__PURE__ */ t("td", { style: n.gmTableCell, children: e.round }),
427
+ /* @__PURE__ */ t("td", { style: n.gmTableCell, children: e.answer || "—" }),
428
+ /* @__PURE__ */ t("td", { style: n.gmTableCell, children: e.correct }),
429
+ /* @__PURE__ */ t("td", { style: n.gmTableCell, children: e.result === "correct" ? "✔ Correct" : e.result === "almost" ? "◐ Almost (0.5)" : "✘ Wrong" })
430
+ ] }, i)) })
431
+ ] }),
432
+ /* @__PURE__ */ r("div", { style: { display: "flex", gap: 12, marginTop: 24 }, children: [
433
+ /* @__PURE__ */ t("button", { style: n.gmButton, onClick: _, children: "🔁 Play again" }),
434
+ /* @__PURE__ */ t("button", { style: n.gmButton, onClick: se, children: "⬅️ Choose theme" })
435
+ ] })
436
+ ] }),
437
+ b && !C && /* @__PURE__ */ r("div", { style: n.gmGameLayout, children: [
438
+ /* @__PURE__ */ r(
439
+ "div",
440
+ {
441
+ style: {
442
+ minHeight: 160,
443
+ display: "flex",
444
+ flexDirection: "column",
445
+ justifyContent: "center",
446
+ alignItems: "center"
488
447
  },
489
- i
490
- );
491
- })
492
- }
493
- ),
494
- /* @__PURE__ */ r("div", { style: { marginTop: 16, height: 80 }, children: [
495
- h === "guess" && !f && /* @__PURE__ */ r("div", { children: [
496
- /* @__PURE__ */ o(
497
- "input",
448
+ children: [
449
+ h === "ready" && /* @__PURE__ */ r(ae, { children: [
450
+ /* @__PURE__ */ t("h1", { style: { ...n.gmHeadline1, color: "#ec4c44" }, children: "GET READY" }),
451
+ /* @__PURE__ */ t("div", { style: n.gmHourglass, children: "⏳" })
452
+ ] }),
453
+ h === "memorize" && /* @__PURE__ */ r("p", { style: { ...n.gmBodyM, color: "#10b981" }, children: [
454
+ "MEMORIZE (",
455
+ S,
456
+ ")"
457
+ ] }),
458
+ h === "guess" && !f && /* @__PURE__ */ r("p", { style: n.gmBodyM, children: [
459
+ "⏳ Time left: ",
460
+ R,
461
+ "s"
462
+ ] })
463
+ ]
464
+ }
465
+ ),
466
+ h !== "ready" && /* @__PURE__ */ t(
467
+ "div",
498
468
  {
499
- type: "text",
500
- placeholder: "Type the missing word",
501
- value: T,
502
- onChange: (e) => U(e.target.value),
503
- style: t.gmInput
469
+ style: {
470
+ ...n.gmGrid,
471
+ gridTemplateColumns: p ? "repeat(2, 1fr)" : "repeat(3, 210px)",
472
+ gridAutoRows: p ? "150px" : "210px",
473
+ gap: p ? "12px" : "20px",
474
+ justifyItems: "center"
475
+ },
476
+ children: o.map((e, i) => {
477
+ const g = u === i && h === "guess" && !f;
478
+ return /* @__PURE__ */ t(
479
+ "div",
480
+ {
481
+ style: {
482
+ ...n.gmCard,
483
+ ...N === "correct" && u === i ? n.gmCorrect : {},
484
+ ...N === "wrong" && u === i ? n.gmWrong : {}
485
+ },
486
+ children: !g && /* @__PURE__ */ t(
487
+ "img",
488
+ {
489
+ src: e.src,
490
+ alt: e.name,
491
+ style: {
492
+ width: "100%",
493
+ height: "100%",
494
+ objectFit: "cover"
495
+ }
496
+ }
497
+ )
498
+ },
499
+ i
500
+ );
501
+ })
504
502
  }
505
503
  ),
506
- /* @__PURE__ */ o("button", { style: { ...t.gmButton, marginLeft: 8 }, onClick: ie, disabled: A, children: A ? "..." : "Check" })
507
- ] }),
508
- f && /* @__PURE__ */ o("button", { style: t.gmButton, onClick: re, children: "Next round" })
504
+ /* @__PURE__ */ r("div", { style: { marginTop: 16, height: 80 }, children: [
505
+ h === "guess" && !f && /* @__PURE__ */ r("div", { children: [
506
+ /* @__PURE__ */ t(
507
+ "input",
508
+ {
509
+ type: "text",
510
+ placeholder: "Type the missing word",
511
+ value: T,
512
+ onChange: (e) => U(e.target.value),
513
+ style: n.gmInput
514
+ }
515
+ ),
516
+ /* @__PURE__ */ t("button", { style: { ...n.gmButton, marginLeft: 8 }, onClick: ie, disabled: A, children: A ? "..." : "Check" })
517
+ ] }),
518
+ f && /* @__PURE__ */ t("button", { style: n.gmButton, onClick: re, children: "Next round" })
519
+ ] })
520
+ ] })
509
521
  ] })
510
- ] })
511
- ] })
522
+ }
523
+ )
512
524
  }
513
525
  )
514
526
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mblinkov/whats-missing",
3
- "version": "20.0.15",
3
+ "version": "20.0.16",
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
@@ -1,4 +1,3 @@
1
-
2
1
  import { useState, useEffect, useMemo, useRef } from "react";
3
2
  import { themes } from "./themes";
4
3
  import { styles } from "./Game.styles";
@@ -99,9 +98,6 @@ export default function Game() {
99
98
  return () => window.removeEventListener("resize", resize);
100
99
  }, []);
101
100
 
102
- // =============================
103
- // GAME LOGIC
104
- // =============================
105
101
  const getRandomSix = (arr: ImageItem[]) =>
106
102
  [...arr].sort(() => Math.random() - 0.5).slice(0, 6);
107
103
 
@@ -211,7 +207,6 @@ export default function Game() {
211
207
  setTheme(null);
212
208
  };
213
209
 
214
- // логотип
215
210
  const MemoizedLogo = useMemo(
216
211
  () => (
217
212
  <div style={styles.gmLogoFixed}>
@@ -240,190 +235,200 @@ export default function Game() {
240
235
  transition: "background 0.3s ease",
241
236
  }}
242
237
  >
243
- {/* Внутренний canvas (виртуальное игровое окно 1440x768) */}
244
238
  <div
245
239
  style={{
246
- width: isMobile ? "100vw" : 1440,
247
- height: isMobile ? "100vh" : 768,
248
- transform: isMobile ? "none" : `scale(${scale})`,
249
- transformOrigin: "top center",
240
+ width: isMobile ? "100%" : 1440,
241
+ height: isMobile ? "100%" : 768,
250
242
  display: "flex",
251
- flexDirection: "column",
252
243
  justifyContent: "center",
253
244
  alignItems: "center",
254
245
  overflow: "hidden",
255
246
  borderRadius: isMobile ? 0 : "20px",
256
247
  background: "linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",
257
248
  boxShadow: isMobile ? "none" : "0 0 40px rgba(0,0,0,0.1)",
249
+ margin: isMobile ? "0 auto" : "unset",
258
250
  }}
259
251
  >
260
- <div id="whats-missing-root">
261
- {!isMobile && MemoizedLogo}
252
+ {/* ✅ добавленный блок для правильного масштабирования и центрирования */}
253
+ <div
254
+ style={{
255
+ transform: isMobile ? "none" : `scale(${scale})`,
256
+ transformOrigin: "center center",
257
+ width: "100%",
258
+ height: "100%",
259
+ display: "flex",
260
+ justifyContent: "center",
261
+ alignItems: "center",
262
+ }}
263
+ >
264
+ <div id="whats-missing-root">
265
+ {!isMobile && MemoizedLogo}
262
266
 
263
- {/* ====== ИГРОВАЯ ЛОГИКА ====== */}
264
- {!theme && !started && (
265
- <div style={styles.gmCenterScreen}>
266
- <h1 style={styles.gmHeadline1}>WHAT'S MISSING?</h1>
267
- <p style={styles.gmBodyM}>Select a theme:</p>
268
- <div style={{ display: "flex", gap: 16 }}>
269
- {["animals", "food", "toys"].map((t) => (
270
- <button key={t} style={styles.gmButton} onClick={() => setTheme(t as Theme)}>
271
- {t === "animals" ? "🐶 Animals" : t === "food" ? "🍎 Food" : "🧸 Toys"}
272
- </button>
273
- ))}
274
- </div>
275
- <div style={{ marginTop: 24 }}>
276
- <p style={styles.gmBodyS}>Choose number of rounds:</p>
277
- <div style={{ display: "flex", gap: 12, marginTop: 8 }}>
278
- {[3, 4, 5].map((n) => (
279
- <button
280
- key={n}
281
- style={{
282
- ...styles.gmButton,
283
- ...(rounds === n ? styles.gmButtonActive : {}),
284
- }}
285
- onClick={() => setRounds(n)}
286
- >
287
- {n}
267
+ {/* ====== ИГРОВАЯ ЛОГИКА ====== */}
268
+ {!theme && !started && (
269
+ <div style={styles.gmCenterScreen}>
270
+ <h1 style={styles.gmHeadline1}>WHAT'S MISSING?</h1>
271
+ <p style={styles.gmBodyM}>Select a theme:</p>
272
+ <div style={{ display: "flex", gap: 16 }}>
273
+ {["animals", "food", "toys"].map((t) => (
274
+ <button key={t} style={styles.gmButton} onClick={() => setTheme(t as Theme)}>
275
+ {t === "animals" ? "🐶 Animals" : t === "food" ? "🍎 Food" : "🧸 Toys"}
288
276
  </button>
289
277
  ))}
290
278
  </div>
279
+ <div style={{ marginTop: 24 }}>
280
+ <p style={styles.gmBodyS}>Choose number of rounds:</p>
281
+ <div style={{ display: "flex", gap: 12, marginTop: 8 }}>
282
+ {[3, 4, 5].map((n) => (
283
+ <button
284
+ key={n}
285
+ style={{
286
+ ...styles.gmButton,
287
+ ...(rounds === n ? styles.gmButtonActive : {}),
288
+ }}
289
+ onClick={() => setRounds(n)}
290
+ >
291
+ {n}
292
+ </button>
293
+ ))}
294
+ </div>
295
+ </div>
291
296
  </div>
292
- </div>
293
- )}
297
+ )}
294
298
 
295
- {theme && !started && (
296
- <div style={styles.gmCenterScreen}>
297
- <h1 style={styles.gmHeadline1}>Theme selected: {theme}</h1>
298
- <p style={styles.gmBodyM}>Rounds: {rounds}</p>
299
- <button style={styles.gmButton} onClick={startGame}>
300
- ▶ Start game
301
- </button>
302
- </div>
303
- )}
304
-
305
- {finished && (
306
- <div style={styles.gmCenterScreen}>
307
- <h1 style={styles.gmHeadline1}>Results</h1>
308
- <h2 style={styles.gmHeadline3}>
309
- Your score: {score} / {rounds}
310
- </h2>
311
- <p style={{ ...styles.gmBodyM, color: "#10b981", marginTop: 12 }}>Yahoo! You did it! 🍬✨</p>
312
- <table style={styles.gmTable}>
313
- <thead>
314
- <tr>
315
- <th>Round</th>
316
- <th>Your Answer</th>
317
- <th>Correct</th>
318
- <th>Result</th>
319
- </tr>
320
- </thead>
321
- <tbody>
322
- {resultsTable.map((r, i) => (
323
- <tr key={i}>
324
- <td style={styles.gmTableCell}>{r.round}</td>
325
- <td style={styles.gmTableCell}>{r.answer || "—"}</td>
326
- <td style={styles.gmTableCell}>{r.correct}</td>
327
- <td style={styles.gmTableCell}>
328
- {r.result === "correct"
329
- ? "✔ Correct"
330
- : r.result === "almost"
331
- ? "◐ Almost (0.5)"
332
- : "✘ Wrong"}
333
- </td>
334
- </tr>
335
- ))}
336
- </tbody>
337
- </table>
338
- <div style={{ display: "flex", gap: 12, marginTop: 24 }}>
299
+ {theme && !started && (
300
+ <div style={styles.gmCenterScreen}>
301
+ <h1 style={styles.gmHeadline1}>Theme selected: {theme}</h1>
302
+ <p style={styles.gmBodyM}>Rounds: {rounds}</p>
339
303
  <button style={styles.gmButton} onClick={startGame}>
340
- 🔁 Play again
341
- </button>
342
- <button style={styles.gmButton} onClick={exitGame}>
343
- ⬅️ Choose theme
304
+ Start game
344
305
  </button>
345
306
  </div>
346
- </div>
347
- )}
307
+ )}
348
308
 
349
- {started && !finished && (
350
- <div style={styles.gmGameLayout}>
351
- <div
352
- style={{
353
- minHeight: 160,
354
- display: "flex",
355
- flexDirection: "column",
356
- justifyContent: "center",
357
- alignItems: "center",
358
- }}
359
- >
360
- {phase === "ready" && (
361
- <>
362
- <h1 style={{ ...styles.gmHeadline1, color: "#ec4c44" }}>GET READY</h1>
363
- <div style={styles.gmHourglass}>⏳</div>
364
- </>
365
- )}
366
- {phase === "memorize" && <p style={{ ...styles.gmBodyM, color: "#10b981" }}>MEMORIZE ({memorizeTime})</p>}
367
- {phase === "guess" && !answered && <p style={styles.gmBodyM}>⏳ Time left: {timeLeft}s</p>}
309
+ {finished && (
310
+ <div style={styles.gmCenterScreen}>
311
+ <h1 style={styles.gmHeadline1}>Results</h1>
312
+ <h2 style={styles.gmHeadline3}>
313
+ Your score: {score} / {rounds}
314
+ </h2>
315
+ <p style={{ ...styles.gmBodyM, color: "#10b981", marginTop: 12 }}>Yahoo! You did it! 🍬✨</p>
316
+ <table style={styles.gmTable}>
317
+ <thead>
318
+ <tr>
319
+ <th>Round</th>
320
+ <th>Your Answer</th>
321
+ <th>Correct</th>
322
+ <th>Result</th>
323
+ </tr>
324
+ </thead>
325
+ <tbody>
326
+ {resultsTable.map((r, i) => (
327
+ <tr key={i}>
328
+ <td style={styles.gmTableCell}>{r.round}</td>
329
+ <td style={styles.gmTableCell}>{r.answer || "—"}</td>
330
+ <td style={styles.gmTableCell}>{r.correct}</td>
331
+ <td style={styles.gmTableCell}>
332
+ {r.result === "correct"
333
+ ? "✔ Correct"
334
+ : r.result === "almost"
335
+ ? "◐ Almost (0.5)"
336
+ : "✘ Wrong"}
337
+ </td>
338
+ </tr>
339
+ ))}
340
+ </tbody>
341
+ </table>
342
+ <div style={{ display: "flex", gap: 12, marginTop: 24 }}>
343
+ <button style={styles.gmButton} onClick={startGame}>
344
+ 🔁 Play again
345
+ </button>
346
+ <button style={styles.gmButton} onClick={exitGame}>
347
+ ⬅️ Choose theme
348
+ </button>
349
+ </div>
368
350
  </div>
351
+ )}
369
352
 
370
- {phase !== "ready" && (
353
+ {started && !finished && (
354
+ <div style={styles.gmGameLayout}>
371
355
  <div
372
356
  style={{
373
- ...styles.gmGrid,
374
- gridTemplateColumns: isMobile ? "repeat(2, 1fr)" : "repeat(3, 210px)",
375
- gridAutoRows: isMobile ? "150px" : "210px",
376
- gap: isMobile ? "12px" : "20px",
377
- justifyItems: "center",
357
+ minHeight: 160,
358
+ display: "flex",
359
+ flexDirection: "column",
360
+ justifyContent: "center",
361
+ alignItems: "center",
378
362
  }}
379
363
  >
380
- {files.map((file, i) => {
381
- const isHidden = hiddenIndex === i && phase === "guess" && !answered;
382
- return (
383
- <div
384
- key={i}
385
- style={{
386
- ...styles.gmCard,
387
- ...(result === "correct" && hiddenIndex === i ? styles.gmCorrect : {}),
388
- ...(result === "wrong" && hiddenIndex === i ? styles.gmWrong : {}),
389
- }}
390
- >
391
- {!isHidden && (
392
- <img
393
- src={file.src}
394
- alt={file.name}
395
- style={{
396
- width: "100%",
397
- height: "100%",
398
- objectFit: "cover",
399
- }}
400
- />
401
- )}
402
- </div>
403
- );
404
- })}
364
+ {phase === "ready" && (
365
+ <>
366
+ <h1 style={{ ...styles.gmHeadline1, color: "#ec4c44" }}>GET READY</h1>
367
+ <div style={styles.gmHourglass}>⏳</div>
368
+ </>
369
+ )}
370
+ {phase === "memorize" && <p style={{ ...styles.gmBodyM, color: "#10b981" }}>MEMORIZE ({memorizeTime})</p>}
371
+ {phase === "guess" && !answered && <p style={styles.gmBodyM}>⏳ Time left: {timeLeft}s</p>}
405
372
  </div>
406
- )}
407
373
 
408
- <div style={{ marginTop: 16, height: 80 }}>
409
- {phase === "guess" && !answered && (
410
- <div>
411
- <input
412
- type="text"
413
- placeholder="Type the missing word"
414
- value={inputValue}
415
- onChange={(e) => setInputValue(e.target.value)}
416
- style={styles.gmInput}
417
- />
418
- <button style={{ ...styles.gmButton, marginLeft: 8 }} onClick={checkAnswer} disabled={animating}>
419
- {animating ? "..." : "Check"}
420
- </button>
374
+ {phase !== "ready" && (
375
+ <div
376
+ style={{
377
+ ...styles.gmGrid,
378
+ gridTemplateColumns: isMobile ? "repeat(2, 1fr)" : "repeat(3, 210px)",
379
+ gridAutoRows: isMobile ? "150px" : "210px",
380
+ gap: isMobile ? "12px" : "20px",
381
+ justifyItems: "center",
382
+ }}
383
+ >
384
+ {files.map((file, i) => {
385
+ const isHidden = hiddenIndex === i && phase === "guess" && !answered;
386
+ return (
387
+ <div
388
+ key={i}
389
+ style={{
390
+ ...styles.gmCard,
391
+ ...(result === "correct" && hiddenIndex === i ? styles.gmCorrect : {}),
392
+ ...(result === "wrong" && hiddenIndex === i ? styles.gmWrong : {}),
393
+ }}
394
+ >
395
+ {!isHidden && (
396
+ <img
397
+ src={file.src}
398
+ alt={file.name}
399
+ style={{
400
+ width: "100%",
401
+ height: "100%",
402
+ objectFit: "cover",
403
+ }}
404
+ />
405
+ )}
406
+ </div>
407
+ );
408
+ })}
421
409
  </div>
422
410
  )}
423
- {answered && <button style={styles.gmButton} onClick={nextRound}>Next round</button>}
411
+
412
+ <div style={{ marginTop: 16, height: 80 }}>
413
+ {phase === "guess" && !answered && (
414
+ <div>
415
+ <input
416
+ type="text"
417
+ placeholder="Type the missing word"
418
+ value={inputValue}
419
+ onChange={(e) => setInputValue(e.target.value)}
420
+ style={styles.gmInput}
421
+ />
422
+ <button style={{ ...styles.gmButton, marginLeft: 8 }} onClick={checkAnswer} disabled={animating}>
423
+ {animating ? "..." : "Check"}
424
+ </button>
425
+ </div>
426
+ )}
427
+ {answered && <button style={styles.gmButton} onClick={nextRound}>Next round</button>}
428
+ </div>
424
429
  </div>
425
- </div>
426
- )}
430
+ )}
431
+ </div>
427
432
  </div>
428
433
  </div>
429
434
  </div>