@mblinkov/whats-missing 20.0.15 → 20.0.17

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