diff --git a/build/public/assets/index.0aa9cc2a.js b/build/public/assets/index.0aa9cc2a.js new file mode 100644 index 0000000..5567da5 --- /dev/null +++ b/build/public/assets/index.0aa9cc2a.js @@ -0,0 +1 @@ +import{d as e,c as t,a as n,w as l,b as o,r as i,o as a,e as s,t as r,F as c,f as d,g as u,h as g,v as p,i as h,j as m,k as y,l as f,m as w,n as v,p as b}from"./vendor.1ad14f11.js";var x=e({name:"app",computed:{showNav(){return!["game","replay"].includes(String(this.$route.name))}}});const C={id:"app"},k={key:0,class:"nav"},A=s("Index"),T=s("New game");x.render=function(e,s,r,c,d,u){const g=i("router-link"),p=i("router-view");return a(),t("div",C,[e.showNav?(a(),t("ul",k,[n("li",null,[n(g,{class:"btn",to:{name:"index"}},{default:l((()=>[A])),_:1})]),n("li",null,[n(g,{class:"btn",to:{name:"new-game"}},{default:l((()=>[T])),_:1})])])):o("",!0),n(p)])};const S=864e5,z=e=>{const t=Math.floor(e/S);e%=S;const n=Math.floor(e/36e5);e%=36e5;const l=Math.floor(e/6e4);e%=6e4;return`${t}d ${n}h ${l}m ${Math.floor(e/1e3)}s`};var I=1e3,P=()=>{const e=new Date;return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds())},_=(e,t)=>z(t-e),D=z,B=e({name:"game-teaser",props:{game:{type:Object,required:!0}},computed:{style(){return{"background-image":`url("${this.game.imageUrl.replace("uploads/","uploads/r/")+"-375x210.webp"}")`}}},methods:{time(e,t){const n=t?"🏁":"⏳",l=e,o=t||P();return`${n} ${_(l,o)}`}}});const E={class:"game-info-text"},O=n("br",null,null,-1),U=n("br",null,null,-1),N=n("br",null,null,-1);B.render=function(e,c,d,u,g,p){const h=i("router-link");return a(),t("div",{class:"game-teaser",style:e.style},[n(h,{class:"game-info",to:{name:"game",params:{id:e.game.id}}},{default:l((()=>[n("span",E,[s(" 🧩 "+r(e.game.tilesFinished)+"/"+r(e.game.tilesTotal),1),O,s(" πŸ‘₯ "+r(e.game.players),1),U,s(" "+r(e.time(e.game.started,e.game.finished)),1),N])])),_:1},8,["to"]),o("",!0)],4)};var M=e({components:{GameTeaser:B},data:()=>({gamesRunning:[],gamesFinished:[]}),async created(){const e=await fetch("/api/index-data"),t=await e.json();this.gamesRunning=t.gamesRunning,this.gamesFinished=t.gamesFinished}});const G=n("h1",null,"Running games",-1),$=n("h1",null,"Finished games",-1);M.render=function(e,l,o,s,r,u){const g=i("game-teaser");return a(),t("div",null,[G,(a(!0),t(c,null,d(e.gamesRunning,((e,l)=>(a(),t("div",{class:"game-teaser-wrap",key:l},[n(g,{game:e},null,8,["game"])])))),128)),$,(a(!0),t(c,null,d(e.gamesFinished,((e,l)=>(a(),t("div",{class:"game-teaser-wrap",key:l},[n(g,{game:e},null,8,["game"])])))),128))])};var R=e({name:"image-teaser",props:{image:{type:Object,required:!0}},computed:{style(){return{backgroundImage:`url("${this.image.url.replace("uploads/","uploads/r/")+"-150x100.webp"}")`}}},emits:{click:null,editClick:null},methods:{onClick(){this.$emit("click")},onEditClick(){this.$emit("editClick")}}});R.render=function(e,l,o,i,s,r){return a(),t("div",{class:"imageteaser",style:e.style,onClick:l[2]||(l[2]=(...t)=>e.onClick&&e.onClick(...t))},[n("div",{class:"btn edit",onClick:l[1]||(l[1]=u(((...t)=>e.onEditClick&&e.onEditClick(...t)),["stop"]))},"✏️")],4)};var V=e({name:"image-library",components:{ImageTeaser:R},props:{images:{type:Array,required:!0}},emits:{imageClicked:null,imageEditClicked:null},methods:{imageClicked(e){this.$emit("imageClicked",e)},imageEditClicked(e){this.$emit("imageEditClicked",e)}}});V.render=function(e,n,l,o,s,r){const u=i("image-teaser");return a(),t("div",null,[(a(!0),t(c,null,d(e.images,((n,l)=>(a(),t(u,{image:n,onClick:t=>e.imageClicked(n),onEditClick:t=>e.imageEditClicked(n),key:l},null,8,["image","onClick","onEditClick"])))),128))])};var j=e({name:"upload",props:{accept:String,label:String},methods:{async upload(e){const t=e.target;if(!t.files)return;const n=t.files[0];if(!n)return;const l=new FormData;l.append("file",n,n.name);const o=await fetch("/upload",{method:"post",body:l}),i=await o.json();this.$emit("uploaded",i)}}});const F={class:"btn"};j.render=function(e,l,o,i,s,c){return a(),t("label",null,[n("input",{type:"file",style:{display:"none"},onChange:l[1]||(l[1]=(...t)=>e.upload&&e.upload(...t)),accept:e.accept},null,40,["accept"]),n("span",F,r(e.label||"Upload File"),1)])};const W={name:"responsive-image",props:{src:String,title:{type:String,default:""},height:{type:String,default:"100%"},width:{type:String,default:"100%"}},computed:{style(){return{display:"inline-block",verticalAlign:"text-bottom",backgroundImage:`url('${this.src}')`,backgroundRepeat:"no-repeat",backgroundSize:"contain",backgroundPosition:"center",width:this.width,height:this.height}}}};W.render=function(e,n,l,o,i,s){return a(),t("div",{style:s.style,title:l.title},null,12,["title"])};var L=e({name:"new-image-dialog",components:{Upload:j,ResponsiveImage:W},emits:{bgclick:null,setupGameClick:null,postToGalleryClick:null},data:()=>({previewUrl:"",file:null,title:"",category:""}),computed:{canPostToGallery(){return!(!this.previewUrl||!this.file)},canSetupGameClick(){return!(!this.previewUrl||!this.file)}},methods:{preview(e){const t=e.target;if(!t.files)return;const n=t.files[0];if(!n)return;const l=new FileReader;l.readAsDataURL(n),l.onload=e=>{this.previewUrl=e.target.result,this.file=n}},postToGallery(){this.$emit("postToGalleryClick",{file:this.file,title:this.title,category:this.category})},setupGameClick(){this.$emit("setupGameClick",{file:this.file,title:this.title,category:this.category})}}});const H={key:0,class:"has-image"},Q={key:1},Y={class:"upload"},q={class:"btn"},Z={class:"area-settings"},K=n("td",null,[n("label",null,"Title")],-1),J=n("tr",null,[n("td",{colspan:"2"},[n("div",{class:"hint"},"Feel free to leave a credit to the artist/photographer in the title :)")])],-1),X=n("td",null,[n("label",null,"Category")],-1),ee={class:"area-buttons"},te=s("🧩 Post to gallery "),ne=n("br",null,null,-1),le=s(" + set up game");L.render=function(e,l,o,s,c,d){const h=i("responsive-image");return a(),t("div",{class:"overlay new-image-dialog",onClick:l[8]||(l[8]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:l[7]||(l[7]=u((()=>{}),["stop"]))},[n("div",{class:["area-image",{"has-image":!!e.previewUrl,"no-image":!e.previewUrl}]},[e.previewUrl?(a(),t("div",H,[n("span",{class:"remove btn",onClick:l[1]||(l[1]=t=>e.previewUrl="")},"X"),n(h,{src:e.previewUrl},null,8,["src"])])):(a(),t("div",Q,[n("label",Y,[n("input",{type:"file",style:{display:"none"},onChange:l[2]||(l[2]=(...t)=>e.preview&&e.preview(...t)),accept:"image/*"},null,32),n("span",q,r(e.label||"Upload File"),1)])]))],2),n("div",Z,[n("table",null,[n("tr",null,[K,n("td",null,[g(n("input",{type:"text","onUpdate:modelValue":l[3]||(l[3]=t=>e.title=t),placeholder:"Flower by @artist"},null,512),[[p,e.title]])])]),J,n("tr",null,[X,n("td",null,[g(n("input",{type:"text","onUpdate:modelValue":l[4]||(l[4]=t=>e.category=t),placeholder:"Plants"},null,512),[[p,e.category]])])])])]),n("div",ee,[n("button",{class:"btn",disabled:!e.canPostToGallery,onClick:l[5]||(l[5]=(...t)=>e.postToGallery&&e.postToGallery(...t))},"πŸ–ΌοΈ Post to gallery",8,["disabled"]),n("button",{class:"btn",disabled:!e.canSetupGameClick,onClick:l[6]||(l[6]=(...t)=>e.setupGameClick&&e.setupGameClick(...t))},[te,ne,le],8,["disabled"])])])])};var oe=e({name:"edit-image-dialog",components:{ResponsiveImage:W},props:{image:{type:Object,required:!0}},emits:{bgclick:null,saveClick:null},data:()=>({title:"",category:""}),created(){this.title=this.image.title,this.category=this.image.categories.length>0?this.image.categories[0].title:""},methods:{saveImage(){this.$emit("saveClick",{id:this.image.id,title:this.title,category:this.category})}}});const ie={class:"area-image"},ae={class:"has-image"},se={class:"area-settings"},re=n("td",null,[n("label",null,"Title")],-1),ce=n("tr",null,[n("td",{colspan:"2"},[n("div",{class:"hint"},"Feel free to leave a credit to the artist/photographer in the title :)")])],-1),de=n("td",null,[n("label",null,"Category")],-1),ue={class:"area-buttons"};function ge(e,t){const n=e.x-t.x,l=e.y-t.y;return Math.sqrt(n*n+l*l)}function pe(e){return{x:e.x+e.w/2,y:e.y+e.h/2}}oe.render=function(e,l,o,s,r,c){const d=i("responsive-image");return a(),t("div",{class:"overlay edit-image-dialog",onClick:l[5]||(l[5]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:l[4]||(l[4]=u((()=>{}),["stop"]))},[n("div",ie,[n("div",ae,[n(d,{src:e.image.url,title:e.image.title},null,8,["src","title"])])]),n("div",se,[n("table",null,[n("tr",null,[re,n("td",null,[g(n("input",{type:"text","onUpdate:modelValue":l[1]||(l[1]=t=>e.title=t),placeholder:"Flower by @artist"},null,512),[[p,e.title]])])]),ce,n("tr",null,[de,n("td",null,[g(n("input",{type:"text","onUpdate:modelValue":l[2]||(l[2]=t=>e.category=t),placeholder:"Plants"},null,512),[[p,e.category]])])])])]),n("div",ue,[n("button",{class:"btn",onClick:l[3]||(l[3]=(...t)=>e.saveImage&&e.saveImage(...t))},"πŸ–ΌοΈ Save image")])])])};var he={pointSub:function(e,t){return{x:e.x-t.x,y:e.y-t.y}},pointAdd:function(e,t){return{x:e.x+t.x,y:e.y+t.y}},pointDistance:ge,pointInBounds:function(e,t){return e.x>=t.x&&e.x<=t.x+t.w&&e.y>=t.y&&e.y<=t.y+t.h},rectCenter:pe,rectMoved:function(e,t,n){return{x:e.x+t,y:e.y+n,w:e.w,h:e.h}},rectCenterDistance:function(e,t){return ge(pe(e),pe(t))},rectsOverlap:function(e,t){return!(t.x>e.x+e.w||e.x>t.x+t.w||t.y>e.y+e.h||e.y>t.y+t.h)}};var me=1,ye=4,fe=5,we=2,ve=3,be=6,xe=2,Ce=4,ke=3,Ae=9,Te=1,Se=2,ze=3,Ie=4,Pe=5,_e=6,De=7,Be=8,Ee=10,Oe=1,Ue=2,Ne=3;class Me{constructor(e){this.rand_high=e||3735929054,this.rand_low=1231121986^e}random(e,t){return this.rand_high=(this.rand_high<<16)+(this.rand_high>>16)+this.rand_low&4294967295,this.rand_low=this.rand_low+this.rand_high&4294967295,e+(this.rand_high>>>0)/4294967295*(t-e+1)|0}choice(e){return e[this.random(0,e.length-1)]}shuffle(e){const t=e.slice();for(let n=0;n<=t.length-2;n++){const e=this.random(n,t.length-1),l=t[n];t[n]=t[e],t[e]=l}return t}static serialize(e){return{rand_high:e.rand_high,rand_low:e.rand_low}}static unserialize(e){const t=new Me(0);return t.rand_high=e.rand_high,t.rand_low=e.rand_low,t}}const Ge=(e,t)=>{const n=`${e}`;return n.length>=t.length?n:t.substr(0,t.length-n.length)+n},$e=(...e)=>{const t=t=>(...n)=>{const l=new Date,o=Ge(l.getHours(),"00"),i=Ge(l.getMinutes(),"00"),a=Ge(l.getSeconds(),"00");console[t](`${o}:${i}:${a}`,...e,...n)};return{log:t("log"),error:t("error"),info:t("info")}};var Re,Ve,je,Fe,We={hash:e=>{let t=0;for(let n=0;n{let t=e.toLowerCase();return t=t.replace(/[^a-z0-9]+/g,"-"),t=t.replace(/^-|-$/,""),t},uniqId:()=>Date.now().toString(36)+Math.random().toString(36).substring(2),encodeShape:function(e){return e.top+1<<0|e.right+1<<2|e.bottom+1<<4|e.left+1<<6},decodeShape:function(e){return{top:(e>>0&3)-1,right:(e>>2&3)-1,bottom:(e>>4&3)-1,left:(e>>6&3)-1}},encodeTile:function(e){return[e.idx,e.pos.x,e.pos.y,e.z,e.owner,e.group]},decodeTile:function(e){return{idx:e[0],pos:{x:e[1],y:e[2]},z:e[3],owner:e[4],group:e[5]}},encodePlayer:function(e){return[e.id,e.x,e.y,e.d,e.name,e.color,e.bgcolor,e.points,e.ts]},decodePlayer:function(e){return{id:e[0],x:e[1],y:e[2],d:e[3],name:e[4],color:e[5],bgcolor:e[6],points:e[7],ts:e[8]}},encodeGame:function(e){return Array.isArray(e)?e:[e.id,e.rng.type,Me.serialize(e.rng.obj),e.puzzle,e.players,e.evtInfos,e.scoreMode]},decodeGame:function(e){return Array.isArray(e)?{id:e[0],rng:{type:e[1],obj:Me.unserialize(e[2])},puzzle:e[3],players:e[4],evtInfos:e[5],scoreMode:e[6]}:e},coordByTileIdx:function(e,t){const n=e.width/e.tileSize;return{x:t%n,y:Math.floor(t/n)}},asQueryArgs:function(e){const t=[];for(let n in e){const l=[n,e[n]].map(encodeURIComponent);t.push(l.join("="))}return 0===t.length?"":`?${t.join("&")}`}};(Ve=Re||(Re={}))[Ve.Flat=0]="Flat",Ve[Ve.Out=1]="Out",Ve[Ve.In=-1]="In",(Fe=je||(je={}))[Fe.FINAL=0]="FINAL",Fe[Fe.ANY=1]="ANY";const Le={};function He(e,t){return{id:e,x:0,y:0,d:0,name:null,color:null,bgcolor:null,points:0,ts:t}}function Qe(e,t){let n=0;for(let l of Le[e].players){if(We.decodePlayer(l).id===t)return n;n++}return-1}function Ye(e,t){const n=Qe(e,t);return We.decodePlayer(Le[e].players[n])}function qe(e,t,n){const l=Qe(e,t);-1===l?Le[e].players.push(We.encodePlayer(n)):Le[e].players[l]=We.encodePlayer(n)}function Ze(e,t){return-1!==Qe(e,t)}function Ke(e){return Le[e]?Le[e].players.map(We.decodePlayer):[]}function Je(e){return Le[e].puzzle.tiles.length}function Xe(e){return Le[e].scoreMode||0}function et(e){return tt(e)===Je(e)}function tt(e){let t=0;for(let n of Le[e].puzzle.tiles)-1===We.decodeTile(n).owner&&t++;return t}function nt(e,t,n){const l=Ye(e,t);for(let o of Object.keys(n))l[o]=n[o];qe(e,t,l)}function lt(e,t){for(let n of Object.keys(t))Le[e].puzzle.data[n]=t[n]}function ot(e,t,n){for(let l of Object.keys(n)){const o=We.decodeTile(Le[e].puzzle.tiles[t]);o[l]=n[l],Le[e].puzzle.tiles[t]=We.encodeTile(o)}}const it=(e,t)=>We.decodeTile(Le[e].puzzle.tiles[t]),at=(e,t)=>it(e,t).group,st=(e,t)=>{const n=Le[e].puzzle.info,l={x:(n.table.width-n.width)/2,y:(n.table.height-n.height)/2},o=function(e,t){const n=Le[e].puzzle.info,l=We.coordByTileIdx(n,t),o=l.x*n.tileSize,i=l.y*n.tileSize;return{x:o,y:i}}(e,t);return he.pointAdd(l,o)},rt=(e,t)=>it(e,t).pos,ct=e=>{const t=At(e),n=Tt(e),l=Math.round(t/4),o=Math.round(n/4);return{x:0-l,y:0-o,w:t+2*l,h:n+2*o}},dt=(e,t)=>{const n=ht(e),l=it(e,t);return{x:l.pos.x,y:l.pos.y,w:n,h:n}},ut=(e,t)=>it(e,t).z,gt=(e,t)=>{for(let n of Le[e].puzzle.tiles){const e=We.decodeTile(n);if(e.owner===t)return e.idx}return-1},pt=e=>Le[e].puzzle.info.tileDrawSize,ht=e=>Le[e].puzzle.info.tileSize,mt=e=>Le[e].puzzle.data.maxGroup,yt=e=>Le[e].puzzle.data.maxZ;function ft(e,t){const n=Le[e].puzzle.info,l=We.coordByTileIdx(n,t);return[l.y>0?t-n.tilesX:-1,l.x0?t-1:-1]}const wt=(e,t,n)=>{for(let l of t)ot(e,l,{z:n})},vt=(e,t,n)=>{const l=rt(e,t);ot(e,t,{pos:he.pointAdd(l,n)})},bt=(e,t,n)=>{const l=pt(e),o=ct(e),i=n;for(let a of t){const t=it(e,a);t.pos.x+n.xo.x+o.w&&(i.x=Math.min(o.x+o.w-t.pos.x+l,i.x)),t.pos.y+n.yo.y+o.h&&(i.y=Math.min(o.y+o.h-t.pos.y+l,i.y))}for(let a of t)vt(e,a,i)},xt=(e,t,n)=>{for(let l of t)ot(e,l,{owner:n})};function Ct(e,t){const n=Le[e].puzzle.tiles,l=We.decodeTile(n[t]),o=[];if(l.group)for(let i of n){const e=We.decodeTile(i);e.group===l.group&&o.push(e.idx)}else o.push(l.idx);return o}const kt=(e,t)=>{const n=Ye(e,t);return n?n.points:0},At=e=>Le[e].puzzle.info.table.width,Tt=e=>Le[e].puzzle.info.table.height;var St={__createPlayerObject:He,setGame:function(e,t){Le[e]=t},exists:function(e){return!!Le[e]||!1},playerExists:Ze,getActivePlayers:function(e,t){const n=t-30*I;return Ke(e).filter((e=>e.ts>=n))},getIdlePlayers:function(e,t){const n=t-30*I;return Ke(e).filter((e=>e.ts0))},addPlayer:function(e,t,n){Ze(e,t)?nt(e,t,{ts:n}):qe(e,t,He(t,n))},getFinishedTileCount:tt,getTileCount:Je,getImageUrl:function(e){return Le[e].puzzle.info.imageUrl},setImageUrl:function(e,t){Le[e].puzzle.info.imageUrl=t},get:function(e){return Le[e]},getAllGames:function(){return Object.values(Le).sort(((e,t)=>et(e.id)===et(t.id)?t.puzzle.data.started-e.puzzle.data.started:et(e.id)?1:-1))},getPlayerBgColor:(e,t)=>{const n=Ye(e,t);return n?n.bgcolor:null},getPlayerColor:(e,t)=>{const n=Ye(e,t);return n?n.color:null},getPlayerName:(e,t)=>{const n=Ye(e,t);return n?n.name:null},getPlayerIndexById:Qe,getPlayerIdByIndex:function(e,t){return Le[e].players.length>t?We.decodePlayer(Le[e].players[t]).id:null},changePlayer:nt,setPlayer:qe,setTile:function(e,t,n){Le[e].puzzle.tiles[t]=We.encodeTile(n)},setPuzzleData:function(e,t){Le[e].puzzle.data=t},getTableWidth:At,getTableHeight:Tt,getPuzzle:e=>Le[e].puzzle,getRng:e=>Le[e].rng.obj,getPuzzleWidth:e=>Le[e].puzzle.info.width,getPuzzleHeight:e=>Le[e].puzzle.info.height,getTilesSortedByZIndex:function(e){return Le[e].puzzle.tiles.map(We.decodeTile).sort(((e,t)=>e.z-t.z))},getFirstOwnedTile:(e,t)=>{const n=gt(e,t);return n<0?null:Le[e].puzzle.tiles[n]},getTileDrawOffset:e=>Le[e].puzzle.info.tileDrawOffset,getTileDrawSize:pt,getFinalTilePos:st,getStartTs:e=>Le[e].puzzle.data.started,getFinishTs:e=>Le[e].puzzle.data.finished,handleInput:function(e,t,n,l){const o=Le[e].puzzle,i=function(e,t){return t in Le[e].evtInfos?Le[e].evtInfos[t]:{_last_mouse:null,_last_mouse_down:null}}(e,t),a=[],s=()=>{a.push([Oe,o.data])},r=t=>{a.push([Ue,We.encodeTile(it(e,t))])},c=e=>{for(const t of e)r(t)},d=()=>{a.push([Ne,We.encodePlayer(Ye(e,t))])},u=n[0];if(u===_e){const o=n[1];nt(e,t,{bgcolor:o,ts:l}),d()}else if(u===De){const o=n[1];nt(e,t,{color:o,ts:l}),d()}else if(u===Be){const o=`${n[1]}`.substr(0,16);nt(e,t,{name:o,ts:l}),d()}else if(u===Te){const o={x:n[1],y:n[2]};nt(e,t,{d:1,ts:l}),d(),i._last_mouse_down=o;const a=((e,t)=>{let n=Le[e].puzzle.info,l=Le[e].puzzle.tiles,o=-1,i=-1;for(let a=0;ao)&&(o=e.z,i=a)}return i})(e,o);if(a>=0){let n=yt(e)+1;lt(e,{maxZ:n}),s();const l=Ct(e,a);wt(e,l,yt(e)),xt(e,l,t),c(l)}i._last_mouse=o}else if(u===ze){const o=n[1],a=n[2],s={x:o,y:a};if(null===i._last_mouse_down)nt(e,t,{x:o,y:a,ts:l}),d();else{let n=gt(e,t);if(n>=0){nt(e,t,{x:o,y:a,ts:l}),d();const r=Ct(e,n);let u=he.pointInBounds(s,ct(e))&&he.pointInBounds(i._last_mouse_down,ct(e));for(let t of r){const n=dt(e,t);if(he.pointInBounds(s,n)){u=!0;break}}if(u){const t=o-i._last_mouse_down.x,n=a-i._last_mouse_down.y;bt(e,r,{x:t,y:n}),c(r)}}else nt(e,t,{ts:l}),d();i._last_mouse_down=s}i._last_mouse=s}else if(u===Se){const a={x:n[1],y:n[2]},u=0;i._last_mouse_down=null;let g=gt(e,t);if(g>=0){let n=Ct(e,g);xt(e,n,0),c(n);let i=rt(e,g),a=st(e,g);if(he.pointDistance(a,i){for(let n of t)ot(e,n,{owner:-1,z:1})})(e,n),c(n);let r=kt(e,t);0===Xe(e)?r+=n.length:1===Xe(e)&&(r+=1),nt(e,t,{d:u,ts:l,points:r}),d(),tt(e)===Je(e)&&(lt(e,{finished:l}),s())}else{const n=(e,t,n,l)=>{let o=Le[e].puzzle.info;if(n<0)return!1;if(((e,t,n)=>{const l=at(e,t),o=at(e,n);return l&&l===o})(e,t,n))return!1;const i=rt(e,t),a=he.pointAdd(rt(e,n),{x:l[0]*o.tileSize,y:l[1]*o.tileSize});if(he.pointDistance(i,a){const l=Le[e].puzzle.tiles,o=at(e,t),i=at(e,n);let a;const c=[];o&&c.push(o),i&&c.push(i),o?a=o:i?a=i:(lt(e,{maxGroup:mt(e)+1}),s(),a=mt(e));if(ot(e,t,{group:a}),r(t),ot(e,n,{group:a}),r(n),c.length>0)for(const s of l){const t=We.decodeTile(s);c.includes(t.group)&&(ot(e,t.idx,{group:a}),r(t.idx))}})(e,t,n),o=Ct(e,t);const d=((e,t)=>{let n=0;for(let l of t){let t=ut(e,l);t>n&&(n=t)}return n})(e,o);return wt(e,o,d),c(o),!0}return!1};let o=!1;for(let t of Ct(e,g)){let l=ft(e,t);if(n(e,t,l[0],[0,1])||n(e,t,l[1],[-1,0])||n(e,t,l[2],[0,-1])||n(e,t,l[3],[1,0])){o=!0;break}}if(o&&1===Xe(e)){const n=kt(e,t)+1;nt(e,t,{d:u,ts:l,points:n}),d()}else nt(e,t,{d:u,ts:l}),d()}}else nt(e,t,{d:u,ts:l}),d();i._last_mouse=a}else if(u===Ie){const o=n[1],a=n[2];nt(e,t,{x:o,y:a,ts:l}),d(),i._last_mouse={x:o,y:a}}else if(u===Pe){const o=n[1],a=n[2];nt(e,t,{x:o,y:a,ts:l}),d(),i._last_mouse={x:o,y:a}}else nt(e,t,{ts:l}),d();return function(e,t,n){Le[e].evtInfos[t]=n}(e,t,i),a}},zt=e({name:"new-game-dialog",components:{ResponsiveImage:W},props:{image:{type:Object,required:!0}},emits:{newGame:null,bgclick:null},data:()=>({tiles:1e3,scoreMode:je.ANY}),methods:{onNewGameClick(){this.$emit("newGame",{tiles:this.tilesInt,image:this.image,scoreMode:this.scoreModeInt})}},computed:{canStartNewGame(){return!!(this.tilesInt&&this.image&&this.image.url&&[0,1].includes(this.scoreModeInt))},scoreModeInt(){return parseInt(`${this.scoreMode}`,10)},tilesInt(){return parseInt(`${this.tiles}`,10)}}});const It={class:"area-image"},Pt={class:"has-image"},_t={class:"area-settings"},Dt=n("td",null,[n("label",null,"Pieces")],-1),Bt=n("td",null,[n("label",null,"Scoring: ")],-1),Et=s(" Any (Score when pieces are connected to each other or on final location)"),Ot=n("br",null,null,-1),Ut=s(" Final (Score when pieces are put to their final location)"),Nt={class:"area-buttons"};zt.render=function(e,l,o,s,r,c){const d=i("responsive-image");return a(),t("div",{class:"overlay new-game-dialog",onClick:l[6]||(l[6]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:l[5]||(l[5]=u((()=>{}),["stop"]))},[n("div",It,[n("div",Pt,[n(d,{src:e.image.url,title:e.image.title},null,8,["src","title"])])]),n("div",_t,[n("table",null,[n("tr",null,[Dt,n("td",null,[g(n("input",{type:"text","onUpdate:modelValue":l[1]||(l[1]=t=>e.tiles=t)},null,512),[[p,e.tiles]])])]),n("tr",null,[Bt,n("td",null,[n("label",null,[g(n("input",{type:"radio","onUpdate:modelValue":l[2]||(l[2]=t=>e.scoreMode=t),value:"1"},null,512),[[h,e.scoreMode]]),Et]),Ot,n("label",null,[g(n("input",{type:"radio","onUpdate:modelValue":l[3]||(l[3]=t=>e.scoreMode=t),value:"0"},null,512),[[h,e.scoreMode]]),Ut])])])])]),n("div",Nt,[n("button",{class:"btn",disabled:!e.canStartNewGame,onClick:l[4]||(l[4]=(...t)=>e.onNewGameClick&&e.onNewGameClick(...t))}," 🧩 Generate Puzzle ",8,["disabled"])])])])};var Mt=e({components:{ImageLibrary:V,NewImageDialog:L,EditImageDialog:oe,NewGameDialog:zt},data:()=>({filters:{sort:"date_desc",category:""},images:[],categories:[],image:{id:0,filename:"",file:"",url:"",title:"",categories:[],created:0},dialog:""}),async created(){await this.loadImages()},methods:{async loadImages(){const e=await fetch(`/api/newgame-data${We.asQueryArgs(this.filters)}`),t=await e.json();this.images=t.images,this.categories=t.categories},async filtersChanged(){await this.loadImages()},onImageClicked(e){this.image=e,this.dialog="new-game"},onImageEditClicked(e){this.image=e,this.dialog="edit-image"},async uploadImage(e){const t=new FormData;t.append("file",e.file,e.file.name),t.append("title",e.title),t.append("category",e.category);const n=await fetch("/api/upload",{method:"post",body:t});return await n.json()},async saveImage(e){const t=await fetch("/api/save-image",{method:"post",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({id:e.id,title:e.title,category:e.category})});return await t.json()},async onSaveImageClick(e){await this.saveImage(e),this.dialog="",await this.loadImages()},async postToGalleryClick(e){await this.uploadImage(e),this.dialog="",await this.loadImages()},async setupGameClick(e){const t=await this.uploadImage(e);this.loadImages(),this.image=t,this.dialog="new-game"},async onNewGame(e){const t=await fetch("/newgame",{method:"post",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(e)});if(200===t.status){const e=await t.json();this.$router.push({name:"game",params:{id:e.id}})}}}});const Gt={class:"upload-image-teaser"},$t=n("div",{class:"hint"},"(The image you upload will be added to the public gallery.)",-1),Rt={key:0},Vt=s(" Category: "),jt=n("option",{value:""},"All",-1),Ft=s(" Sort by: "),Wt=n("option",{value:"date_desc"},"Newest first",-1),Lt=n("option",{value:"date_asc"},"Oldest first",-1),Ht=n("option",{value:"alpha_asc"},"A-Z",-1),Qt=n("option",{value:"alpha_desc"},"Z-A",-1);Mt.render=function(e,l,s,u,p,h){const y=i("image-library"),f=i("new-image-dialog"),w=i("edit-image-dialog"),v=i("new-game-dialog");return a(),t("div",null,[n("div",Gt,[n("div",{class:"btn btn-big",onClick:l[1]||(l[1]=t=>e.dialog="new-image")},"Upload your image"),$t]),n("div",null,[e.categories.length>0?(a(),t("label",Rt,[Vt,g(n("select",{"onUpdate:modelValue":l[2]||(l[2]=t=>e.filters.category=t),onChange:l[3]||(l[3]=(...t)=>e.filtersChanged&&e.filtersChanged(...t))},[jt,(a(!0),t(c,null,d(e.categories,((e,n)=>(a(),t("option",{key:n,value:e.slug},r(e.title),9,["value"])))),128))],544),[[m,e.filters.category]])])):o("",!0),n("label",null,[Ft,g(n("select",{"onUpdate:modelValue":l[4]||(l[4]=t=>e.filters.sort=t),onChange:l[5]||(l[5]=(...t)=>e.filtersChanged&&e.filtersChanged(...t))},[Wt,Lt,Ht,Qt],544),[[m,e.filters.sort]])])]),n(y,{images:e.images,onImageClicked:e.onImageClicked,onImageEditClicked:e.onImageEditClicked},null,8,["images","onImageClicked","onImageEditClicked"]),"new-image"===e.dialog?(a(),t(f,{key:0,onBgclick:l[6]||(l[6]=t=>e.dialog=""),onPostToGalleryClick:e.postToGalleryClick,onSetupGameClick:e.setupGameClick},null,8,["onPostToGalleryClick","onSetupGameClick"])):o("",!0),"edit-image"===e.dialog?(a(),t(w,{key:1,onBgclick:l[7]||(l[7]=t=>e.dialog=""),onSaveClick:e.onSaveImageClick,image:e.image},null,8,["onSaveClick","image"])):o("",!0),e.image&&"new-game"===e.dialog?(a(),t(v,{key:2,onBgclick:l[8]||(l[8]=t=>e.dialog=""),onNewGame:e.onNewGame,image:e.image},null,8,["onNewGame","image"])):o("",!0)])};var Yt=e({name:"scores",props:{activePlayers:{type:Array,required:!0},idlePlayers:{type:Array,required:!0}},computed:{actives(){return this.activePlayers.sort(((e,t)=>t.points-e.points)),this.activePlayers},idles(){return this.idlePlayers.sort(((e,t)=>t.points-e.points)),this.idlePlayers}}});const qt={class:"scores"},Zt=n("div",null,"Scores",-1),Kt=n("td",null,"⚑",-1),Jt=n("td",null,"πŸ’€",-1);Yt.render=function(e,l,o,i,s,u){return a(),t("div",qt,[Zt,n("table",null,[(a(!0),t(c,null,d(e.actives,((e,l)=>(a(),t("tr",{key:l,style:{color:e.color}},[Kt,n("td",null,r(e.name),1),n("td",null,r(e.points),1)],4)))),128)),(a(!0),t(c,null,d(e.idles,((e,l)=>(a(),t("tr",{key:l,style:{color:e.color}},[Jt,n("td",null,r(e.name),1),n("td",null,r(e.points),1)],4)))),128))])])};var Xt=e({name:"puzzle-status",props:{finished:{type:Boolean,required:!0},duration:{type:Number,required:!0},piecesDone:{type:Number,required:!0},piecesTotal:{type:Number,required:!0}},computed:{icon(){return this.finished?"🏁":"⏳"},durationStr(){return D(this.duration)}}});const en={class:"timer"};Xt.render=function(e,l,o,i,s,c){return a(),t("div",en,[n("div",null," 🧩 "+r(e.piecesDone)+"/"+r(e.piecesTotal),1),n("div",null,r(e.icon)+" "+r(e.durationStr),1),y(e.$slots,"default")])};var tn=e({name:"settings-overlay",emits:{bgclick:null,"update:modelValue":null},props:{modelValue:Object},created(){this.$watch("modelValue",(e=>{this.$emit("update:modelValue",e)}),{deep:!0})}});const nn=n("td",null,[n("label",null,"Background: ")],-1),ln=n("td",null,[n("label",null,"Color: ")],-1),on=n("td",null,[n("label",null,"Name: ")],-1);tn.render=function(e,l,o,i,s,r){return a(),t("div",{class:"overlay transparent",onClick:l[5]||(l[5]=t=>e.$emit("bgclick"))},[n("table",{class:"overlay-content settings",onClick:l[4]||(l[4]=u((()=>{}),["stop"]))},[n("tr",null,[nn,n("td",null,[g(n("input",{type:"color","onUpdate:modelValue":l[1]||(l[1]=t=>e.modelValue.background=t)},null,512),[[p,e.modelValue.background]])])]),n("tr",null,[ln,n("td",null,[g(n("input",{type:"color","onUpdate:modelValue":l[2]||(l[2]=t=>e.modelValue.color=t)},null,512),[[p,e.modelValue.color]])])]),n("tr",null,[on,n("td",null,[g(n("input",{type:"text",maxLength:"16","onUpdate:modelValue":l[3]||(l[3]=t=>e.modelValue.name=t)},null,512),[[p,e.modelValue.name]])])])])])};var an=e({name:"preview-overlay",props:{img:String},emits:{bgclick:null},computed:{previewStyle(){return{backgroundImage:`url('${this.img}')`}}}});const sn={class:"preview"};an.render=function(e,l,o,i,s,r){return a(),t("div",{class:"overlay",onClick:l[1]||(l[1]=t=>e.$emit("bgclick"))},[n("div",sn,[n("div",{class:"img",style:e.previewStyle},null,4)])])};const rn=$e("Communication.js");let cn,dn=e=>{},un=e=>{};let gn=0;const pn=e=>{gn!==e&&(gn=e,un(e))};function hn(e){if(2===gn)try{cn.send(JSON.stringify(e))}catch(t){rn.info("unable to send message.. maybe because ws is invalid?")}}let mn,yn;var fn={connect:function(e,t,n){return mn=0,yn={},pn(3),new Promise((l=>{cn=new WebSocket(e,n+"|"+t),cn.onopen=e=>{pn(2),hn([ve])},cn.onmessage=e=>{const t=JSON.parse(e.data),o=t[0];if(o===ye){const e=t[1];l(e)}else{if(o!==me)throw`[ 2021-05-09 invalid connect msgType ${o} ]`;{const e=t[1],l=t[2];if(e===n&&yn[l])return void delete yn[l];dn(t)}}},cn.onerror=e=>{throw pn(1),"[ 2021-05-15 onerror ]"},cn.onclose=e=>{4e3===e.code||1001===e.code?pn(4):pn(1)}}))},connectReplay:function(e,t,n){return mn=0,yn={},pn(3),new Promise((l=>{cn=new WebSocket(e,n+"|"+t),cn.onopen=e=>{pn(2),hn([be])},cn.onmessage=e=>{const t=JSON.parse(e.data),n=t[0];if(n!==fe)throw`[ 2021-05-09 invalid connectReplay msgType ${n} ]`;{const e=t[1],n=t[2];l({game:e,log:n})}},cn.onerror=e=>{throw pn(1),"[ 2021-05-15 onerror ]"},cn.onclose=e=>{4e3===e.code||1001===e.code?pn(4):pn(1)}}))},disconnect:function(){cn&&cn.close(4e3),mn=0,yn={}},sendClientEvent:function(e){mn++,yn[mn]=e,hn([we,mn,yn[mn]])},onServerChange:function(e){dn=e},onConnectionStateChange:function(e){un=e},CODE_CUSTOM_DISCONNECT:4e3,CONN_STATE_NOT_CONNECTED:0,CONN_STATE_DISCONNECTED:1,CONN_STATE_CLOSED:4,CONN_STATE_CONNECTED:2,CONN_STATE_CONNECTING:3},wn=e({name:"connection-overlay",emits:{reconnect:null},props:{connectionState:Number},computed:{lostConnection(){return this.connectionState===fn.CONN_STATE_DISCONNECTED},connecting(){return this.connectionState===fn.CONN_STATE_CONNECTING},show(){return!(!this.lostConnection&&!this.connecting)}}});const vn={key:0,class:"overlay connection-lost"},bn={key:0,class:"overlay-content"},xn=n("div",null,"⁉️ LOST CONNECTION ⁉️",-1),Cn={key:1,class:"overlay-content"},kn=n("div",null,"Connecting...",-1);wn.render=function(e,l,i,s,r,c){return e.show?(a(),t("div",vn,[e.lostConnection?(a(),t("div",bn,[xn,n("span",{class:"btn",onClick:l[1]||(l[1]=t=>e.$emit("reconnect"))},"Reconnect")])):o("",!0),e.connecting?(a(),t("div",Cn,[kn])):o("",!0)])):o("",!0)};var An=e({name:"help-overlay",emits:{bgclick:null}});const Tn=n("tr",null,[n("td",null,"⬆️ Move up:"),n("td",null,[n("div",null,[n("kbd",null,"W"),s("/"),n("kbd",null,"↑"),s("/πŸ–±οΈ")])])],-1),Sn=n("tr",null,[n("td",null,"⬇️ Move down:"),n("td",null,[n("div",null,[n("kbd",null,"S"),s("/"),n("kbd",null,"↓"),s("/πŸ–±οΈ")])])],-1),zn=n("tr",null,[n("td",null,"⬅️ Move left:"),n("td",null,[n("div",null,[n("kbd",null,"A"),s("/"),n("kbd",null,"←"),s("/πŸ–±οΈ")])])],-1),In=n("tr",null,[n("td",null,"➑️ Move right:"),n("td",null,[n("div",null,[n("kbd",null,"D"),s("/"),n("kbd",null,"β†’"),s("/πŸ–±οΈ")])])],-1),Pn=n("tr",null,[n("td"),n("td",null,[n("div",null,[s("Move faster by holding "),n("kbd",null,"Shift")])])],-1),_n=n("tr",null,[n("td",null,"πŸ”+ Zoom in:"),n("td",null,[n("div",null,[n("kbd",null,"E"),s("/πŸ–±οΈ-Wheel")])])],-1),Dn=n("tr",null,[n("td",null,"πŸ”- Zoom out:"),n("td",null,[n("div",null,[n("kbd",null,"Q"),s("/πŸ–±οΈ-Wheel")])])],-1),Bn=n("tr",null,[n("td",null,"πŸ–ΌοΈ Toggle preview:"),n("td",null,[n("div",null,[n("kbd",null,"Space")])])],-1),En=n("tr",null,[n("td",null,"πŸ§©βœ”οΈ Toggle fixed pieces:"),n("td",null,[n("div",null,[n("kbd",null,"F")])])],-1),On=n("tr",null,[n("td",null,"πŸ§©β“ Toggle loose pieces:"),n("td",null,[n("div",null,[n("kbd",null,"G")])])],-1);An.render=function(e,l,o,i,s,r){return a(),t("div",{class:"overlay transparent",onClick:l[2]||(l[2]=t=>e.$emit("bgclick"))},[n("table",{class:"overlay-content help",onClick:l[1]||(l[1]=u((()=>{}),["stop"]))},[Tn,Sn,zn,In,Pn,_n,Dn,Bn,En,On])])};var Un=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAW0lEQVQ4je1RywrAIAxLxP//5exixRWlVgZelpOKeTQFfnDypgy3eLIkSLLL8mxGPoHsU2hPAgDHBLvRX6hZZw/fwT0BtlLSONqCbWAmEIqMZOCDDlaDR3N03gOyDCn+y4DWmAAAAABJRU5ErkJggg=="}),Nn=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAARElEQVQ4jWNgGAU0Af+hmBCbgYGBgYERhwHEAEYGBgYGJtIdiApYyLAZBVDsAqoagC1ACQJyY4ERg0GCISh6KA4DigEAou8LC+LnIJoAAAAASUVORK5CYII="}),Mn=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAcUlEQVQ4ja1TQQ7AIAgD///n7jCozA2Hbk00jbG1KIrcARszTugoBs49qioZj7r2kKACptkyAOCJsJuA+GzglwHjvMSSWFVaENWVASxh5eRLiq5fN/ASjI89VcP2K3hHpq1cEXNaMfnrL3TDZP2tDuoOA6MzCCXWr38AAAAASUVORK5CYII="}),Gn=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAU0lEQVQ4jWNgoAH4D8X42HDARKlt5BoAd82AuQAOGLGIYQQUPv0wF5CiCQUge4EsQ5C9QI4BjMguwBYeBAElscCIy1ZivMKIwSDBEBQ9FCckigEAU3QOD7TGvY4AAAAASUVORK5CYII="});function $n(){let e=0,t=0,n=1;const l=(l,o)=>{e+=l/n,t+=o/n},o=e=>{const t=n+.05*n*("in"===e?1:-1);return Math.min(Math.max(t,.1),6)},i=l=>({x:l.x/n-e,y:l.y/n-t}),a=l=>({x:(l.x+e)*n,y:(l.y+t)*n}),s=e=>({w:e.w*n,h:e.h*n});return{move:l,canZoom:e=>n!=o(e),zoom:(e,t)=>((e,t)=>{if(n==e)return!1;const o=1-n/e;return l(-t.x*o,-t.y*o),n=e,!0})(o(e),t),worldToViewport:e=>{const{x:t,y:n}=a(e);return{x:Math.round(t),y:Math.round(n)}},worldToViewportRaw:a,worldDimToViewport:e=>{const{w:t,h:n}=s(e);return{w:Math.round(t),h:Math.round(n)}},worldDimToViewportRaw:s,viewportToWorld:e=>{const{x:t,y:n}=i(e);return{x:Math.round(t),y:Math.round(n)}},viewportToWorldRaw:i}}function Rn(e=0,t=0){const n=document.createElement("canvas");return n.width=e,n.height=t,n}var Vn={createCanvas:Rn,loadImageToBitmap:async function(e){return new Promise((t=>{const n=new Image;n.onload=()=>{createImageBitmap(n).then(t)},n.src=e}))},resizeBitmap:async function(e,t,n){const l=Rn(t,n);return l.getContext("2d").drawImage(e,0,0,e.width,e.height,0,0,t,n),await createImageBitmap(l)},colorize:async function(e,t,n){const l=Rn(e.width,e.height),o=l.getContext("2d");return o.save(),o.drawImage(t,0,0),o.fillStyle=n,o.globalCompositeOperation="source-in",o.fillRect(0,0,t.width,t.height),o.restore(),o.save(),o.globalCompositeOperation="destination-over",o.drawImage(e,0,0),o.restore(),await createImageBitmap(l)}};const jn=$e("Debug.js");let Fn=0,Wn=0;var Ln=e=>{Fn=performance.now(),Wn=e},Hn=e=>{const t=performance.now(),n=t-Fn;n>Wn&&jn.log(e+": "+n),Fn=t};const Qn=$e("PuzzleGraphics.js");function Yn(e,t){const n=We.coordByTileIdx(e,t);return{x:n.x*e.tileSize,y:n.y*e.tileSize,w:e.tileSize,h:e.tileSize}}var qn={loadPuzzleBitmaps:async function(e){const t=await Vn.loadImageToBitmap(e.info.imageUrl),n=await Vn.resizeBitmap(t,e.info.width,e.info.height);return await async function(e,t,n){Qn.log("start createPuzzleTileBitmaps");var l=n.tileSize,o=n.tileMarginWidth,i=n.tileDrawSize,a=l/100,s=[0,0,40,15,37,5,37,5,40,0,38,-5,38,-5,20,-20,50,-20,50,-20,80,-20,62,-5,62,-5,60,0,63,5,63,5,65,15,100,0];const r=new Array(t.length),c={};function d(e){const t=`${e.top}${e.right}${e.left}${e.bottom}`;if(c[t])return c[t];const n=new Path2D,i={x:o,y:o},r=he.pointAdd(i,{x:l,y:0}),d=he.pointAdd(r,{x:0,y:l}),u=he.pointSub(d,{x:l,y:0});if(n.moveTo(i.x,i.y),0!==e.top)for(let l=0;l=0&&e&&this.explode(e),this.px+=this.vx,this.py+=this.vy}draw(e){e.beginPath(),e.arc(this.px,this.py,this.previousRadius,0,2*Math.PI,!1),this.hasExploded||(e.fillStyle=this.color,e.lineWidth=1,e.fill())}explode(e){this.hasExploded=!0;const t=3+Math.floor(3*Math.random());for(let n=0;n{this.resize()}))}setSpeedParams(){let e=0,t=0;for(;e=0;)t+=1,e+=t;Jn=t/2,Xn=t-Jn;const n=1/4*this.canvas.width/(t/2);Zn=-n,Kn=2*n}resize(){this.setSpeedParams()}init(){this.readyBombs=[],this.explodedBombs=[],this.particles=[];for(let e=0;e<1;e++)this.readyBombs.push(new el(this.rng))}update(){100*Math.random()<5&&this.readyBombs.push(new el(this.rng));const e=[];for(;this.explodedBombs.length>0;){const t=this.explodedBombs.shift();if(!t)break;t.update(),t.alive&&e.push(t)}this.explodedBombs=e;const t=[];for(;this.readyBombs.length>0;){const e=this.readyBombs.shift();if(!e)break;e.update(this.particles),e.hasExploded?this.explodedBombs.push(e):t.push(e)}this.readyBombs=t;const n=[];for(;this.particles.length>0;){const e=this.particles.shift();if(!e)break;e.update(),e.alive&&n.push(e)}this.particles=n}render(){this.ctx.beginPath(),this.ctx.fillStyle="rgba(0, 0, 0, 0.1)",this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height);for(let e=0;e{const t=e.color+" "+e.d;if(!h[t]){const n=e.d?a:s;if(e.color){const l=e.d?r:c;h[t]=await Vn.colorize(n,l,e.color)}else h[t]=n}return h[t]},y=function(e,t){return t.width=window.innerWidth,t.height=window.innerHeight,e.appendChild(t),window.addEventListener("resize",(()=>{t.width=window.innerWidth,t.height=window.innerHeight,al=!0})),t}(o,Vn.createCanvas()),f={log:[],logIdx:0,speeds:[.5,1,2,5,10,20,50],speedIdx:1,paused:!1,lastRealTs:0,lastGameTs:0,gameStartTs:0};fn.onConnectionStateChange((e=>{i.setConnectionState(e)}));let w=()=>0;const v=async()=>{if("play"===l){const l=await fn.connect(n,e,t),o=We.decodeGame(l);St.setGame(o.id,o),w=()=>P()}else{if("replay"!==l)throw"[ 2020-12-22 MODE invalid, must be play|replay ]";{const l=await fn.connectReplay(n,e,t),o=We.decodeGame(l.game);St.setGame(o.id,o),f.log=l.log,f.lastRealTs=P(),f.gameStartTs=parseInt(f.log[0][f.log[0].length-2],10),f.lastGameTs=f.gameStartTs,w=()=>f.lastGameTs}}al=!0};await v();const b=St.getTileDrawOffset(e),x=St.getTileDrawSize(e),C=St.getPuzzleWidth(e),k=St.getPuzzleHeight(e),A=St.getTableWidth(e),T=St.getTableHeight(e),S={x:(A-C)/2,y:(T-k)/2},z={w:C,h:k},I={w:x,h:x},_=await qn.loadPuzzleBitmaps(St.getPuzzle(e)),D=new nl(y,St.getRng(e));D.init();const B=y.getContext("2d");y.classList.add("loaded");const E=$n();E.move(-(A-y.width)/2,-(T-y.height)/2);const O=function(e,t,n){let l=[],o=!0,i=!1,a=!1,s=!1,r=!1,c=!1,d=!1,u=!1;const g=(e,t)=>{const l=n.viewportToWorld({x:e,y:t});return[l.x,l.y]},p=e=>g(e.offsetX,e.offsetY),h=()=>g(e.width/2,e.height/2),m=(e,t)=>{o&&("Shift"===t.key?u=e:"ArrowUp"===t.key||"w"===t.key||"W"===t.key?s=e:"ArrowDown"===t.key||"s"===t.key||"S"===t.key?r=e:"ArrowLeft"===t.key||"a"===t.key||"A"===t.key?i=e:"ArrowRight"===t.key||"d"===t.key||"D"===t.key?a=e:"q"===t.key?d=e:"e"===t.key&&(c=e))};e.addEventListener("mousedown",(e=>{0===e.button&&y([Te,...p(e)])})),e.addEventListener("mouseup",(e=>{0===e.button&&y([Se,...p(e)])})),e.addEventListener("mousemove",(e=>{y([ze,...p(e)])})),e.addEventListener("wheel",(e=>{if(n.canZoom(e.deltaY<0?"in":"out")){const t=e.deltaY<0?Ie:Pe;y([t,...p(e)])}})),t.addEventListener("keydown",(e=>m(!0,e))),t.addEventListener("keyup",(e=>m(!1,e))),t.addEventListener("keypress",(e=>{o&&(" "===e.key&&y([Ee]),"F"!==e.key&&"f"!==e.key||(ol=!ol,al=!0),"G"!==e.key&&"g"!==e.key||(il=!il,al=!0))}));const y=e=>{l.push(e)};return{addEvent:y,consumeAll:()=>{if(0===l.length)return[];const e=l.slice();return l=[],e},createKeyEvents:()=>{const e=u?20:10,t=(i?e:0)-(a?e:0),l=(s?e:0)-(r?e:0);0===t&&0===l||y([Ae,t,l]),c&&d||(c?n.canZoom("in")&&y([Ie,...h()]):d&&n.canZoom("out")&&y([Pe,...h()]))},setHotkeys:e=>{o=e}}}(y,window,E),U=St.getImageUrl(e),N=()=>{const t=St.getStartTs(e),n=St.getFinishTs(e),l=w();i.setFinished(!!n),i.setDuration((n||l)-t)};N(),i.setPiecesDone(St.getFinishedTileCount(e)),i.setPiecesTotal(St.getTileCount(e));const M=w();i.setActivePlayers(St.getActivePlayers(e,M)),i.setIdlePlayers(St.getIdlePlayers(e,M));const G=!!St.getFinishTs(e);let $=G;const R=()=>$&&!G,V=()=>St.getPlayerBgColor(e,t)||localStorage.getItem("bg_color")||"#222222",j=()=>{i.setReplaySpeed&&i.setReplaySpeed(f.speeds[f.speedIdx]),i.setReplayPaused&&i.setReplayPaused(f.paused)};if("play"===l?setInterval(N,1e3):"replay"===l&&j(),"play"===l)fn.onServerChange((n=>{n[0],n[1],n[2];const l=n[3];for(const[o,i]of l)switch(o){case Ne:{const n=We.decodePlayer(i);n.id!==t&&(St.setPlayer(e,n.id,n),al=!0)}break;case Ue:{const t=We.decodeTile(i);St.setTile(e,t.idx,t),al=!0}break;case Oe:St.setPuzzleData(e,i),al=!0}$=!!St.getFinishTs(e)}));else if("replay"===l){let t=setInterval((()=>{const n=P();if(f.paused)return void(f.lastRealTs=n);const l=(n-f.lastRealTs)*f.speeds[f.speedIdx],o=f.lastGameTs+l;for(;;){if(f.paused)break;const n=f.logIdx+1;if(n>=f.log.length){clearInterval(t);break}const l=f.log[n],i=f.gameStartTs+l[l.length-1];if(i>o)break;const a=l.slice();if(a[0]===xe){const t=a[1];St.addPlayer(e,t,i),al=!0}else if(a[0]===Ce){const t=St.getPlayerIdByIndex(e,a[1]);if(!t)throw"[ 2021-05-17 player not found (update player) ]";St.addPlayer(e,t,i),al=!0}else if(a[0]===ke){const t=St.getPlayerIdByIndex(e,a[1]);if(!t)throw"[ 2021-05-17 player not found (handle input) ]";const n=a[2];St.handleInput(e,t,n,i),al=!0}f.logIdx=n}f.lastRealTs=n,f.lastGameTs=o,N()}),50)}let F=null;return(e=>{const t=e.fps||60,n=e.slow||1,l=e.update,o=e.render,i=window.requestAnimationFrame,a=1/t,s=n*a;let r,c=0,d=window.performance.now();const u=()=>{for(r=window.performance.now(),c+=Math.min(1,(r-d)/1e3);c>s;)c-=s,l(a);o(c/n),d=r,i(u)};i(u)})({update:()=>{O.createKeyEvents();for(const n of O.consumeAll())if("play"===l){const l=n[0];if(l===Ae){const e=n[1],t=n[2];al=!0,E.move(e,t)}else if(l===ze){if(F&&!St.getFirstOwnedTile(e,t)){const e={x:n[1],y:n[2]},t=E.worldToViewport(e),l=Math.round(t.x-F.x),o=Math.round(t.y-F.y);al=!0,E.move(l,o),F=t}}else if(l===Te){const e={x:n[1],y:n[2]};F=E.worldToViewport(e)}else if(l===Se)F=null;else if(l===Ie){const e={x:n[1],y:n[2]};al=!0,E.zoom("in",E.worldToViewport(e))}else if(l===Pe){const e={x:n[1],y:n[2]};al=!0,E.zoom("out",E.worldToViewport(e))}else l===Ee&&i.togglePreview();const o=w();St.handleInput(e,t,n,o).length>0&&(al=!0),fn.sendClientEvent(n)}else if("replay"===l){const e=n[0];if(e===Ae){const e=n[1],t=n[2];al=!0,E.move(e,t)}else if(e===ze){if(F){const e={x:n[1],y:n[2]},t=E.worldToViewport(e),l=Math.round(t.x-F.x),o=Math.round(t.y-F.y);al=!0,E.move(l,o),F=t}}else if(e===Te){const e={x:n[1],y:n[2]};F=E.worldToViewport(e)}else if(e===Se)F=null;else if(e===Ie){const e={x:n[1],y:n[2]};al=!0,E.zoom("in",E.worldToViewport(e))}else if(e===Pe){const e={x:n[1],y:n[2]};al=!0,E.zoom("out",E.worldToViewport(e))}else e===Ee&&i.togglePreview()}$=!!St.getFinishTs(e),R()&&(D.update(),al=!0)},render:async()=>{if(!al)return;const n=w();let o,a,s;window.DEBUG&&Ln(0),B.fillStyle=V(),B.fillRect(0,0,y.width,y.height),window.DEBUG&&Hn("clear done"),o=E.worldToViewportRaw(S),a=E.worldDimToViewportRaw(z),B.fillStyle="rgba(255, 255, 255, .3)",B.fillRect(o.x,o.y,a.w,a.h),window.DEBUG&&Hn("board done");const r=St.getTilesSortedByZIndex(e);window.DEBUG&&Hn("get tiles done"),a=E.worldDimToViewportRaw(I);for(const e of r)(-1===e.owner?ol:il)&&(s=_[e.idx],o=E.worldToViewportRaw({x:b+e.pos.x,y:b+e.pos.y}),B.drawImage(s,0,0,s.width,s.height,o.x,o.y,a.w,a.h));window.DEBUG&&Hn("tiles done");const c=[];for(const i of St.getActivePlayers(e,n))s=await m(i),o=E.worldToViewport(i),B.drawImage(s,o.x-u,o.y-p),d=i,("replay"===l||d.id!==t)&&c.push([`${i.name} (${i.points})`,o.x,o.y+g]);var d;B.fillStyle="white",B.textAlign="center";for(const[e,t,l]of c)B.fillText(e,t,l);window.DEBUG&&Hn("players done"),i.setActivePlayers(St.getActivePlayers(e,n)),i.setIdlePlayers(St.getIdlePlayers(e,n)),i.setPiecesDone(St.getFinishedTileCount(e)),window.DEBUG&&Hn("HUD done"),R()&&D.render(),al=!1}}),{setHotkeys:e=>{O.setHotkeys(e)},onBgChange:e=>{localStorage.setItem("bg_color",e),O.addEvent([_e,e])},onColorChange:e=>{localStorage.setItem("player_color",e),O.addEvent([De,e])},onNameChange:e=>{localStorage.setItem("player_name",e),O.addEvent([Be,e])},replayOnSpeedUp:()=>{f.speedIdx+1{f.speedIdx>=1&&(f.speedIdx--,j())},replayOnPauseToggle:()=>{f.paused=!f.paused,j()},previewImageUrl:U,player:{background:V(),color:St.getPlayerColor(e,t)||localStorage.getItem("player_color")||"#ffffff",name:St.getPlayerName(e,t)||localStorage.getItem("player_name")||"anon"},disconnect:fn.disconnect,connect:v}}var rl=e({name:"game",components:{PuzzleStatus:Xt,Scores:Yt,SettingsOverlay:tn,PreviewOverlay:an,ConnectionOverlay:wn,HelpOverlay:An},data:()=>({activePlayers:[],idlePlayers:[],finished:!1,duration:0,piecesDone:0,piecesTotal:0,overlay:"",connectionState:0,g:{player:{background:"",color:"",name:""},previewImageUrl:"",setHotkeys:e=>{},onBgChange:e=>{},onColorChange:e=>{},onNameChange:e=>{},disconnect:()=>{},connect:()=>{}}}),async mounted(){this.$route.params.id&&(this.$watch((()=>this.g.player.background),(e=>{this.g.onBgChange(e)})),this.$watch((()=>this.g.player.color),(e=>{this.g.onColorChange(e)})),this.$watch((()=>this.g.player.name),(e=>{this.g.onNameChange(e)})),this.g=await sl(`${this.$route.params.id}`,this.$clientId,this.$config.WS_ADDRESS,"play",this.$el,{setActivePlayers:e=>{this.activePlayers=e},setIdlePlayers:e=>{this.idlePlayers=e},setFinished:e=>{this.finished=e},setDuration:e=>{this.duration=e},setPiecesDone:e=>{this.piecesDone=e},setPiecesTotal:e=>{this.piecesTotal=e},setConnectionState:e=>{this.connectionState=e},togglePreview:()=>{this.toggle("preview",!1)}}))},unmounted(){this.g.disconnect()},methods:{reconnect(){this.g.connect()},toggle(e,t){""===this.overlay?(this.overlay=e,t&&this.g.setHotkeys(!1)):(this.overlay="",t&&this.g.setHotkeys(!0))}}});const cl={id:"game"},dl={class:"menu"},ul={class:"tabs"},gl=s("🧩 Puzzles");rl.render=function(e,o,s,r,c,d){const u=i("settings-overlay"),p=i("preview-overlay"),h=i("help-overlay"),m=i("connection-overlay"),y=i("puzzle-status"),w=i("router-link"),v=i("scores");return a(),t("div",cl,[g(n(u,{onBgclick:o[1]||(o[1]=t=>e.toggle("settings",!0)),modelValue:e.g.player,"onUpdate:modelValue":o[2]||(o[2]=t=>e.g.player=t)},null,8,["modelValue"]),[[f,"settings"===e.overlay]]),g(n(p,{onBgclick:o[3]||(o[3]=t=>e.toggle("preview",!1)),img:e.g.previewImageUrl},null,8,["img"]),[[f,"preview"===e.overlay]]),g(n(h,{onBgclick:o[4]||(o[4]=t=>e.toggle("help",!0))},null,512),[[f,"help"===e.overlay]]),n(m,{connectionState:e.connectionState,onReconnect:e.reconnect},null,8,["connectionState","onReconnect"]),n(y,{finished:e.finished,duration:e.duration,piecesDone:e.piecesDone,piecesTotal:e.piecesTotal},null,8,["finished","duration","piecesDone","piecesTotal"]),n("div",dl,[n("div",ul,[n(w,{class:"opener",to:{name:"index"},target:"_blank"},{default:l((()=>[gl])),_:1}),n("div",{class:"opener",onClick:o[5]||(o[5]=t=>e.toggle("preview",!1))},"πŸ–ΌοΈ Preview"),n("div",{class:"opener",onClick:o[6]||(o[6]=t=>e.toggle("settings",!0))},"πŸ› οΈ Settings"),n("div",{class:"opener",onClick:o[7]||(o[7]=t=>e.toggle("help",!0))},"ℹ️ Help")])]),n(v,{activePlayers:e.activePlayers,idlePlayers:e.idlePlayers},null,8,["activePlayers","idlePlayers"])])};var pl=e({name:"replay",components:{PuzzleStatus:Xt,Scores:Yt,SettingsOverlay:tn,PreviewOverlay:an,HelpOverlay:An},data:()=>({activePlayers:[],idlePlayers:[],finished:!1,duration:0,piecesDone:0,piecesTotal:0,overlay:"",connectionState:0,g:{player:{background:"",color:"",name:""},previewImageUrl:"",setHotkeys:e=>{},onBgChange:e=>{},onColorChange:e=>{},onNameChange:e=>{},replayOnSpeedUp:()=>{},replayOnSpeedDown:()=>{},replayOnPauseToggle:()=>{},disconnect:()=>{}},replay:{speed:1,paused:!1}}),async mounted(){this.$route.params.id&&(this.$watch((()=>this.g.player.background),(e=>{this.g.onBgChange(e)})),this.$watch((()=>this.g.player.color),(e=>{this.g.onColorChange(e)})),this.$watch((()=>this.g.player.name),(e=>{this.g.onNameChange(e)})),this.g=await sl(`${this.$route.params.id}`,this.$clientId,this.$config.WS_ADDRESS,"replay",this.$el,{setActivePlayers:e=>{this.activePlayers=e},setIdlePlayers:e=>{this.idlePlayers=e},setFinished:e=>{this.finished=e},setDuration:e=>{this.duration=e},setPiecesDone:e=>{this.piecesDone=e},setPiecesTotal:e=>{this.piecesTotal=e},togglePreview:()=>{this.toggle("preview",!1)},setConnectionState:e=>{this.connectionState=e},setReplaySpeed:e=>{this.replay.speed=e},setReplayPaused:e=>{this.replay.paused=e}}))},unmounted(){this.g.disconnect()},methods:{toggle(e,t){""===this.overlay?(this.overlay=e,t&&this.g.setHotkeys(!1)):(this.overlay="",t&&this.g.setHotkeys(!0))}},computed:{replayText(){return"Replay-Speed: "+this.replay.speed+"x"+(this.replay.paused?" Paused":"")}}});const hl={id:"replay"},ml={class:"menu"},yl={class:"tabs"},fl=s("🧩 Puzzles");pl.render=function(e,o,s,c,d,u){const p=i("settings-overlay"),h=i("preview-overlay"),m=i("help-overlay"),y=i("puzzle-status"),w=i("router-link"),v=i("scores");return a(),t("div",hl,[g(n(p,{onBgclick:o[1]||(o[1]=t=>e.toggle("settings",!0)),modelValue:e.g.player,"onUpdate:modelValue":o[2]||(o[2]=t=>e.g.player=t)},null,8,["modelValue"]),[[f,"settings"===e.overlay]]),g(n(h,{onBgclick:o[3]||(o[3]=t=>e.toggle("preview",!1)),img:e.g.previewImageUrl},null,8,["img"]),[[f,"preview"===e.overlay]]),g(n(m,{onBgclick:o[4]||(o[4]=t=>e.toggle("help",!0))},null,512),[[f,"help"===e.overlay]]),n(y,{finished:e.finished,duration:e.duration,piecesDone:e.piecesDone,piecesTotal:e.piecesTotal},{default:l((()=>[n("div",null,[n("div",null,r(e.replayText),1),n("button",{class:"btn",onClick:o[5]||(o[5]=t=>e.g.replayOnSpeedUp())},"⏫"),n("button",{class:"btn",onClick:o[6]||(o[6]=t=>e.g.replayOnSpeedDown())},"⏬"),n("button",{class:"btn",onClick:o[7]||(o[7]=t=>e.g.replayOnPauseToggle())},"⏸️")])])),_:1},8,["finished","duration","piecesDone","piecesTotal"]),n("div",ml,[n("div",yl,[n(w,{class:"opener",to:{name:"index"},target:"_blank"},{default:l((()=>[fl])),_:1}),n("div",{class:"opener",onClick:o[8]||(o[8]=t=>e.toggle("preview",!1))},"πŸ–ΌοΈ Preview"),n("div",{class:"opener",onClick:o[9]||(o[9]=t=>e.toggle("settings",!0))},"πŸ› οΈ Settings"),n("div",{class:"opener",onClick:o[10]||(o[10]=t=>e.toggle("help",!0))},"ℹ️ Help")])]),n(v,{activePlayers:e.activePlayers,idlePlayers:e.idlePlayers},null,8,["activePlayers","idlePlayers"])])},(async()=>{const e=await fetch("/api/conf"),t=await e.json();const n=w({history:v(),routes:[{name:"index",path:"/",component:M},{name:"new-game",path:"/new-game",component:Mt},{name:"game",path:"/g/:id",component:rl},{name:"replay",path:"/replay/:id",component:pl}]});n.beforeEach(((e,t)=>{t.name&&document.documentElement.classList.remove(`view-${String(t.name)}`),document.documentElement.classList.add(`view-${String(e.name)}`)}));const l=b(x);l.config.globalProperties.$config=t,l.config.globalProperties.$clientId=function(){let e=localStorage.getItem("ID");return e||(e=We.uniqId(),localStorage.setItem("ID",e)),e}(),l.use(n),l.mount("#app")})(); diff --git a/build/public/assets/index.1c0291a2.js b/build/public/assets/index.1c0291a2.js deleted file mode 100644 index 1f35521..0000000 --- a/build/public/assets/index.1c0291a2.js +++ /dev/null @@ -1 +0,0 @@ -import{d as e,c as t,a as n,w as o,b as l,r as i,o as a,e as s,t as r,F as d,f as c,g as u,v as p,h as g,i as h,j as y,k as m,l as f,m as w,n as v,p as b}from"./vendor.8616a479.js";var x=e({name:"app",computed:{showNav(){return!["game","replay"].includes(String(this.$route.name))}}});const C={id:"app"},A={key:0,class:"nav"},k=s("Index"),T=s("New game");x.render=function(e,s,r,d,c,u){const p=i("router-link"),g=i("router-view");return a(),t("div",C,[e.showNav?(a(),t("ul",A,[n("li",null,[n(p,{class:"btn",to:{name:"index"}},{default:o((()=>[k])),_:1})]),n("li",null,[n(p,{class:"btn",to:{name:"new-game"}},{default:o((()=>[T])),_:1})])])):l("",!0),n(g)])};const z=864e5,S=e=>{const t=Math.floor(e/z);e%=z;const n=Math.floor(e/36e5);e%=36e5;const o=Math.floor(e/6e4);e%=6e4;return`${t}d ${n}h ${o}m ${Math.floor(e/1e3)}s`};var I=1e3,P=()=>{const e=new Date;return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds())},_=(e,t)=>S(t-e),D=S,B=e({name:"game-teaser",props:{game:{type:Object,required:!0}},computed:{style(){return{"background-image":`url("${this.game.imageUrl.replace("uploads/","uploads/r/")+"-375x210.webp"}")`}}},methods:{time(e,t){const n=t?"🏁":"⏳",o=e,l=t||P();return`${n} ${_(o,l)}`}}});const O={class:"game-info-text"},E=n("br",null,null,-1),M=n("br",null,null,-1),N=n("br",null,null,-1);B.render=function(e,d,c,u,p,g){const h=i("router-link");return a(),t("div",{class:"game-teaser",style:e.style},[n(h,{class:"game-info",to:{name:"game",params:{id:e.game.id}}},{default:o((()=>[n("span",O,[s(" 🧩 "+r(e.game.tilesFinished)+"/"+r(e.game.tilesTotal),1),E,s(" πŸ‘₯ "+r(e.game.players),1),M,s(" "+r(e.time(e.game.started,e.game.finished)),1),N])])),_:1},8,["to"]),l("",!0)],4)};var U=e({components:{GameTeaser:B},data:()=>({gamesRunning:[],gamesFinished:[]}),async created(){const e=await fetch("/api/index-data"),t=await e.json();this.gamesRunning=t.gamesRunning,this.gamesFinished=t.gamesFinished}});const G=n("h1",null,"Running games",-1),R=n("h1",null,"Finished games",-1);U.render=function(e,o,l,s,r,u){const p=i("game-teaser");return a(),t("div",null,[G,(a(!0),t(d,null,c(e.gamesRunning,((e,o)=>(a(),t("div",{class:"game-teaser-wrap",key:o},[n(p,{game:e},null,8,["game"])])))),128)),R,(a(!0),t(d,null,c(e.gamesFinished,((e,o)=>(a(),t("div",{class:"game-teaser-wrap",key:o},[n(p,{game:e},null,8,["game"])])))),128))])};var $=e({name:"image-teaser",props:{image:{type:Object,required:!0}},computed:{style(){return{backgroundImage:`url("${this.image.url.replace("uploads/","uploads/r/")+"-150x100.webp"}")`}}},methods:{onClick(){this.$emit("click")}}});$.render=function(e,n,o,l,i,s){return a(),t("div",{class:"imageteaser",style:e.style,onClick:n[1]||(n[1]=(...t)=>e.onClick&&e.onClick(...t))},null,4)};var V=e({name:"image-library",components:{ImageTeaser:$},props:{images:{type:Array,required:!0}},emits:{imageClicked:null},methods:{imageClicked(e){this.$emit("imageClicked",e)}}});V.render=function(e,n,o,l,s,r){const u=i("image-teaser");return a(),t("div",null,[(a(!0),t(d,null,c(e.images,((n,o)=>(a(),t(u,{image:n,onClick:t=>e.imageClicked(n),key:o},null,8,["image","onClick"])))),128))])};var j=e({name:"upload",props:{accept:String,label:String},methods:{async upload(e){const t=e.target;if(!t.files)return;const n=t.files[0];if(!n)return;const o=new FormData;o.append("file",n,n.name);const l=await fetch("/upload",{method:"post",body:o}),i=await l.json();this.$emit("uploaded",i)}}});const F={class:"btn"};j.render=function(e,o,l,i,s,d){return a(),t("label",null,[n("input",{type:"file",style:{display:"none"},onChange:o[1]||(o[1]=(...t)=>e.upload&&e.upload(...t)),accept:e.accept},null,40,["accept"]),n("span",F,r(e.label||"Upload File"),1)])};const W={name:"responsive-image",props:{src:String,title:{type:String,default:""},height:{type:String,default:"100%"},width:{type:String,default:"100%"}},computed:{style(){return{display:"inline-block",verticalAlign:"text-bottom",backgroundImage:`url('${this.src}')`,backgroundRepeat:"no-repeat",backgroundSize:"contain",backgroundPosition:"center",width:this.width,height:this.height}}}};W.render=function(e,n,o,l,i,s){return a(),t("div",{style:s.style,title:o.title},null,12,["title"])};var L=e({name:"new-image-dialog",components:{Upload:j,ResponsiveImage:W},emits:{bgclick:null,setupGameClick:null,postToGalleryClick:null},data:()=>({previewUrl:"",file:null,title:"",category:""}),computed:{canPostToGallery(){return!(!this.previewUrl||!this.file)},canSetupGameClick(){return!(!this.previewUrl||!this.file)}},methods:{preview(e){const t=e.target;if(!t.files)return;const n=t.files[0];if(!n)return;const o=new FileReader;o.readAsDataURL(n),o.onload=e=>{this.previewUrl=e.target.result,this.file=n}},postToGallery(){this.$emit("postToGalleryClick",{file:this.file,title:this.title,category:this.category})},setupGameClick(){this.$emit("setupGameClick",{file:this.file,title:this.title,category:this.category})}}});const H={key:0,class:"has-image"},Q={key:1},Y={class:"upload"},q={class:"btn"},Z={class:"area-settings"},K=n("td",null,[n("label",null,"Title")],-1),J=n("tr",null,[n("td",{colspan:"2"},[n("div",{class:"hint"},"Feel free to leave a credit to the artist/photographer in the title :)")])],-1),X=n("td",null,[n("label",null,"Category")],-1),ee={class:"area-buttons"},te=s("🧩 Post to gallery "),ne=n("br",null,null,-1),oe=s(" + set up game");function le(e,t){const n=e.x-t.x,o=e.y-t.y;return Math.sqrt(n*n+o*o)}function ie(e){return{x:e.x+e.w/2,y:e.y+e.h/2}}L.render=function(e,o,l,s,d,c){const h=i("responsive-image");return a(),t("div",{class:"overlay new-image-dialog",onClick:o[8]||(o[8]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:o[7]||(o[7]=g((()=>{}),["stop"]))},[n("div",{class:["area-image",{"has-image":!!e.previewUrl,"no-image":!e.previewUrl}]},[e.previewUrl?(a(),t("div",H,[n("span",{class:"remove btn",onClick:o[1]||(o[1]=t=>e.previewUrl="")},"X"),n(h,{src:e.previewUrl},null,8,["src"])])):(a(),t("div",Q,[n("label",Y,[n("input",{type:"file",style:{display:"none"},onChange:o[2]||(o[2]=(...t)=>e.preview&&e.preview(...t)),accept:"image/*"},null,32),n("span",q,r(e.label||"Upload File"),1)])]))],2),n("div",Z,[n("table",null,[n("tr",null,[K,n("td",null,[u(n("input",{type:"text","onUpdate:modelValue":o[3]||(o[3]=t=>e.title=t),placeholder:"Flower by @artist"},null,512),[[p,e.title]])])]),J,n("tr",null,[X,n("td",null,[u(n("input",{type:"text","onUpdate:modelValue":o[4]||(o[4]=t=>e.category=t),placeholder:"Plants"},null,512),[[p,e.category]])])])])]),n("div",ee,[n("button",{class:"btn",disabled:!e.canPostToGallery,onClick:o[5]||(o[5]=(...t)=>e.postToGallery&&e.postToGallery(...t))},"πŸ–ΌοΈ Post to gallery",8,["disabled"]),n("button",{class:"btn",disabled:!e.canSetupGameClick,onClick:o[6]||(o[6]=(...t)=>e.setupGameClick&&e.setupGameClick(...t))},[te,ne,oe],8,["disabled"])])])])};var ae={pointSub:function(e,t){return{x:e.x-t.x,y:e.y-t.y}},pointAdd:function(e,t){return{x:e.x+t.x,y:e.y+t.y}},pointDistance:le,pointInBounds:function(e,t){return e.x>=t.x&&e.x<=t.x+t.w&&e.y>=t.y&&e.y<=t.y+t.h},rectCenter:ie,rectMoved:function(e,t,n){return{x:e.x+t,y:e.y+n,w:e.w,h:e.h}},rectCenterDistance:function(e,t){return le(ie(e),ie(t))},rectsOverlap:function(e,t){return!(t.x>e.x+e.w||e.x>t.x+t.w||t.y>e.y+e.h||e.y>t.y+t.h)}};var se=1,re=4,de=5,ce=2,ue=3,pe=6,ge=2,he=4,ye=3,me=9,fe=1,we=2,ve=3,be=4,xe=5,Ce=6,Ae=7,ke=8,Te=10,ze=1,Se=2,Ie=3;class Pe{constructor(e){this.rand_high=e||3735929054,this.rand_low=1231121986^e}random(e,t){return this.rand_high=(this.rand_high<<16)+(this.rand_high>>16)+this.rand_low&4294967295,this.rand_low=this.rand_low+this.rand_high&4294967295,e+(this.rand_high>>>0)/4294967295*(t-e+1)|0}choice(e){return e[this.random(0,e.length-1)]}shuffle(e){const t=e.slice();for(let n=0;n<=t.length-2;n++){const e=this.random(n,t.length-1),o=t[n];t[n]=t[e],t[e]=o}return t}static serialize(e){return{rand_high:e.rand_high,rand_low:e.rand_low}}static unserialize(e){const t=new Pe(0);return t.rand_high=e.rand_high,t.rand_low=e.rand_low,t}}const _e=(e,t)=>{const n=`${e}`;return n.length>=t.length?n:t.substr(0,t.length-n.length)+n},De=(...e)=>{const t=t=>(...n)=>{const o=new Date,l=_e(o.getHours(),"00"),i=_e(o.getMinutes(),"00"),a=_e(o.getSeconds(),"00");console[t](`${l}:${i}:${a}`,...e,...n)};return{log:t("log"),error:t("error"),info:t("info")}};var Be,Oe,Ee,Me,Ne={hash:e=>{let t=0;for(let n=0;n{let t=e.toLowerCase();return t=t.replace(/[^a-z0-9]+/g,"-"),t=t.replace(/^-|-$/,""),t},uniqId:()=>Date.now().toString(36)+Math.random().toString(36).substring(2),encodeShape:function(e){return e.top+1<<0|e.right+1<<2|e.bottom+1<<4|e.left+1<<6},decodeShape:function(e){return{top:(e>>0&3)-1,right:(e>>2&3)-1,bottom:(e>>4&3)-1,left:(e>>6&3)-1}},encodeTile:function(e){return[e.idx,e.pos.x,e.pos.y,e.z,e.owner,e.group]},decodeTile:function(e){return{idx:e[0],pos:{x:e[1],y:e[2]},z:e[3],owner:e[4],group:e[5]}},encodePlayer:function(e){return[e.id,e.x,e.y,e.d,e.name,e.color,e.bgcolor,e.points,e.ts]},decodePlayer:function(e){return{id:e[0],x:e[1],y:e[2],d:e[3],name:e[4],color:e[5],bgcolor:e[6],points:e[7],ts:e[8]}},encodeGame:function(e){return Array.isArray(e)?e:[e.id,e.rng.type,Pe.serialize(e.rng.obj),e.puzzle,e.players,e.evtInfos,e.scoreMode]},decodeGame:function(e){return Array.isArray(e)?{id:e[0],rng:{type:e[1],obj:Pe.unserialize(e[2])},puzzle:e[3],players:e[4],evtInfos:e[5],scoreMode:e[6]}:e},coordByTileIdx:function(e,t){const n=e.width/e.tileSize;return{x:t%n,y:Math.floor(t/n)}},asQueryArgs:function(e){const t=[];for(let n in e){const o=[n,e[n]].map(encodeURIComponent);t.push(o.join("="))}return 0===t.length?"":`?${t.join("&")}`}};(Oe=Be||(Be={}))[Oe.Flat=0]="Flat",Oe[Oe.Out=1]="Out",Oe[Oe.In=-1]="In",(Me=Ee||(Ee={}))[Me.FINAL=0]="FINAL",Me[Me.ANY=1]="ANY";const Ue={};function Ge(e,t){return{id:e,x:0,y:0,d:0,name:null,color:null,bgcolor:null,points:0,ts:t}}function Re(e,t){let n=0;for(let o of Ue[e].players){if(Ne.decodePlayer(o).id===t)return n;n++}return-1}function $e(e,t){const n=Re(e,t);return Ne.decodePlayer(Ue[e].players[n])}function Ve(e,t,n){const o=Re(e,t);-1===o?Ue[e].players.push(Ne.encodePlayer(n)):Ue[e].players[o]=Ne.encodePlayer(n)}function je(e,t){return-1!==Re(e,t)}function Fe(e){return Ue[e]?Ue[e].players.map(Ne.decodePlayer):[]}function We(e){return Ue[e].puzzle.tiles.length}function Le(e){return Ue[e].scoreMode||0}function He(e){return Qe(e)===We(e)}function Qe(e){let t=0;for(let n of Ue[e].puzzle.tiles)-1===Ne.decodeTile(n).owner&&t++;return t}function Ye(e,t,n){const o=$e(e,t);for(let l of Object.keys(n))o[l]=n[l];Ve(e,t,o)}function qe(e,t){for(let n of Object.keys(t))Ue[e].puzzle.data[n]=t[n]}function Ze(e,t,n){for(let o of Object.keys(n)){const l=Ne.decodeTile(Ue[e].puzzle.tiles[t]);l[o]=n[o],Ue[e].puzzle.tiles[t]=Ne.encodeTile(l)}}const Ke=(e,t)=>Ne.decodeTile(Ue[e].puzzle.tiles[t]),Je=(e,t)=>Ke(e,t).group,Xe=(e,t)=>{const n=Ue[e].puzzle.info,o={x:(n.table.width-n.width)/2,y:(n.table.height-n.height)/2},l=function(e,t){const n=Ue[e].puzzle.info,o=Ne.coordByTileIdx(n,t),l=o.x*n.tileSize,i=o.y*n.tileSize;return{x:l,y:i}}(e,t);return ae.pointAdd(o,l)},et=(e,t)=>Ke(e,t).pos,tt=e=>{const t=mt(e),n=ft(e),o=Math.round(t/4),l=Math.round(n/4);return{x:0-o,y:0-l,w:t+2*o,h:n+2*l}},nt=(e,t)=>{const n=at(e),o=Ke(e,t);return{x:o.pos.x,y:o.pos.y,w:n,h:n}},ot=(e,t)=>Ke(e,t).z,lt=(e,t)=>{for(let n of Ue[e].puzzle.tiles){const e=Ne.decodeTile(n);if(e.owner===t)return e.idx}return-1},it=e=>Ue[e].puzzle.info.tileDrawSize,at=e=>Ue[e].puzzle.info.tileSize,st=e=>Ue[e].puzzle.data.maxGroup,rt=e=>Ue[e].puzzle.data.maxZ;function dt(e,t){const n=Ue[e].puzzle.info,o=Ne.coordByTileIdx(n,t);return[o.y>0?t-n.tilesX:-1,o.x0?t-1:-1]}const ct=(e,t,n)=>{for(let o of t)Ze(e,o,{z:n})},ut=(e,t,n)=>{const o=et(e,t);Ze(e,t,{pos:ae.pointAdd(o,n)})},pt=(e,t,n)=>{const o=it(e),l=tt(e),i=n;for(let a of t){const t=Ke(e,a);t.pos.x+n.xl.x+l.w&&(i.x=Math.min(l.x+l.w-t.pos.x+o,i.x)),t.pos.y+n.yl.y+l.h&&(i.y=Math.min(l.y+l.h-t.pos.y+o,i.y))}for(let a of t)ut(e,a,i)},gt=(e,t,n)=>{for(let o of t)Ze(e,o,{owner:n})};function ht(e,t){const n=Ue[e].puzzle.tiles,o=Ne.decodeTile(n[t]),l=[];if(o.group)for(let i of n){const e=Ne.decodeTile(i);e.group===o.group&&l.push(e.idx)}else l.push(o.idx);return l}const yt=(e,t)=>{const n=$e(e,t);return n?n.points:0},mt=e=>Ue[e].puzzle.info.table.width,ft=e=>Ue[e].puzzle.info.table.height;var wt={__createPlayerObject:Ge,setGame:function(e,t){Ue[e]=t},exists:function(e){return!!Ue[e]||!1},playerExists:je,getActivePlayers:function(e,t){const n=t-30*I;return Fe(e).filter((e=>e.ts>=n))},getIdlePlayers:function(e,t){const n=t-30*I;return Fe(e).filter((e=>e.ts0))},addPlayer:function(e,t,n){je(e,t)?Ye(e,t,{ts:n}):Ve(e,t,Ge(t,n))},getFinishedTileCount:Qe,getTileCount:We,getImageUrl:function(e){return Ue[e].puzzle.info.imageUrl},setImageUrl:function(e,t){Ue[e].puzzle.info.imageUrl=t},get:function(e){return Ue[e]},getAllGames:function(){return Object.values(Ue).sort(((e,t)=>He(e.id)===He(t.id)?t.puzzle.data.started-e.puzzle.data.started:He(e.id)?1:-1))},getPlayerBgColor:(e,t)=>{const n=$e(e,t);return n?n.bgcolor:null},getPlayerColor:(e,t)=>{const n=$e(e,t);return n?n.color:null},getPlayerName:(e,t)=>{const n=$e(e,t);return n?n.name:null},getPlayerIndexById:Re,getPlayerIdByIndex:function(e,t){return Ue[e].players.length>t?Ne.decodePlayer(Ue[e].players[t]).id:null},changePlayer:Ye,setPlayer:Ve,setTile:function(e,t,n){Ue[e].puzzle.tiles[t]=Ne.encodeTile(n)},setPuzzleData:function(e,t){Ue[e].puzzle.data=t},getTableWidth:mt,getTableHeight:ft,getPuzzle:e=>Ue[e].puzzle,getRng:e=>Ue[e].rng.obj,getPuzzleWidth:e=>Ue[e].puzzle.info.width,getPuzzleHeight:e=>Ue[e].puzzle.info.height,getTilesSortedByZIndex:function(e){return Ue[e].puzzle.tiles.map(Ne.decodeTile).sort(((e,t)=>e.z-t.z))},getFirstOwnedTile:(e,t)=>{const n=lt(e,t);return n<0?null:Ue[e].puzzle.tiles[n]},getTileDrawOffset:e=>Ue[e].puzzle.info.tileDrawOffset,getTileDrawSize:it,getFinalTilePos:Xe,getStartTs:e=>Ue[e].puzzle.data.started,getFinishTs:e=>Ue[e].puzzle.data.finished,handleInput:function(e,t,n,o){const l=Ue[e].puzzle,i=function(e,t){return t in Ue[e].evtInfos?Ue[e].evtInfos[t]:{_last_mouse:null,_last_mouse_down:null}}(e,t),a=[],s=()=>{a.push([ze,l.data])},r=t=>{a.push([Se,Ne.encodeTile(Ke(e,t))])},d=e=>{for(const t of e)r(t)},c=()=>{a.push([Ie,Ne.encodePlayer($e(e,t))])},u=n[0];if(u===Ce){const l=n[1];Ye(e,t,{bgcolor:l,ts:o}),c()}else if(u===Ae){const l=n[1];Ye(e,t,{color:l,ts:o}),c()}else if(u===ke){const l=`${n[1]}`.substr(0,16);Ye(e,t,{name:l,ts:o}),c()}else if(u===fe){const l={x:n[1],y:n[2]};Ye(e,t,{d:1,ts:o}),c(),i._last_mouse_down=l;const a=((e,t)=>{let n=Ue[e].puzzle.info,o=Ue[e].puzzle.tiles,l=-1,i=-1;for(let a=0;al)&&(l=e.z,i=a)}return i})(e,l);if(a>=0){let n=rt(e)+1;qe(e,{maxZ:n}),s();const o=ht(e,a);ct(e,o,rt(e)),gt(e,o,t),d(o)}i._last_mouse=l}else if(u===ve){const l=n[1],a=n[2],s={x:l,y:a};if(null===i._last_mouse_down)Ye(e,t,{x:l,y:a,ts:o}),c();else{let n=lt(e,t);if(n>=0){Ye(e,t,{x:l,y:a,ts:o}),c();const r=ht(e,n);let u=ae.pointInBounds(s,tt(e))&&ae.pointInBounds(i._last_mouse_down,tt(e));for(let t of r){const n=nt(e,t);if(ae.pointInBounds(s,n)){u=!0;break}}if(u){const t=l-i._last_mouse_down.x,n=a-i._last_mouse_down.y;pt(e,r,{x:t,y:n}),d(r)}}else Ye(e,t,{ts:o}),c();i._last_mouse_down=s}i._last_mouse=s}else if(u===we){const a={x:n[1],y:n[2]},u=0;i._last_mouse_down=null;let p=lt(e,t);if(p>=0){let n=ht(e,p);gt(e,n,0),d(n);let i=et(e,p),a=Xe(e,p);if(ae.pointDistance(a,i){for(let n of t)Ze(e,n,{owner:-1,z:1})})(e,n),d(n);let r=yt(e,t);0===Le(e)?r+=n.length:1===Le(e)&&(r+=1),Ye(e,t,{d:u,ts:o,points:r}),c(),Qe(e)===We(e)&&(qe(e,{finished:o}),s())}else{const n=(e,t,n,o)=>{let l=Ue[e].puzzle.info;if(n<0)return!1;if(((e,t,n)=>{const o=Je(e,t),l=Je(e,n);return o&&o===l})(e,t,n))return!1;const i=et(e,t),a=ae.pointAdd(et(e,n),{x:o[0]*l.tileSize,y:o[1]*l.tileSize});if(ae.pointDistance(i,a){const o=Ue[e].puzzle.tiles,l=Je(e,t),i=Je(e,n);let a;const d=[];l&&d.push(l),i&&d.push(i),l?a=l:i?a=i:(qe(e,{maxGroup:st(e)+1}),s(),a=st(e));if(Ze(e,t,{group:a}),r(t),Ze(e,n,{group:a}),r(n),d.length>0)for(const s of o){const t=Ne.decodeTile(s);d.includes(t.group)&&(Ze(e,t.idx,{group:a}),r(t.idx))}})(e,t,n),l=ht(e,t);const c=((e,t)=>{let n=0;for(let o of t){let t=ot(e,o);t>n&&(n=t)}return n})(e,l);return ct(e,l,c),d(l),!0}return!1};let l=!1;for(let t of ht(e,p)){let o=dt(e,t);if(n(e,t,o[0],[0,1])||n(e,t,o[1],[-1,0])||n(e,t,o[2],[0,-1])||n(e,t,o[3],[1,0])){l=!0;break}}if(l&&1===Le(e)){const n=yt(e,t)+1;Ye(e,t,{d:u,ts:o,points:n}),c()}else Ye(e,t,{d:u,ts:o}),c()}}else Ye(e,t,{d:u,ts:o}),c();i._last_mouse=a}else if(u===be){const l=n[1],a=n[2];Ye(e,t,{x:l,y:a,ts:o}),c(),i._last_mouse={x:l,y:a}}else if(u===xe){const l=n[1],a=n[2];Ye(e,t,{x:l,y:a,ts:o}),c(),i._last_mouse={x:l,y:a}}else Ye(e,t,{ts:o}),c();return function(e,t,n){Ue[e].evtInfos[t]=n}(e,t,i),a}},vt=e({name:"new-game-dialog",components:{ResponsiveImage:W},props:{image:{type:Object,required:!0}},emits:{newGame:null,bgclick:null},data:()=>({tiles:1e3,scoreMode:Ee.ANY}),methods:{onNewGameClick(){this.$emit("newGame",{tiles:this.tilesInt,image:this.image,scoreMode:this.scoreModeInt})}},computed:{canStartNewGame(){return!!(this.tilesInt&&this.image&&this.image.url&&[0,1].includes(this.scoreModeInt))},scoreModeInt(){return parseInt(`${this.scoreMode}`,10)},tilesInt(){return parseInt(`${this.tiles}`,10)}}});const bt={class:"area-image"},xt={class:"has-image"},Ct={class:"area-settings"},At=n("td",null,[n("label",null,"Pieces")],-1),kt=n("td",null,[n("label",null,"Scoring: ")],-1),Tt=s(" Any (Score when pieces are connected to each other or on final location)"),zt=n("br",null,null,-1),St=s(" Final (Score when pieces are put to their final location)"),It={class:"area-buttons"};vt.render=function(e,o,l,s,r,d){const c=i("responsive-image");return a(),t("div",{class:"overlay new-game-dialog",onClick:o[6]||(o[6]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:o[5]||(o[5]=g((()=>{}),["stop"]))},[n("div",bt,[n("div",xt,[n(c,{src:e.image.url,title:e.image.title},null,8,["src","title"])])]),n("div",Ct,[n("table",null,[n("tr",null,[At,n("td",null,[u(n("input",{type:"text","onUpdate:modelValue":o[1]||(o[1]=t=>e.tiles=t)},null,512),[[p,e.tiles]])])]),n("tr",null,[kt,n("td",null,[n("label",null,[u(n("input",{type:"radio","onUpdate:modelValue":o[2]||(o[2]=t=>e.scoreMode=t),value:"1"},null,512),[[h,e.scoreMode]]),Tt]),zt,n("label",null,[u(n("input",{type:"radio","onUpdate:modelValue":o[3]||(o[3]=t=>e.scoreMode=t),value:"0"},null,512),[[h,e.scoreMode]]),St])])])])]),n("div",It,[n("button",{class:"btn",disabled:!e.canStartNewGame,onClick:o[4]||(o[4]=(...t)=>e.onNewGameClick&&e.onNewGameClick(...t))}," 🧩 Generate Puzzle ",8,["disabled"])])])])};var Pt=e({components:{ImageLibrary:V,NewImageDialog:L,NewGameDialog:vt},data:()=>({filters:{sort:"date_desc",category:""},images:[],categories:[],image:{id:0,filename:"",file:"",url:"",title:"",categories:[],created:0},dialog:""}),async created(){await this.loadImages()},methods:{async loadImages(){const e=await fetch(`/api/newgame-data${Ne.asQueryArgs(this.filters)}`),t=await e.json();this.images=t.images,this.categories=t.categories},async filtersChanged(){await this.loadImages()},imageClicked(e){this.image=e,this.dialog="new-game"},async uploadImage(e){const t=new FormData;t.append("file",e.file,e.file.name),t.append("title",e.title),t.append("category",e.category);const n=await fetch("/upload",{method:"post",body:t});return await n.json()},async postToGalleryClick(e){await this.uploadImage(e),this.dialog="",await this.loadImages()},async setupGameClick(e){const t=await this.uploadImage(e);this.loadImages(),this.image=t,this.dialog="new-game"},async onNewGame(e){const t=await fetch("/newgame",{method:"post",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(e)});if(200===t.status){const e=await t.json();this.$router.push({name:"game",params:{id:e.id}})}}}});const _t={class:"upload-image-teaser"},Dt=n("div",{class:"hint"},"(The image you upload will be added to the public gallery.)",-1),Bt={key:0},Ot=s(" Category: "),Et=n("option",{value:""},"All",-1),Mt=s(" Sort by: "),Nt=n("option",{value:"date_desc"},"Newest first",-1),Ut=n("option",{value:"date_asc"},"Oldest first",-1),Gt=n("option",{value:"alpha_asc"},"A-Z",-1),Rt=n("option",{value:"alpha_desc"},"Z-A",-1);Pt.render=function(e,o,s,p,g,h){const m=i("image-library"),f=i("new-image-dialog"),w=i("new-game-dialog");return a(),t("div",null,[n("div",_t,[n("div",{class:"btn btn-big",onClick:o[1]||(o[1]=t=>e.dialog="new-image")},"Upload your image"),Dt]),n("div",null,[e.categories.length>0?(a(),t("label",Bt,[Ot,u(n("select",{"onUpdate:modelValue":o[2]||(o[2]=t=>e.filters.category=t),onChange:o[3]||(o[3]=(...t)=>e.filtersChanged&&e.filtersChanged(...t))},[Et,(a(!0),t(d,null,c(e.categories,((e,n)=>(a(),t("option",{key:n,value:e.slug},r(e.title),9,["value"])))),128))],544),[[y,e.filters.category]])])):l("",!0),n("label",null,[Mt,u(n("select",{"onUpdate:modelValue":o[4]||(o[4]=t=>e.filters.sort=t),onChange:o[5]||(o[5]=(...t)=>e.filtersChanged&&e.filtersChanged(...t))},[Nt,Ut,Gt,Rt],544),[[y,e.filters.sort]])])]),n(m,{images:e.images,onImageClicked:e.imageClicked},null,8,["images","onImageClicked"]),"new-image"===e.dialog?(a(),t(f,{key:0,onBgclick:o[6]||(o[6]=t=>e.dialog=""),onPostToGalleryClick:e.postToGalleryClick,onSetupGameClick:e.setupGameClick},null,8,["onPostToGalleryClick","onSetupGameClick"])):l("",!0),e.image&&"new-game"===e.dialog?(a(),t(w,{key:1,onBgclick:o[7]||(o[7]=t=>e.dialog=""),onNewGame:e.onNewGame,image:e.image},null,8,["onNewGame","image"])):l("",!0)])};var $t=e({name:"scores",props:{activePlayers:{type:Array,required:!0},idlePlayers:{type:Array,required:!0}},computed:{actives(){return this.activePlayers.sort(((e,t)=>t.points-e.points)),this.activePlayers},idles(){return this.idlePlayers.sort(((e,t)=>t.points-e.points)),this.idlePlayers}}});const Vt={class:"scores"},jt=n("div",null,"Scores",-1),Ft=n("td",null,"⚑",-1),Wt=n("td",null,"πŸ’€",-1);$t.render=function(e,o,l,i,s,u){return a(),t("div",Vt,[jt,n("table",null,[(a(!0),t(d,null,c(e.actives,((e,o)=>(a(),t("tr",{key:o,style:{color:e.color}},[Ft,n("td",null,r(e.name),1),n("td",null,r(e.points),1)],4)))),128)),(a(!0),t(d,null,c(e.idles,((e,o)=>(a(),t("tr",{key:o,style:{color:e.color}},[Wt,n("td",null,r(e.name),1),n("td",null,r(e.points),1)],4)))),128))])])};var Lt=e({name:"puzzle-status",props:{finished:{type:Boolean,required:!0},duration:{type:Number,required:!0},piecesDone:{type:Number,required:!0},piecesTotal:{type:Number,required:!0}},computed:{icon(){return this.finished?"🏁":"⏳"},durationStr(){return D(this.duration)}}});const Ht={class:"timer"};Lt.render=function(e,o,l,i,s,d){return a(),t("div",Ht,[n("div",null," 🧩 "+r(e.piecesDone)+"/"+r(e.piecesTotal),1),n("div",null,r(e.icon)+" "+r(e.durationStr),1),m(e.$slots,"default")])};var Qt=e({name:"settings-overlay",emits:{bgclick:null,"update:modelValue":null},props:{modelValue:Object},created(){this.$watch("modelValue",(e=>{this.$emit("update:modelValue",e)}),{deep:!0})}});const Yt=n("td",null,[n("label",null,"Background: ")],-1),qt=n("td",null,[n("label",null,"Color: ")],-1),Zt=n("td",null,[n("label",null,"Name: ")],-1);Qt.render=function(e,o,l,i,s,r){return a(),t("div",{class:"overlay transparent",onClick:o[5]||(o[5]=t=>e.$emit("bgclick"))},[n("table",{class:"overlay-content settings",onClick:o[4]||(o[4]=g((()=>{}),["stop"]))},[n("tr",null,[Yt,n("td",null,[u(n("input",{type:"color","onUpdate:modelValue":o[1]||(o[1]=t=>e.modelValue.background=t)},null,512),[[p,e.modelValue.background]])])]),n("tr",null,[qt,n("td",null,[u(n("input",{type:"color","onUpdate:modelValue":o[2]||(o[2]=t=>e.modelValue.color=t)},null,512),[[p,e.modelValue.color]])])]),n("tr",null,[Zt,n("td",null,[u(n("input",{type:"text",maxLength:"16","onUpdate:modelValue":o[3]||(o[3]=t=>e.modelValue.name=t)},null,512),[[p,e.modelValue.name]])])])])])};var Kt=e({name:"preview-overlay",props:{img:String},emits:{bgclick:null},computed:{previewStyle(){return{backgroundImage:`url('${this.img}')`}}}});const Jt={class:"preview"};Kt.render=function(e,o,l,i,s,r){return a(),t("div",{class:"overlay",onClick:o[1]||(o[1]=t=>e.$emit("bgclick"))},[n("div",Jt,[n("div",{class:"img",style:e.previewStyle},null,4)])])};const Xt=De("Communication.js");let en,tn=e=>{},nn=e=>{};let on=0;const ln=e=>{on!==e&&(on=e,nn(e))};function an(e){if(2===on)try{en.send(JSON.stringify(e))}catch(t){Xt.info("unable to send message.. maybe because ws is invalid?")}}let sn,rn;var dn={connect:function(e,t,n){return sn=0,rn={},ln(3),new Promise((o=>{en=new WebSocket(e,n+"|"+t),en.onopen=e=>{ln(2),an([ue])},en.onmessage=e=>{const t=JSON.parse(e.data),l=t[0];if(l===re){const e=t[1];o(e)}else{if(l!==se)throw`[ 2021-05-09 invalid connect msgType ${l} ]`;{const e=t[1],o=t[2];if(e===n&&rn[o])return void delete rn[o];tn(t)}}},en.onerror=e=>{throw ln(1),"[ 2021-05-15 onerror ]"},en.onclose=e=>{4e3===e.code||1001===e.code?ln(4):ln(1)}}))},connectReplay:function(e,t,n){return sn=0,rn={},ln(3),new Promise((o=>{en=new WebSocket(e,n+"|"+t),en.onopen=e=>{ln(2),an([pe])},en.onmessage=e=>{const t=JSON.parse(e.data),n=t[0];if(n!==de)throw`[ 2021-05-09 invalid connectReplay msgType ${n} ]`;{const e=t[1],n=t[2];o({game:e,log:n})}},en.onerror=e=>{throw ln(1),"[ 2021-05-15 onerror ]"},en.onclose=e=>{4e3===e.code||1001===e.code?ln(4):ln(1)}}))},disconnect:function(){en&&en.close(4e3),sn=0,rn={}},sendClientEvent:function(e){sn++,rn[sn]=e,an([ce,sn,rn[sn]])},onServerChange:function(e){tn=e},onConnectionStateChange:function(e){nn=e},CODE_CUSTOM_DISCONNECT:4e3,CONN_STATE_NOT_CONNECTED:0,CONN_STATE_DISCONNECTED:1,CONN_STATE_CLOSED:4,CONN_STATE_CONNECTED:2,CONN_STATE_CONNECTING:3},cn=e({name:"connection-overlay",emits:{reconnect:null},props:{connectionState:Number},computed:{lostConnection(){return this.connectionState===dn.CONN_STATE_DISCONNECTED},connecting(){return this.connectionState===dn.CONN_STATE_CONNECTING},show(){return!(!this.lostConnection&&!this.connecting)}}});const un={key:0,class:"overlay connection-lost"},pn={key:0,class:"overlay-content"},gn=n("div",null,"⁉️ LOST CONNECTION ⁉️",-1),hn={key:1,class:"overlay-content"},yn=n("div",null,"Connecting...",-1);cn.render=function(e,o,i,s,r,d){return e.show?(a(),t("div",un,[e.lostConnection?(a(),t("div",pn,[gn,n("span",{class:"btn",onClick:o[1]||(o[1]=t=>e.$emit("reconnect"))},"Reconnect")])):l("",!0),e.connecting?(a(),t("div",hn,[yn])):l("",!0)])):l("",!0)};var mn=e({name:"help-overlay",emits:{bgclick:null}});const fn=n("tr",null,[n("td",null,"⬆️ Move up:"),n("td",null,[n("div",null,[n("kbd",null,"W"),s("/"),n("kbd",null,"↑"),s("/πŸ–±οΈ")])])],-1),wn=n("tr",null,[n("td",null,"⬇️ Move down:"),n("td",null,[n("div",null,[n("kbd",null,"S"),s("/"),n("kbd",null,"↓"),s("/πŸ–±οΈ")])])],-1),vn=n("tr",null,[n("td",null,"⬅️ Move left:"),n("td",null,[n("div",null,[n("kbd",null,"A"),s("/"),n("kbd",null,"←"),s("/πŸ–±οΈ")])])],-1),bn=n("tr",null,[n("td",null,"➑️ Move right:"),n("td",null,[n("div",null,[n("kbd",null,"D"),s("/"),n("kbd",null,"β†’"),s("/πŸ–±οΈ")])])],-1),xn=n("tr",null,[n("td"),n("td",null,[n("div",null,[s("Move faster by holding "),n("kbd",null,"Shift")])])],-1),Cn=n("tr",null,[n("td",null,"πŸ”+ Zoom in:"),n("td",null,[n("div",null,[n("kbd",null,"E"),s("/πŸ–±οΈ-Wheel")])])],-1),An=n("tr",null,[n("td",null,"πŸ”- Zoom out:"),n("td",null,[n("div",null,[n("kbd",null,"Q"),s("/πŸ–±οΈ-Wheel")])])],-1),kn=n("tr",null,[n("td",null,"πŸ–ΌοΈ Toggle preview:"),n("td",null,[n("div",null,[n("kbd",null,"Space")])])],-1),Tn=n("tr",null,[n("td",null,"πŸ§©βœ”οΈ Toggle fixed pieces:"),n("td",null,[n("div",null,[n("kbd",null,"F")])])],-1),zn=n("tr",null,[n("td",null,"πŸ§©β“ Toggle loose pieces:"),n("td",null,[n("div",null,[n("kbd",null,"G")])])],-1);mn.render=function(e,o,l,i,s,r){return a(),t("div",{class:"overlay transparent",onClick:o[2]||(o[2]=t=>e.$emit("bgclick"))},[n("table",{class:"overlay-content help",onClick:o[1]||(o[1]=g((()=>{}),["stop"]))},[fn,wn,vn,bn,xn,Cn,An,kn,Tn,zn])])};var Sn=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAW0lEQVQ4je1RywrAIAxLxP//5exixRWlVgZelpOKeTQFfnDypgy3eLIkSLLL8mxGPoHsU2hPAgDHBLvRX6hZZw/fwT0BtlLSONqCbWAmEIqMZOCDDlaDR3N03gOyDCn+y4DWmAAAAABJRU5ErkJggg=="}),In=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAARElEQVQ4jWNgGAU0Af+hmBCbgYGBgYERhwHEAEYGBgYGJtIdiApYyLAZBVDsAqoagC1ACQJyY4ERg0GCISh6KA4DigEAou8LC+LnIJoAAAAASUVORK5CYII="}),Pn=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAcUlEQVQ4ja1TQQ7AIAgD///n7jCozA2Hbk00jbG1KIrcARszTugoBs49qioZj7r2kKACptkyAOCJsJuA+GzglwHjvMSSWFVaENWVASxh5eRLiq5fN/ASjI89VcP2K3hHpq1cEXNaMfnrL3TDZP2tDuoOA6MzCCXWr38AAAAASUVORK5CYII="}),_n=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAU0lEQVQ4jWNgoAH4D8X42HDARKlt5BoAd82AuQAOGLGIYQQUPv0wF5CiCQUge4EsQ5C9QI4BjMguwBYeBAElscCIy1ZivMKIwSDBEBQ9FCckigEAU3QOD7TGvY4AAAAASUVORK5CYII="});function Dn(){let e=0,t=0,n=1;const o=(o,l)=>{e+=o/n,t+=l/n},l=e=>{const t=n+.05*n*("in"===e?1:-1);return Math.min(Math.max(t,.1),6)},i=o=>({x:o.x/n-e,y:o.y/n-t}),a=o=>({x:(o.x+e)*n,y:(o.y+t)*n}),s=e=>({w:e.w*n,h:e.h*n});return{move:o,canZoom:e=>n!=l(e),zoom:(e,t)=>((e,t)=>{if(n==e)return!1;const l=1-n/e;return o(-t.x*l,-t.y*l),n=e,!0})(l(e),t),worldToViewport:e=>{const{x:t,y:n}=a(e);return{x:Math.round(t),y:Math.round(n)}},worldToViewportRaw:a,worldDimToViewport:e=>{const{w:t,h:n}=s(e);return{w:Math.round(t),h:Math.round(n)}},worldDimToViewportRaw:s,viewportToWorld:e=>{const{x:t,y:n}=i(e);return{x:Math.round(t),y:Math.round(n)}},viewportToWorldRaw:i}}function Bn(e=0,t=0){const n=document.createElement("canvas");return n.width=e,n.height=t,n}var On={createCanvas:Bn,loadImageToBitmap:async function(e){return new Promise((t=>{const n=new Image;n.onload=()=>{createImageBitmap(n).then(t)},n.src=e}))},resizeBitmap:async function(e,t,n){const o=Bn(t,n);return o.getContext("2d").drawImage(e,0,0,e.width,e.height,0,0,t,n),await createImageBitmap(o)},colorize:async function(e,t,n){const o=Bn(e.width,e.height),l=o.getContext("2d");return l.save(),l.drawImage(t,0,0),l.fillStyle=n,l.globalCompositeOperation="source-in",l.fillRect(0,0,t.width,t.height),l.restore(),l.save(),l.globalCompositeOperation="destination-over",l.drawImage(e,0,0),l.restore(),await createImageBitmap(o)}};const En=De("Debug.js");let Mn=0,Nn=0;var Un=e=>{Mn=performance.now(),Nn=e},Gn=e=>{const t=performance.now(),n=t-Mn;n>Nn&&En.log(e+": "+n),Mn=t};const Rn=De("PuzzleGraphics.js");function $n(e,t){const n=Ne.coordByTileIdx(e,t);return{x:n.x*e.tileSize,y:n.y*e.tileSize,w:e.tileSize,h:e.tileSize}}var Vn={loadPuzzleBitmaps:async function(e){const t=await On.loadImageToBitmap(e.info.imageUrl),n=await On.resizeBitmap(t,e.info.width,e.info.height);return await async function(e,t,n){Rn.log("start createPuzzleTileBitmaps");var o=n.tileSize,l=n.tileMarginWidth,i=n.tileDrawSize,a=o/100,s=[0,0,40,15,37,5,37,5,40,0,38,-5,38,-5,20,-20,50,-20,50,-20,80,-20,62,-5,62,-5,60,0,63,5,63,5,65,15,100,0];const r=new Array(t.length),d={};function c(e){const t=`${e.top}${e.right}${e.left}${e.bottom}`;if(d[t])return d[t];const n=new Path2D,i={x:l,y:l},r=ae.pointAdd(i,{x:o,y:0}),c=ae.pointAdd(r,{x:0,y:o}),u=ae.pointSub(c,{x:o,y:0});if(n.moveTo(i.x,i.y),0!==e.top)for(let o=0;o=0&&e&&this.explode(e),this.px+=this.vx,this.py+=this.vy}draw(e){e.beginPath(),e.arc(this.px,this.py,this.previousRadius,0,2*Math.PI,!1),this.hasExploded||(e.fillStyle=this.color,e.lineWidth=1,e.fill())}explode(e){this.hasExploded=!0;const t=3+Math.floor(3*Math.random());for(let n=0;n{this.resize()}))}setSpeedParams(){let e=0,t=0;for(;e=0;)t+=1,e+=t;Wn=t/2,Ln=t-Wn;const n=1/4*this.canvas.width/(t/2);jn=-n,Fn=2*n}resize(){this.setSpeedParams()}init(){this.readyBombs=[],this.explodedBombs=[],this.particles=[];for(let e=0;e<1;e++)this.readyBombs.push(new Hn(this.rng))}update(){100*Math.random()<5&&this.readyBombs.push(new Hn(this.rng));const e=[];for(;this.explodedBombs.length>0;){const t=this.explodedBombs.shift();if(!t)break;t.update(),t.alive&&e.push(t)}this.explodedBombs=e;const t=[];for(;this.readyBombs.length>0;){const e=this.readyBombs.shift();if(!e)break;e.update(this.particles),e.hasExploded?this.explodedBombs.push(e):t.push(e)}this.readyBombs=t;const n=[];for(;this.particles.length>0;){const e=this.particles.shift();if(!e)break;e.update(),e.alive&&n.push(e)}this.particles=n}render(){this.ctx.beginPath(),this.ctx.fillStyle="rgba(0, 0, 0, 0.1)",this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height);for(let e=0;e{const t=e.color+" "+e.d;if(!h[t]){const n=e.d?a:s;if(e.color){const o=e.d?r:d;h[t]=await On.colorize(n,o,e.color)}else h[t]=n}return h[t]},m=function(e,t){return t.width=window.innerWidth,t.height=window.innerHeight,e.appendChild(t),window.addEventListener("resize",(()=>{t.width=window.innerWidth,t.height=window.innerHeight,Jn=!0})),t}(l,On.createCanvas()),f={log:[],logIdx:0,speeds:[.5,1,2,5,10,20,50],speedIdx:1,paused:!1,lastRealTs:0,lastGameTs:0,gameStartTs:0};dn.onConnectionStateChange((e=>{i.setConnectionState(e)}));let w=()=>0;const v=async()=>{if("play"===o){const o=await dn.connect(n,e,t),l=Ne.decodeGame(o);wt.setGame(l.id,l),w=()=>P()}else{if("replay"!==o)throw"[ 2020-12-22 MODE invalid, must be play|replay ]";{const o=await dn.connectReplay(n,e,t),l=Ne.decodeGame(o.game);wt.setGame(l.id,l),f.log=o.log,f.lastRealTs=P(),f.gameStartTs=parseInt(f.log[0][f.log[0].length-2],10),f.lastGameTs=f.gameStartTs,w=()=>f.lastGameTs}}Jn=!0};await v();const b=wt.getTileDrawOffset(e),x=wt.getTileDrawSize(e),C=wt.getPuzzleWidth(e),A=wt.getPuzzleHeight(e),k=wt.getTableWidth(e),T=wt.getTableHeight(e),z={x:(k-C)/2,y:(T-A)/2},S={w:C,h:A},I={w:x,h:x},_=await Vn.loadPuzzleBitmaps(wt.getPuzzle(e)),D=new Yn(m,wt.getRng(e));D.init();const B=m.getContext("2d");m.classList.add("loaded");const O=Dn();O.move(-(k-m.width)/2,-(T-m.height)/2);const E=function(e,t,n){let o=[],l=!0,i=!1,a=!1,s=!1,r=!1,d=!1,c=!1,u=!1;const p=(e,t)=>{const o=n.viewportToWorld({x:e,y:t});return[o.x,o.y]},g=e=>p(e.offsetX,e.offsetY),h=()=>p(e.width/2,e.height/2),y=(e,t)=>{l&&("Shift"===t.key?u=e:"ArrowUp"===t.key||"w"===t.key||"W"===t.key?s=e:"ArrowDown"===t.key||"s"===t.key||"S"===t.key?r=e:"ArrowLeft"===t.key||"a"===t.key||"A"===t.key?i=e:"ArrowRight"===t.key||"d"===t.key||"D"===t.key?a=e:"q"===t.key?c=e:"e"===t.key&&(d=e))};e.addEventListener("mousedown",(e=>{0===e.button&&m([fe,...g(e)])})),e.addEventListener("mouseup",(e=>{0===e.button&&m([we,...g(e)])})),e.addEventListener("mousemove",(e=>{m([ve,...g(e)])})),e.addEventListener("wheel",(e=>{if(n.canZoom(e.deltaY<0?"in":"out")){const t=e.deltaY<0?be:xe;m([t,...g(e)])}})),t.addEventListener("keydown",(e=>y(!0,e))),t.addEventListener("keyup",(e=>y(!1,e))),t.addEventListener("keypress",(e=>{l&&(" "===e.key&&m([Te]),"F"!==e.key&&"f"!==e.key||(Zn=!Zn,Jn=!0),"G"!==e.key&&"g"!==e.key||(Kn=!Kn,Jn=!0))}));const m=e=>{o.push(e)};return{addEvent:m,consumeAll:()=>{if(0===o.length)return[];const e=o.slice();return o=[],e},createKeyEvents:()=>{const e=u?20:10,t=(i?e:0)-(a?e:0),o=(s?e:0)-(r?e:0);0===t&&0===o||m([me,t,o]),d&&c||(d?n.canZoom("in")&&m([be,...h()]):c&&n.canZoom("out")&&m([xe,...h()]))},setHotkeys:e=>{l=e}}}(m,window,O),M=wt.getImageUrl(e),N=()=>{const t=wt.getStartTs(e),n=wt.getFinishTs(e),o=w();i.setFinished(!!n),i.setDuration((n||o)-t)};N(),i.setPiecesDone(wt.getFinishedTileCount(e)),i.setPiecesTotal(wt.getTileCount(e));const U=w();i.setActivePlayers(wt.getActivePlayers(e,U)),i.setIdlePlayers(wt.getIdlePlayers(e,U));const G=!!wt.getFinishTs(e);let R=G;const $=()=>R&&!G,V=()=>wt.getPlayerBgColor(e,t)||localStorage.getItem("bg_color")||"#222222",j=()=>{i.setReplaySpeed&&i.setReplaySpeed(f.speeds[f.speedIdx]),i.setReplayPaused&&i.setReplayPaused(f.paused)};if("play"===o?setInterval(N,1e3):"replay"===o&&j(),"play"===o)dn.onServerChange((n=>{n[0],n[1],n[2];const o=n[3];for(const[l,i]of o)switch(l){case Ie:{const n=Ne.decodePlayer(i);n.id!==t&&(wt.setPlayer(e,n.id,n),Jn=!0)}break;case Se:{const t=Ne.decodeTile(i);wt.setTile(e,t.idx,t),Jn=!0}break;case ze:wt.setPuzzleData(e,i),Jn=!0}R=!!wt.getFinishTs(e)}));else if("replay"===o){let t=setInterval((()=>{const n=P();if(f.paused)return void(f.lastRealTs=n);const o=(n-f.lastRealTs)*f.speeds[f.speedIdx],l=f.lastGameTs+o;for(;;){if(f.paused)break;const n=f.logIdx+1;if(n>=f.log.length){clearInterval(t);break}const o=f.log[n],i=f.gameStartTs+o[o.length-1];if(i>l)break;const a=o.slice();if(a[0]===ge){const t=a[1];wt.addPlayer(e,t,i),Jn=!0}else if(a[0]===he){const t=wt.getPlayerIdByIndex(e,a[1]);if(!t)throw"[ 2021-05-17 player not found (update player) ]";wt.addPlayer(e,t,i),Jn=!0}else if(a[0]===ye){const t=wt.getPlayerIdByIndex(e,a[1]);if(!t)throw"[ 2021-05-17 player not found (handle input) ]";const n=a[2];wt.handleInput(e,t,n,i),Jn=!0}f.logIdx=n}f.lastRealTs=n,f.lastGameTs=l,N()}),50)}let F=null;return(e=>{const t=e.fps||60,n=e.slow||1,o=e.update,l=e.render,i=window.requestAnimationFrame,a=1/t,s=n*a;let r,d=0,c=window.performance.now();const u=()=>{for(r=window.performance.now(),d+=Math.min(1,(r-c)/1e3);d>s;)d-=s,o(a);l(d/n),c=r,i(u)};i(u)})({update:()=>{E.createKeyEvents();for(const n of E.consumeAll())if("play"===o){const o=n[0];if(o===me){const e=n[1],t=n[2];Jn=!0,O.move(e,t)}else if(o===ve){if(F&&!wt.getFirstOwnedTile(e,t)){const e={x:n[1],y:n[2]},t=O.worldToViewport(e),o=Math.round(t.x-F.x),l=Math.round(t.y-F.y);Jn=!0,O.move(o,l),F=t}}else if(o===fe){const e={x:n[1],y:n[2]};F=O.worldToViewport(e)}else if(o===we)F=null;else if(o===be){const e={x:n[1],y:n[2]};Jn=!0,O.zoom("in",O.worldToViewport(e))}else if(o===xe){const e={x:n[1],y:n[2]};Jn=!0,O.zoom("out",O.worldToViewport(e))}else o===Te&&i.togglePreview();const l=w();wt.handleInput(e,t,n,l).length>0&&(Jn=!0),dn.sendClientEvent(n)}else if("replay"===o){const e=n[0];if(e===me){const e=n[1],t=n[2];Jn=!0,O.move(e,t)}else if(e===ve){if(F){const e={x:n[1],y:n[2]},t=O.worldToViewport(e),o=Math.round(t.x-F.x),l=Math.round(t.y-F.y);Jn=!0,O.move(o,l),F=t}}else if(e===fe){const e={x:n[1],y:n[2]};F=O.worldToViewport(e)}else if(e===we)F=null;else if(e===be){const e={x:n[1],y:n[2]};Jn=!0,O.zoom("in",O.worldToViewport(e))}else if(e===xe){const e={x:n[1],y:n[2]};Jn=!0,O.zoom("out",O.worldToViewport(e))}else e===Te&&i.togglePreview()}R=!!wt.getFinishTs(e),$()&&(D.update(),Jn=!0)},render:async()=>{if(!Jn)return;const n=w();let l,a,s;window.DEBUG&&Un(0),B.fillStyle=V(),B.fillRect(0,0,m.width,m.height),window.DEBUG&&Gn("clear done"),l=O.worldToViewportRaw(z),a=O.worldDimToViewportRaw(S),B.fillStyle="rgba(255, 255, 255, .3)",B.fillRect(l.x,l.y,a.w,a.h),window.DEBUG&&Gn("board done");const r=wt.getTilesSortedByZIndex(e);window.DEBUG&&Gn("get tiles done"),a=O.worldDimToViewportRaw(I);for(const e of r)(-1===e.owner?Zn:Kn)&&(s=_[e.idx],l=O.worldToViewportRaw({x:b+e.pos.x,y:b+e.pos.y}),B.drawImage(s,0,0,s.width,s.height,l.x,l.y,a.w,a.h));window.DEBUG&&Gn("tiles done");const d=[];for(const i of wt.getActivePlayers(e,n))s=await y(i),l=O.worldToViewport(i),B.drawImage(s,l.x-u,l.y-g),c=i,("replay"===o||c.id!==t)&&d.push([`${i.name} (${i.points})`,l.x,l.y+p]);var c;B.fillStyle="white",B.textAlign="center";for(const[e,t,o]of d)B.fillText(e,t,o);window.DEBUG&&Gn("players done"),i.setActivePlayers(wt.getActivePlayers(e,n)),i.setIdlePlayers(wt.getIdlePlayers(e,n)),i.setPiecesDone(wt.getFinishedTileCount(e)),window.DEBUG&&Gn("HUD done"),$()&&D.render(),Jn=!1}}),{setHotkeys:e=>{E.setHotkeys(e)},onBgChange:e=>{localStorage.setItem("bg_color",e),E.addEvent([Ce,e])},onColorChange:e=>{localStorage.setItem("player_color",e),E.addEvent([Ae,e])},onNameChange:e=>{localStorage.setItem("player_name",e),E.addEvent([ke,e])},replayOnSpeedUp:()=>{f.speedIdx+1{f.speedIdx>=1&&(f.speedIdx--,j())},replayOnPauseToggle:()=>{f.paused=!f.paused,j()},previewImageUrl:M,player:{background:V(),color:wt.getPlayerColor(e,t)||localStorage.getItem("player_color")||"#ffffff",name:wt.getPlayerName(e,t)||localStorage.getItem("player_name")||"anon"},disconnect:dn.disconnect,connect:v}}var eo=e({name:"game",components:{PuzzleStatus:Lt,Scores:$t,SettingsOverlay:Qt,PreviewOverlay:Kt,ConnectionOverlay:cn,HelpOverlay:mn},data:()=>({activePlayers:[],idlePlayers:[],finished:!1,duration:0,piecesDone:0,piecesTotal:0,overlay:"",connectionState:0,g:{player:{background:"",color:"",name:""},previewImageUrl:"",setHotkeys:e=>{},onBgChange:e=>{},onColorChange:e=>{},onNameChange:e=>{},disconnect:()=>{},connect:()=>{}}}),async mounted(){this.$route.params.id&&(this.$watch((()=>this.g.player.background),(e=>{this.g.onBgChange(e)})),this.$watch((()=>this.g.player.color),(e=>{this.g.onColorChange(e)})),this.$watch((()=>this.g.player.name),(e=>{this.g.onNameChange(e)})),this.g=await Xn(`${this.$route.params.id}`,this.$clientId,this.$config.WS_ADDRESS,"play",this.$el,{setActivePlayers:e=>{this.activePlayers=e},setIdlePlayers:e=>{this.idlePlayers=e},setFinished:e=>{this.finished=e},setDuration:e=>{this.duration=e},setPiecesDone:e=>{this.piecesDone=e},setPiecesTotal:e=>{this.piecesTotal=e},setConnectionState:e=>{this.connectionState=e},togglePreview:()=>{this.toggle("preview",!1)}}))},unmounted(){this.g.disconnect()},methods:{reconnect(){this.g.connect()},toggle(e,t){""===this.overlay?(this.overlay=e,t&&this.g.setHotkeys(!1)):(this.overlay="",t&&this.g.setHotkeys(!0))}}});const to={id:"game"},no={class:"menu"},oo={class:"tabs"},lo=s("🧩 Puzzles");eo.render=function(e,l,s,r,d,c){const p=i("settings-overlay"),g=i("preview-overlay"),h=i("help-overlay"),y=i("connection-overlay"),m=i("puzzle-status"),w=i("router-link"),v=i("scores");return a(),t("div",to,[u(n(p,{onBgclick:l[1]||(l[1]=t=>e.toggle("settings",!0)),modelValue:e.g.player,"onUpdate:modelValue":l[2]||(l[2]=t=>e.g.player=t)},null,8,["modelValue"]),[[f,"settings"===e.overlay]]),u(n(g,{onBgclick:l[3]||(l[3]=t=>e.toggle("preview",!1)),img:e.g.previewImageUrl},null,8,["img"]),[[f,"preview"===e.overlay]]),u(n(h,{onBgclick:l[4]||(l[4]=t=>e.toggle("help",!0))},null,512),[[f,"help"===e.overlay]]),n(y,{connectionState:e.connectionState,onReconnect:e.reconnect},null,8,["connectionState","onReconnect"]),n(m,{finished:e.finished,duration:e.duration,piecesDone:e.piecesDone,piecesTotal:e.piecesTotal},null,8,["finished","duration","piecesDone","piecesTotal"]),n("div",no,[n("div",oo,[n(w,{class:"opener",to:{name:"index"},target:"_blank"},{default:o((()=>[lo])),_:1}),n("div",{class:"opener",onClick:l[5]||(l[5]=t=>e.toggle("preview",!1))},"πŸ–ΌοΈ Preview"),n("div",{class:"opener",onClick:l[6]||(l[6]=t=>e.toggle("settings",!0))},"πŸ› οΈ Settings"),n("div",{class:"opener",onClick:l[7]||(l[7]=t=>e.toggle("help",!0))},"ℹ️ Help")])]),n(v,{activePlayers:e.activePlayers,idlePlayers:e.idlePlayers},null,8,["activePlayers","idlePlayers"])])};var io=e({name:"replay",components:{PuzzleStatus:Lt,Scores:$t,SettingsOverlay:Qt,PreviewOverlay:Kt,HelpOverlay:mn},data:()=>({activePlayers:[],idlePlayers:[],finished:!1,duration:0,piecesDone:0,piecesTotal:0,overlay:"",connectionState:0,g:{player:{background:"",color:"",name:""},previewImageUrl:"",setHotkeys:e=>{},onBgChange:e=>{},onColorChange:e=>{},onNameChange:e=>{},replayOnSpeedUp:()=>{},replayOnSpeedDown:()=>{},replayOnPauseToggle:()=>{},disconnect:()=>{}},replay:{speed:1,paused:!1}}),async mounted(){this.$route.params.id&&(this.$watch((()=>this.g.player.background),(e=>{this.g.onBgChange(e)})),this.$watch((()=>this.g.player.color),(e=>{this.g.onColorChange(e)})),this.$watch((()=>this.g.player.name),(e=>{this.g.onNameChange(e)})),this.g=await Xn(`${this.$route.params.id}`,this.$clientId,this.$config.WS_ADDRESS,"replay",this.$el,{setActivePlayers:e=>{this.activePlayers=e},setIdlePlayers:e=>{this.idlePlayers=e},setFinished:e=>{this.finished=e},setDuration:e=>{this.duration=e},setPiecesDone:e=>{this.piecesDone=e},setPiecesTotal:e=>{this.piecesTotal=e},togglePreview:()=>{this.toggle("preview",!1)},setConnectionState:e=>{this.connectionState=e},setReplaySpeed:e=>{this.replay.speed=e},setReplayPaused:e=>{this.replay.paused=e}}))},unmounted(){this.g.disconnect()},methods:{toggle(e,t){""===this.overlay?(this.overlay=e,t&&this.g.setHotkeys(!1)):(this.overlay="",t&&this.g.setHotkeys(!0))}},computed:{replayText(){return"Replay-Speed: "+this.replay.speed+"x"+(this.replay.paused?" Paused":"")}}});const ao={id:"replay"},so={class:"menu"},ro={class:"tabs"},co=s("🧩 Puzzles");io.render=function(e,l,s,d,c,p){const g=i("settings-overlay"),h=i("preview-overlay"),y=i("help-overlay"),m=i("puzzle-status"),w=i("router-link"),v=i("scores");return a(),t("div",ao,[u(n(g,{onBgclick:l[1]||(l[1]=t=>e.toggle("settings",!0)),modelValue:e.g.player,"onUpdate:modelValue":l[2]||(l[2]=t=>e.g.player=t)},null,8,["modelValue"]),[[f,"settings"===e.overlay]]),u(n(h,{onBgclick:l[3]||(l[3]=t=>e.toggle("preview",!1)),img:e.g.previewImageUrl},null,8,["img"]),[[f,"preview"===e.overlay]]),u(n(y,{onBgclick:l[4]||(l[4]=t=>e.toggle("help",!0))},null,512),[[f,"help"===e.overlay]]),n(m,{finished:e.finished,duration:e.duration,piecesDone:e.piecesDone,piecesTotal:e.piecesTotal},{default:o((()=>[n("div",null,[n("div",null,r(e.replayText),1),n("button",{class:"btn",onClick:l[5]||(l[5]=t=>e.g.replayOnSpeedUp())},"⏫"),n("button",{class:"btn",onClick:l[6]||(l[6]=t=>e.g.replayOnSpeedDown())},"⏬"),n("button",{class:"btn",onClick:l[7]||(l[7]=t=>e.g.replayOnPauseToggle())},"⏸️")])])),_:1},8,["finished","duration","piecesDone","piecesTotal"]),n("div",so,[n("div",ro,[n(w,{class:"opener",to:{name:"index"},target:"_blank"},{default:o((()=>[co])),_:1}),n("div",{class:"opener",onClick:l[8]||(l[8]=t=>e.toggle("preview",!1))},"πŸ–ΌοΈ Preview"),n("div",{class:"opener",onClick:l[9]||(l[9]=t=>e.toggle("settings",!0))},"πŸ› οΈ Settings"),n("div",{class:"opener",onClick:l[10]||(l[10]=t=>e.toggle("help",!0))},"ℹ️ Help")])]),n(v,{activePlayers:e.activePlayers,idlePlayers:e.idlePlayers},null,8,["activePlayers","idlePlayers"])])},(async()=>{const e=await fetch("/api/conf"),t=await e.json();const n=w({history:v(),routes:[{name:"index",path:"/",component:U},{name:"new-game",path:"/new-game",component:Pt},{name:"game",path:"/g/:id",component:eo},{name:"replay",path:"/replay/:id",component:io}]});n.beforeEach(((e,t)=>{t.name&&document.documentElement.classList.remove(`view-${String(t.name)}`),document.documentElement.classList.add(`view-${String(e.name)}`)}));const o=b(x);o.config.globalProperties.$config=t,o.config.globalProperties.$clientId=function(){let e=localStorage.getItem("ID");return e||(e=Ne.uniqId(),localStorage.setItem("ID",e)),e}(),o.use(n),o.mount("#app")})(); diff --git a/build/public/assets/index.c5b0553c.css b/build/public/assets/index.dc049e4e.css similarity index 61% rename from build/public/assets/index.c5b0553c.css rename to build/public/assets/index.dc049e4e.css index a3b815d..f05f1a5 100644 --- a/build/public/assets/index.c5b0553c.css +++ b/build/public/assets/index.dc049e4e.css @@ -1 +1 @@ -:root{--main-color:#c1b19f;--main-darker-color:#4f4e4c;--link-color:#808db0;--link-hover-color:#c5cfeb;--highlight-color:#dd7e7e;--input-bg-color:#262523;--bg-color:rgba(0,0,0,.7)}body,html{margin:0;background:#2b2b2b;color:var(--main-color);height:100%}*{font-family:monospace;font-size:15px}h1,h2,h3,h4{font-size:20px}a{color:var(--link-color);text-decoration:none}a:hover{color:var(--link-hover-color)}td,th{vertical-align:top}.btn{display:inline-block;background:var(--input-bg-color);color:var(--link-color);border:solid 1px #000;padding:5px 10px;box-shadow:1px 1px 2px rgba(0,0,0,.5),0 0 1px rgba(150,150,150,.4) inset;border-radius:4px;user-select:none}.btn-big{font-size:1.5em;padding:10px 20px}.btn:hover{background:#2f2e2c;color:var(--link-hover-color);border:solid 1px #111;box-shadow:0 0 1px rgba(150,150,150,.4) inset;cursor:pointer}.btn:disabled{background:#2f2e2c;color:#8c4747!important;border:solid 1px #111;box-shadow:0 0 1px rgba(150,150,150,.4) inset;cursor:not-allowed}input{background:#333230;border-radius:4px;color:var(--main-color);padding:6px 10px;border:solid 1px #000;box-shadow:0 0 3px rgba(0,0,0,.3) inset}input:focus{border:solid 1px #686767;background:var(--input-bg-color)}.scores{position:absolute;right:0;top:0;background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7)}.timer{position:absolute;left:0;top:0;background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7)}.menu{position:absolute;top:0;left:50%;transform:translateX(-50%);background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7);z-index:2}.closed{display:none}.overlay{position:absolute;top:0;left:0;right:0;bottom:0;z-index:10;background:var(--bg-color)}.overlay.transparent{background:0 0}.overlay-content{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7);z-index:1}.connection-lost .overlay-content{padding:20px;text-align:center}.preview{position:absolute;top:20px;left:20px;bottom:20px;right:20px}.preview .img{height:100%;width:100%;position:absolute;background-repeat:no-repeat;background-position:center;background-size:contain}.menu .opener{display:inline-block;margin-right:10px;color:var(--link-color)}.menu .opener:last-child{margin-right:0}.menu .opener:hover{color:var(--link-hover-color);cursor:pointer}canvas.loaded{cursor:none}kbd{background-color:#eee;border-radius:3px;border:1px solid #b4b4b4;box-shadow:0 1px 1px rgba(0,0,0,.2),0 2px 0 0 rgba(255,255,255,.7) inset;color:#333;display:inline-block;font-size:.85em;font-weight:700;line-height:1;padding:2px 4px;white-space:nowrap}.hint{color:var(--main-darker-color)}.upload-image-teaser{text-align:center}.upload-image-teaser .btn{margin-bottom:.5em}table label{line-height:32px}.nav{list-style:none;padding:0}.nav li{display:inline-block;margin-right:1em}.image-list{overflow:scroll}.image-list-inner{white-space:nowrap}.imageteaser{width:150px;height:100px;display:inline-block;margin:5px;background-size:contain;background-position:center;background-repeat:no-repeat;background-color:#222;cursor:pointer}.game-teaser-wrap{display:inline-block;width:20%;padding:5px;box-sizing:border-box}.game-teaser{display:block;background-repeat:no-repeat;background-position:center;background-size:contain;position:relative;padding-top:56.25%;width:100%;background-color:#222}.game-info{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%}.game-info-text{position:absolute;top:0;background:var(--bg-color);padding:5px}.game-replay{position:absolute;top:0;right:0}html.view-game{overflow:hidden}html.view-game body{overflow:hidden}html.view-replay{overflow:hidden}html.view-replay body{overflow:hidden}html.view-replay canvas{cursor:grab}.new-image-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}.new-image-dialog .area-image{grid-area:image;margin:20px}.new-image-dialog .area-image.no-image{align-content:center;display:grid;text-align:center;border:dashed 6px;position:relative}.new-image-dialog .area-image .has-image{position:relative;width:100%;height:100%}.new-image-dialog .area-image .has-image .remove{position:absolute;top:.5em;left:.5em}.new-image-dialog .area-settings{grid-area:settings}.new-image-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.new-image-dialog .area-buttons{align-self:end;grid-area:buttons}.new-image-dialog .area-buttons button{width:100%;margin-top:.5em}.new-image-dialog .upload{position:absolute;top:0;left:0;right:0;bottom:0;cursor:pointer}.new-image-dialog .upload .btn{position:absolute;top:50%;transform:translate(-50%,-50%)}.new-game-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}.new-game-dialog .area-image{grid-area:image;margin:20px}.new-game-dialog .area-settings{grid-area:settings}.new-game-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.new-game-dialog .area-buttons{align-self:end;grid-area:buttons}.new-game-dialog .area-buttons button{width:100%}.new-game-dialog .has-image{position:relative;width:100%;height:100%}.new-game-dialog .has-image .remove{position:absolute;top:.5em;left:.5em} \ No newline at end of file +:root{--main-color:#c1b19f;--main-darker-color:#4f4e4c;--link-color:#808db0;--link-hover-color:#c5cfeb;--highlight-color:#dd7e7e;--input-bg-color:#262523;--bg-color:rgba(0,0,0,.7)}body,html{margin:0;background:#2b2b2b;color:var(--main-color);height:100%}*{font-family:monospace;font-size:15px}h1,h2,h3,h4{font-size:20px}a{color:var(--link-color);text-decoration:none}a:hover{color:var(--link-hover-color)}td,th{vertical-align:top}.btn{display:inline-block;background:var(--input-bg-color);color:var(--link-color);border:solid 1px #000;padding:5px 10px;box-shadow:1px 1px 2px rgba(0,0,0,.5),0 0 1px rgba(150,150,150,.4) inset;border-radius:4px;user-select:none}.btn-big{font-size:1.5em;padding:10px 20px}.btn:hover{background:#2f2e2c;color:var(--link-hover-color);border:solid 1px #111;box-shadow:0 0 1px rgba(150,150,150,.4) inset;cursor:pointer}.btn:disabled{background:#2f2e2c;color:#8c4747!important;border:solid 1px #111;box-shadow:0 0 1px rgba(150,150,150,.4) inset;cursor:not-allowed}input{background:#333230;border-radius:4px;color:var(--main-color);padding:6px 10px;border:solid 1px #000;box-shadow:0 0 3px rgba(0,0,0,.3) inset}input:focus{border:solid 1px #686767;background:var(--input-bg-color)}.scores{position:absolute;right:0;top:0;background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7)}.timer{position:absolute;left:0;top:0;background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7)}.menu{position:absolute;top:0;left:50%;transform:translateX(-50%);background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7);z-index:2}.closed{display:none}.overlay{position:absolute;top:0;left:0;right:0;bottom:0;z-index:10;background:var(--bg-color)}.overlay.transparent{background:0 0}.overlay-content{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7);z-index:1}.connection-lost .overlay-content{padding:20px;text-align:center}.preview{position:absolute;top:20px;left:20px;bottom:20px;right:20px}.preview .img{height:100%;width:100%;position:absolute;background-repeat:no-repeat;background-position:center;background-size:contain}.menu .opener{display:inline-block;margin-right:10px;color:var(--link-color)}.menu .opener:last-child{margin-right:0}.menu .opener:hover{color:var(--link-hover-color);cursor:pointer}canvas.loaded{cursor:none}kbd{background-color:#eee;border-radius:3px;border:1px solid #b4b4b4;box-shadow:0 1px 1px rgba(0,0,0,.2),0 2px 0 0 rgba(255,255,255,.7) inset;color:#333;display:inline-block;font-size:.85em;font-weight:700;line-height:1;padding:2px 4px;white-space:nowrap}.hint{color:var(--main-darker-color)}.upload-image-teaser{text-align:center}.upload-image-teaser .btn{margin-bottom:.5em}table label{line-height:32px}.nav{list-style:none;padding:0}.nav li{display:inline-block;margin-right:1em}.image-list{overflow:scroll}.image-list-inner{white-space:nowrap}.imageteaser{width:150px;height:100px;display:inline-block;margin:5px;background-size:contain;background-position:center;background-repeat:no-repeat;background-color:#222;cursor:pointer}.game-teaser-wrap{display:inline-block;width:20%;padding:5px;box-sizing:border-box}.game-teaser{display:block;background-repeat:no-repeat;background-position:center;background-size:contain;position:relative;padding-top:56.25%;width:100%;background-color:#222}.game-info{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%}.game-info-text{position:absolute;top:0;background:var(--bg-color);padding:5px}.game-replay{position:absolute;top:0;right:0}html.view-game{overflow:hidden}html.view-game body{overflow:hidden}html.view-replay{overflow:hidden}html.view-replay body{overflow:hidden}html.view-replay canvas{cursor:grab}.imageteaser{position:relative}.imageteaser .edit{display:none;position:absolute}.imageteaser:hover .edit{display:inline-block}.new-image-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}.new-image-dialog .area-image{grid-area:image;margin:20px}.new-image-dialog .area-image.no-image{align-content:center;display:grid;text-align:center;border:dashed 6px;position:relative}.new-image-dialog .area-image .has-image{position:relative;width:100%;height:100%}.new-image-dialog .area-image .has-image .remove{position:absolute;top:.5em;left:.5em}.new-image-dialog .area-settings{grid-area:settings}.new-image-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.new-image-dialog .area-buttons{align-self:end;grid-area:buttons}.new-image-dialog .area-buttons button{width:100%;margin-top:.5em}.new-image-dialog .upload{position:absolute;top:0;left:0;right:0;bottom:0;cursor:pointer}.new-image-dialog .upload .btn{position:absolute;top:50%;transform:translate(-50%,-50%)}.edit-image-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}.edit-image-dialog .area-image{grid-area:image;margin:20px}.edit-image-dialog .area-image.no-image{align-content:center;display:grid;text-align:center;border:dashed 6px;position:relative}.edit-image-dialog .area-image .has-image{position:relative;width:100%;height:100%}.edit-image-dialog .area-image .has-image .remove{position:absolute;top:.5em;left:.5em}.edit-image-dialog .area-settings{grid-area:settings}.edit-image-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.edit-image-dialog .area-buttons{align-self:end;grid-area:buttons}.edit-image-dialog .area-buttons button{width:100%;margin-top:.5em}.new-game-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}.new-game-dialog .area-image{grid-area:image;margin:20px}.new-game-dialog .area-settings{grid-area:settings}.new-game-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.new-game-dialog .area-buttons{align-self:end;grid-area:buttons}.new-game-dialog .area-buttons button{width:100%}.new-game-dialog .has-image{position:relative;width:100%;height:100%}.new-game-dialog .has-image .remove{position:absolute;top:.5em;left:.5em} \ No newline at end of file diff --git a/build/public/assets/vendor.8616a479.js b/build/public/assets/vendor.1ad14f11.js similarity index 99% rename from build/public/assets/vendor.8616a479.js rename to build/public/assets/vendor.1ad14f11.js index 23960f6..5a8888d 100644 --- a/build/public/assets/vendor.8616a479.js +++ b/build/public/assets/vendor.1ad14f11.js @@ -3,4 +3,4 @@ function e(e,t){const n=Object.create(null),r=e.split(",");for(let o=0;owo?Symbol(e):"_vr_"+e,Eo=xo("rvlm"),ko=xo("rvd"),So=xo("r"),Oo=xo("rl"),Co=xo("rvl"),Ro="undefined"!=typeof window;const Ao=Object.assign;function Po(e,t){const n={};for(const r in t){const o=t[r];n[r]=Array.isArray(o)?o.map(e):e(o)}return n}let Fo=()=>{};const jo=/\/$/;function $o(e,t,n="/"){let r,o={},s="",l="";const i=t.indexOf("?"),c=t.indexOf("#",i>-1?i:0);return i>-1&&(r=t.slice(0,i),s=t.slice(i+1,c>-1?c:t.length),o=e(s)),c>-1&&(r=r||t.slice(0,c),l=t.slice(c,t.length)),r=function(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),r=e.split("/");let o,s,l=n.length-1;for(o=0;oe===t[n])):1===e.length&&e[0]===t}var No,Lo,Bo,Do;function qo(e){if(!e)if(Ro){const t=document.querySelector("base");e=(e=t&&t.getAttribute("href")||"/").replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return"/"!==e[0]&&"#"!==e[0]&&(e="/"+e),e.replace(jo,"")}(Lo=No||(No={})).pop="pop",Lo.push="push",(Do=Bo||(Bo={})).back="back",Do.forward="forward",Do.unknown="";const zo=/^[^#]+#/;function Wo(e,t){return e.replace(zo,"#")+t}const Ko=()=>({left:window.pageXOffset,top:window.pageYOffset});function Go(e){let t;if("el"in e){let n=e.el;const r="string"==typeof n&&n.startsWith("#"),o="string"==typeof n?r?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!o)return;t=function(e,t){const n=document.documentElement.getBoundingClientRect(),r=e.getBoundingClientRect();return{behavior:t.behavior,left:r.left-n.left-(t.left||0),top:r.top-n.top-(t.top||0)}}(o,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(null!=t.left?t.left:window.pageXOffset,null!=t.top?t.top:window.pageYOffset)}function Ho(e,t){return(history.state?history.state.position-t:-1)+e}const Xo=new Map;function Jo(e,t){const{pathname:n,search:r,hash:o}=t,s=e.indexOf("#");if(s>-1){let t=o.includes(e.slice(s))?e.slice(s).length:1,n=o.slice(t);return"/"!==n[0]&&(n="/"+n),Mo(n,"")}return Mo(n,e)+r+o}function Qo(e,t,n,r=!1,o=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:o?Ko():null}}function Yo(e){const{history:t,location:n}=window;let r={value:Jo(e,n)},o={value:t.state};function s(r,s,l){const i=e.indexOf("#"),c=i>-1?(n.host&&document.querySelector("base")?e:e.slice(i))+r:location.protocol+"//"+location.host+e+r;try{t[l?"replaceState":"pushState"](s,"",c),o.value=s}catch(a){console.error(a),n[l?"replace":"assign"](c)}}return o.value||s(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0),{location:r,state:o,push:function(e,n){const l=Ao({},o.value,t.state,{forward:e,scroll:Ko()});s(l.current,l,!0),s(e,Ao({},Qo(r.value,e,null),{position:l.position+1},n),!1),r.value=e},replace:function(e,n){s(e,Ao({},t.state,Qo(o.value.back,e,o.value.forward,!0),n,{position:o.value.position}),!0),r.value=e}}}function Zo(e){const t=Yo(e=qo(e)),n=function(e,t,n,r){let o=[],s=[],l=null;const i=({state:s})=>{const i=Jo(e,location),c=n.value,a=t.value;let u=0;if(s){if(n.value=i,t.value=s,l&&l===c)return void(l=null);u=a?s.position-a.position:0}else r(i);o.forEach((e=>{e(n.value,c,{delta:u,type:No.pop,direction:u?u>0?Bo.forward:Bo.back:Bo.unknown})}))};function c(){const{history:e}=window;e.state&&e.replaceState(Ao({},e.state,{scroll:Ko()}),"")}return window.addEventListener("popstate",i),window.addEventListener("beforeunload",c),{pauseListeners:function(){l=n.value},listen:function(e){o.push(e);const t=()=>{const t=o.indexOf(e);t>-1&&o.splice(t,1)};return s.push(t),t},destroy:function(){for(const e of s)e();s=[],window.removeEventListener("popstate",i),window.removeEventListener("beforeunload",c)}}}(e,t.state,t.location,t.replace);const r=Ao({location:"",base:e,go:function(e,t=!0){t||n.pauseListeners(),history.go(e)},createHref:Wo.bind(null,e)},t,n);return Object.defineProperty(r,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(r,"state",{enumerable:!0,get:()=>t.state.value}),r}function es(e){return(e=location.host?e||location.pathname+location.search:"").indexOf("#")<0&&(e+="#"),Zo(e)}function ts(e){return"string"==typeof e||"symbol"==typeof e}const ns={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},rs=xo("nf");var os,ss;function ls(e,t){return Ao(new Error,{type:e,[rs]:!0},t)}function is(e,t){return e instanceof Error&&rs in e&&(null==t||!!(e.type&t))}(ss=os||(os={}))[ss.aborted=4]="aborted",ss[ss.cancelled=8]="cancelled",ss[ss.duplicated=16]="duplicated";const cs={sensitive:!1,strict:!1,start:!0,end:!0},as=/[.+*?^${}()[\]/\\]/g;function us(e,t){let n=0;for(;nt.length?1===t.length&&80===t[0]?1:-1:0}function fs(e,t){let n=0;const r=e.score,o=t.score;for(;n1&&("*"===i||"+"===i)&&t(`A repeatable param (${a}) must be alone in its segment. eg: '/:ids+.`),s.push({type:1,value:a,regexp:u,repeatable:"*"===i||"+"===i,optional:"*"===i||"?"===i})):t("Invalid state to consume buffer"),a="")}function p(){a+=i}for(;c{s(p)}:Fo}function s(e){if(ts(e)){const t=r.get(e);t&&(r.delete(e),n.splice(n.indexOf(t),1),t.children.forEach(s),t.alias.forEach(s))}else{let t=n.indexOf(e);t>-1&&(n.splice(t,1),e.record.name&&r.delete(e.record.name),e.children.forEach(s),e.alias.forEach(s))}}function l(e){let t=0;for(;t=0;)t++;n.splice(t,0,e),e.record.name&&!vs(e)&&r.set(e.record.name,e)}return t=bs({strict:!1,end:!0,sensitive:!1},t),e.forEach((e=>o(e))),{addRoute:o,resolve:function(e,t){let o,s,l,i={};if("name"in e&&e.name){if(o=r.get(e.name),!o)throw ls(1,{location:e});l=o.record.name,i=Ao(function(e,t){let n={};for(let r of t)r in e&&(n[r]=e[r]);return n}(t.params,o.keys.filter((e=>!e.optional)).map((e=>e.name))),e.params),s=o.stringify(i)}else if("path"in e)s=e.path,o=n.find((e=>e.re.test(s))),o&&(i=o.parse(s),l=o.record.name);else{if(o=t.name?r.get(t.name):n.find((e=>e.re.test(t.path))),!o)throw ls(1,{location:e,currentLocation:t});l=o.record.name,i=Ao({},t.params,e.params),s=o.stringify(i)}const c=[];let a=o;for(;a;)c.unshift(a.record),a=a.parent;return{name:l,path:s,params:i,matched:c,meta:ys(c)}},removeRoute:s,getRoutes:function(){return n},getRecordMatcher:function(e){return r.get(e)}}}function gs(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(let r in e.components)t[r]="boolean"==typeof n?n:n[r];return t}function vs(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function ys(e){return e.reduce(((e,t)=>Ao(e,t.meta)),{})}function bs(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}const _s=/#/g,ws=/&/g,xs=/\//g,Es=/=/g,ks=/\?/g,Ss=/\+/g,Os=/%5B/g,Cs=/%5D/g,Rs=/%5E/g,As=/%60/g,Ps=/%7B/g,Fs=/%7C/g,js=/%7D/g,$s=/%20/g;function Ms(e){return encodeURI(""+e).replace(Fs,"|").replace(Os,"[").replace(Cs,"]")}function Is(e){return Ms(e).replace(Ss,"%2B").replace($s,"+").replace(_s,"%23").replace(ws,"%26").replace(As,"`").replace(Ps,"{").replace(js,"}").replace(Rs,"^")}function Ts(e){return function(e){return Ms(e).replace(_s,"%23").replace(ks,"%3F")}(e).replace(xs,"%2F")}function Us(e){try{return decodeURIComponent(""+e)}catch(t){}return""+e}function Vs(e){const t={};if(""===e||"?"===e)return t;const n=("?"===e[0]?e.slice(1):e).split("&");for(let r=0;re&&Is(e))):[r&&Is(r)]).forEach((e=>{void 0!==e&&(t+=(t.length?"&":"")+n,null!=e&&(t+="="+e))}))}return t}function Ls(e){const t={};for(let n in e){let r=e[n];void 0!==r&&(t[n]=Array.isArray(r)?r.map((e=>null==e?null:""+e)):null==r?r:""+r)}return t}function Bs(){let e=[];return{add:function(t){return e.push(t),()=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)}},list:()=>e,reset:function(){e=[]}}}function Ds(e,t,n,r,o){const s=r&&(r.enterCallbacks[o]=r.enterCallbacks[o]||[]);return()=>new Promise(((l,i)=>{const c=e=>{var c;!1===e?i(ls(4,{from:n,to:t})):e instanceof Error?i(e):"string"==typeof(c=e)||c&&"object"==typeof c?i(ls(2,{from:t,to:e})):(s&&r.enterCallbacks[o]===s&&"function"==typeof e&&s.push(e),l())},a=e.call(r&&r.instances[o],t,n,c);let u=Promise.resolve(a);e.length<3&&(u=u.then(c)),u.catch((e=>i(e)))}))}function qs(e,t,n,r){const o=[];for(const l of e)for(const e in l.components){let i=l.components[e];if("beforeRouteEnter"===t||l.instances[e])if("object"==typeof(s=i)||"displayName"in s||"props"in s||"__vccOpts"in s){const s=(i.__vccOpts||i)[t];s&&o.push(Ds(s,n,r,l,e))}else{let s=i();s=s.catch(console.error),o.push((()=>s.then((o=>{if(!o)return Promise.reject(new Error(`Couldn't resolve component "${e}" at "${l.path}"`));const s=(i=o).__esModule||wo&&"Module"===i[Symbol.toStringTag]?o.default:o;var i;l.components[e]=s;const c=(s.__vccOpts||s)[t];return c&&Ds(c,n,r,l,e)()}))))}}var s;return o}function zs(e){const t=pr(So),n=pr(Oo),r=Ir((()=>t.resolve(st(e.to)))),o=Ir((()=>{let{matched:e}=r.value,{length:t}=e;const o=e[t-1];let s=n.matched;if(!o||!s.length)return-1;let l=s.findIndex(Io.bind(null,o));if(l>-1)return l;let i=Ks(e[t-2]);return t>1&&Ks(o)===i&&s[s.length-1].path!==i?s.findIndex(Io.bind(null,e[t-2])):l})),s=Ir((()=>o.value>-1&&function(e,t){for(let n in t){let r=t[n],o=e[n];if("string"==typeof r){if(r!==o)return!1}else if(!Array.isArray(o)||o.length!==r.length||r.some(((e,t)=>e!==o[t])))return!1}return!0}(n.params,r.value.params))),l=Ir((()=>o.value>-1&&o.value===n.matched.length-1&&To(n.params,r.value.params)));return{route:r,href:Ir((()=>r.value.href)),isActive:s,isExactActive:l,navigate:function(n={}){return function(e){if(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;if(e.defaultPrevented)return;if(void 0!==e.button&&0!==e.button)return;if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}e.preventDefault&&e.preventDefault();return!0}(n)?t[st(e.replace)?"replace":"push"](st(e.to)):Promise.resolve()}}}const Ws=Mn({name:"RouterLink",props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"}},setup(e,{slots:t}){const n=He(zs(e)),{options:r}=pr(So),o=Ir((()=>({[Gs(e.activeClass,r.linkActiveClass,"router-link-active")]:n.isActive,[Gs(e.exactActiveClass,r.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive})));return()=>{const r=t.default&&t.default(n);return e.custom?r:Tr("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:o.value},r)}}});function Ks(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const Gs=(e,t,n)=>null!=e?e:null!=t?t:n;function Hs(e,t){if(!e)return null;const n=e(t);return 1===n.length?n[0]:n}const Xs=Mn({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},setup(e,{attrs:t,slots:n}){const r=pr(Co),o=Ir((()=>e.route||r.value)),s=pr(ko,0),l=Ir((()=>o.value.matched[s]));fr(ko,s+1),fr(Eo,l),fr(Co,o);const i=ot(c);var c;return vn((()=>[i.value,l.value,e.name]),(([e,t,n],[r,o,s])=>{t&&(t.instances[n]=e,o&&o!==t&&e&&e===r&&(t.leaveGuards.size||(t.leaveGuards=o.leaveGuards),t.updateGuards.size||(t.updateGuards=o.updateGuards))),!e||!t||o&&Io(t,o)&&r||(t.enterCallbacks[n]||[]).forEach((t=>t(e)))}),{flush:"post"}),()=>{const r=o.value,s=l.value,c=s&&s.components[e.name],a=e.name;if(!c)return Hs(n.default,{Component:c,route:r});const u=s.props[e.name],f=u?!0===u?r.params:"function"==typeof u?u(r):u:null,p=Tr(c,Ao({},f,t,{onVnodeUnmounted:e=>{e.component.isUnmounted&&(s.instances[a]=null)},ref:i}));return Hs(n.default,{Component:p,route:r})||p}}});function Js(e){const t=ms(e.routes,e);let n=e.parseQuery||Vs,r=e.stringifyQuery||Ns,o=e.history;const s=Bs(),l=Bs(),i=Bs(),c=ot(ns,!0);let a=ns;Ro&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=Po.bind(null,(e=>""+e)),f=Po.bind(null,Ts),p=Po.bind(null,Us);function d(e,s){if(s=Ao({},s||c.value),"string"==typeof e){let r=$o(n,e,s.path),l=t.resolve({path:r.path},s),i=o.createHref(r.fullPath);return Ao(r,l,{params:p(l.params),hash:Us(r.hash),redirectedFrom:void 0,href:i})}let l;"path"in e?l=Ao({},e,{path:$o(n,e.path,s.path).path}):(l=Ao({},e,{params:f(e.params)}),s.params=f(s.params));let i=t.resolve(l,s);const a=e.hash||"";i.params=u(p(i.params));const d=function(e,t){let n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}(r,Ao({},e,{hash:(h=a,Ms(h).replace(Ps,"{").replace(js,"}").replace(Rs,"^")),path:i.path}));var h;let m=o.createHref(d);return Ao({fullPath:d,hash:a,query:r===Ns?Ls(e.query):e.query},i,{redirectedFrom:void 0,href:m})}function h(e){return"string"==typeof e?$o(n,e,c.value.path):Ao({},e)}function m(e,t){if(a!==e)return ls(8,{from:t,to:e})}function g(e){return y(e)}function v(e){const t=e.matched[e.matched.length-1];if(t&&t.redirect){const{redirect:n}=t;let r="function"==typeof n?n(e):n;return"string"==typeof r&&(r=r.indexOf("?")>-1||r.indexOf("#")>-1?r=h(r):{path:r}),Ao({query:e.query,hash:e.hash,params:e.params},r)}}function y(e,t){const n=a=d(e),o=c.value,s=e.state,l=e.force,i=!0===e.replace,u=v(n);if(u)return y(Ao(h(u),{state:s,force:l,replace:i}),t||n);const f=n;let p;return f.redirectedFrom=t,!l&&function(e,t,n){let r=t.matched.length-1,o=n.matched.length-1;return r>-1&&r===o&&Io(t.matched[r],n.matched[o])&&To(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}(r,o,n)&&(p=ls(16,{to:f,from:o}),P(o,o,!0,!1)),(p?Promise.resolve(p):_(f,o)).catch((e=>is(e)?e:R(e))).then((e=>{if(e){if(is(e,2))return y(Ao(h(e.to),{state:s,force:l,replace:i}),t||f)}else e=x(f,o,!0,i,s);return w(f,o,e),e}))}function b(e,t){const n=m(e,t);return n?Promise.reject(n):Promise.resolve()}function _(e,t){let n;const[r,o,i]=function(e,t){const n=[],r=[],o=[],s=Math.max(t.matched.length,e.matched.length);for(let l=0;lIo(e,s)))?r.push(s):n.push(s));const i=e.matched[l];i&&(t.matched.find((e=>Io(e,i)))||o.push(i))}return[n,r,o]}(e,t);n=qs(r.reverse(),"beforeRouteLeave",e,t);for(const s of r)s.leaveGuards.forEach((r=>{n.push(Ds(r,e,t))}));const c=b.bind(null,e,t);return n.push(c),Qs(n).then((()=>{n=[];for(const r of s.list())n.push(Ds(r,e,t));return n.push(c),Qs(n)})).then((()=>{n=qs(o,"beforeRouteUpdate",e,t);for(const r of o)r.updateGuards.forEach((r=>{n.push(Ds(r,e,t))}));return n.push(c),Qs(n)})).then((()=>{n=[];for(const r of e.matched)if(r.beforeEnter&&t.matched.indexOf(r)<0)if(Array.isArray(r.beforeEnter))for(const o of r.beforeEnter)n.push(Ds(o,e,t));else n.push(Ds(r.beforeEnter,e,t));return n.push(c),Qs(n)})).then((()=>(e.matched.forEach((e=>e.enterCallbacks={})),n=qs(i,"beforeRouteEnter",e,t),n.push(c),Qs(n)))).then((()=>{n=[];for(const r of l.list())n.push(Ds(r,e,t));return n.push(c),Qs(n)})).catch((e=>is(e,8)?e:Promise.reject(e)))}function w(e,t,n){for(const r of i.list())r(e,t,n)}function x(e,t,n,r,s){const l=m(e,t);if(l)return l;const i=t===ns,a=Ro?history.state:{};n&&(r||i?o.replace(e.fullPath,Ao({scroll:i&&a&&a.scroll},s)):o.push(e.fullPath,s)),c.value=e,P(e,t,n,i),A()}let E;function k(){E=o.listen(((e,t,n)=>{let r=d(e);const s=v(r);if(s)return void y(Ao(s,{replace:!0}),r).catch(Fo);a=r;const l=c.value;var i,u;Ro&&(i=Ho(l.fullPath,n.delta),u=Ko(),Xo.set(i,u)),_(r,l).catch((e=>is(e,12)?e:is(e,2)?(y(e.to,r).catch(Fo),Promise.reject()):(n.delta&&o.go(-n.delta,!1),R(e)))).then((e=>{(e=e||x(r,l,!1))&&n.delta&&o.go(-n.delta,!1),w(r,l,e)})).catch(Fo)}))}let S,O=Bs(),C=Bs();function R(e){return A(e),C.list().forEach((t=>t(e))),Promise.reject(e)}function A(e){S||(S=!0,k(),O.list().forEach((([t,n])=>e?n(e):t())),O.reset())}function P(t,n,r,o){const{scrollBehavior:s}=e;if(!Ro||!s)return Promise.resolve();let l=!r&&function(e){const t=Xo.get(e);return Xo.delete(e),t}(Ho(t.fullPath,0))||(o||!r)&&history.state&&history.state.scroll||null;return Ot().then((()=>s(t,n,l))).then((e=>e&&Go(e))).catch(R)}const F=e=>o.go(e);let j;const $=new Set;return{currentRoute:c,addRoute:function(e,n){let r,o;return ts(e)?(r=t.getRecordMatcher(e),o=n):o=e,t.addRoute(o,r)},removeRoute:function(e){let n=t.getRecordMatcher(e);n&&t.removeRoute(n)},hasRoute:function(e){return!!t.getRecordMatcher(e)},getRoutes:function(){return t.getRoutes().map((e=>e.record))},resolve:d,options:e,push:g,replace:function(e){return g(Ao(h(e),{replace:!0}))},go:F,back:()=>F(-1),forward:()=>F(1),beforeEach:s.add,beforeResolve:l.add,afterEach:i.add,onError:C.add,isReady:function(){return S&&c.value!==ns?Promise.resolve():new Promise(((e,t)=>{O.add([e,t])}))},install(e){e.component("RouterLink",Ws),e.component("RouterView",Xs),e.config.globalProperties.$router=this,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>st(c)}),Ro&&!j&&c.value===ns&&(j=!0,g(o.location).catch((e=>{})));const t={};for(let r in ns)t[r]=Ir((()=>c.value[r]));e.provide(So,this),e.provide(Oo,He(t)),e.provide(Co,c);let n=e.unmount;$.add(e),e.unmount=function(){$.delete(e),$.size<1&&(E(),c.value=ns,j=!1,S=!1),n()}}}}function Qs(e){return e.reduce(((e,t)=>e.then((()=>t()))),Promise.resolve())}export{zn as F,or as a,ir as b,Yn as c,Mn as d,lr as e,Ur as f,An as g,mo as h,co as i,ao as j,Nt as k,go as l,Js as m,es as n,Jn as o,_o as p,Bn as r,u as t,io as v,zt as w}; + */(e);if(!r)return;const o=t._component;C(o)||o.render||o.template||(o.template=r.innerHTML),r.innerHTML="";const s=n(r,!1,r instanceof SVGElement);return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),s},t};const wo="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag,xo=e=>wo?Symbol(e):"_vr_"+e,Eo=xo("rvlm"),ko=xo("rvd"),So=xo("r"),Oo=xo("rl"),Co=xo("rvl"),Ro="undefined"!=typeof window;const Ao=Object.assign;function Po(e,t){const n={};for(const r in t){const o=t[r];n[r]=Array.isArray(o)?o.map(e):e(o)}return n}let Fo=()=>{};const jo=/\/$/;function $o(e,t,n="/"){let r,o={},s="",l="";const i=t.indexOf("?"),c=t.indexOf("#",i>-1?i:0);return i>-1&&(r=t.slice(0,i),s=t.slice(i+1,c>-1?c:t.length),o=e(s)),c>-1&&(r=r||t.slice(0,c),l=t.slice(c,t.length)),r=function(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),r=e.split("/");let o,s,l=n.length-1;for(o=0;oe===t[n])):1===e.length&&e[0]===t}var No,Lo,Bo,Do;function qo(e){if(!e)if(Ro){const t=document.querySelector("base");e=(e=t&&t.getAttribute("href")||"/").replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return"/"!==e[0]&&"#"!==e[0]&&(e="/"+e),e.replace(jo,"")}(Lo=No||(No={})).pop="pop",Lo.push="push",(Do=Bo||(Bo={})).back="back",Do.forward="forward",Do.unknown="";const zo=/^[^#]+#/;function Wo(e,t){return e.replace(zo,"#")+t}const Ko=()=>({left:window.pageXOffset,top:window.pageYOffset});function Go(e){let t;if("el"in e){let n=e.el;const r="string"==typeof n&&n.startsWith("#"),o="string"==typeof n?r?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!o)return;t=function(e,t){const n=document.documentElement.getBoundingClientRect(),r=e.getBoundingClientRect();return{behavior:t.behavior,left:r.left-n.left-(t.left||0),top:r.top-n.top-(t.top||0)}}(o,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(null!=t.left?t.left:window.pageXOffset,null!=t.top?t.top:window.pageYOffset)}function Ho(e,t){return(history.state?history.state.position-t:-1)+e}const Xo=new Map;function Jo(e,t){const{pathname:n,search:r,hash:o}=t,s=e.indexOf("#");if(s>-1){let t=o.includes(e.slice(s))?e.slice(s).length:1,n=o.slice(t);return"/"!==n[0]&&(n="/"+n),Mo(n,"")}return Mo(n,e)+r+o}function Qo(e,t,n,r=!1,o=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:o?Ko():null}}function Yo(e){const{history:t,location:n}=window;let r={value:Jo(e,n)},o={value:t.state};function s(r,s,l){const i=e.indexOf("#"),c=i>-1?(n.host&&document.querySelector("base")?e:e.slice(i))+r:location.protocol+"//"+location.host+e+r;try{t[l?"replaceState":"pushState"](s,"",c),o.value=s}catch(a){console.error(a),n[l?"replace":"assign"](c)}}return o.value||s(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0),{location:r,state:o,push:function(e,n){const l=Ao({},o.value,t.state,{forward:e,scroll:Ko()});s(l.current,l,!0),s(e,Ao({},Qo(r.value,e,null),{position:l.position+1},n),!1),r.value=e},replace:function(e,n){s(e,Ao({},t.state,Qo(o.value.back,e,o.value.forward,!0),n,{position:o.value.position}),!0),r.value=e}}}function Zo(e){const t=Yo(e=qo(e)),n=function(e,t,n,r){let o=[],s=[],l=null;const i=({state:s})=>{const i=Jo(e,location),c=n.value,a=t.value;let u=0;if(s){if(n.value=i,t.value=s,l&&l===c)return void(l=null);u=a?s.position-a.position:0}else r(i);o.forEach((e=>{e(n.value,c,{delta:u,type:No.pop,direction:u?u>0?Bo.forward:Bo.back:Bo.unknown})}))};function c(){const{history:e}=window;e.state&&e.replaceState(Ao({},e.state,{scroll:Ko()}),"")}return window.addEventListener("popstate",i),window.addEventListener("beforeunload",c),{pauseListeners:function(){l=n.value},listen:function(e){o.push(e);const t=()=>{const t=o.indexOf(e);t>-1&&o.splice(t,1)};return s.push(t),t},destroy:function(){for(const e of s)e();s=[],window.removeEventListener("popstate",i),window.removeEventListener("beforeunload",c)}}}(e,t.state,t.location,t.replace);const r=Ao({location:"",base:e,go:function(e,t=!0){t||n.pauseListeners(),history.go(e)},createHref:Wo.bind(null,e)},t,n);return Object.defineProperty(r,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(r,"state",{enumerable:!0,get:()=>t.state.value}),r}function es(e){return(e=location.host?e||location.pathname+location.search:"").indexOf("#")<0&&(e+="#"),Zo(e)}function ts(e){return"string"==typeof e||"symbol"==typeof e}const ns={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},rs=xo("nf");var os,ss;function ls(e,t){return Ao(new Error,{type:e,[rs]:!0},t)}function is(e,t){return e instanceof Error&&rs in e&&(null==t||!!(e.type&t))}(ss=os||(os={}))[ss.aborted=4]="aborted",ss[ss.cancelled=8]="cancelled",ss[ss.duplicated=16]="duplicated";const cs={sensitive:!1,strict:!1,start:!0,end:!0},as=/[.+*?^${}()[\]/\\]/g;function us(e,t){let n=0;for(;nt.length?1===t.length&&80===t[0]?1:-1:0}function fs(e,t){let n=0;const r=e.score,o=t.score;for(;n1&&("*"===i||"+"===i)&&t(`A repeatable param (${a}) must be alone in its segment. eg: '/:ids+.`),s.push({type:1,value:a,regexp:u,repeatable:"*"===i||"+"===i,optional:"*"===i||"?"===i})):t("Invalid state to consume buffer"),a="")}function p(){a+=i}for(;c{s(p)}:Fo}function s(e){if(ts(e)){const t=r.get(e);t&&(r.delete(e),n.splice(n.indexOf(t),1),t.children.forEach(s),t.alias.forEach(s))}else{let t=n.indexOf(e);t>-1&&(n.splice(t,1),e.record.name&&r.delete(e.record.name),e.children.forEach(s),e.alias.forEach(s))}}function l(e){let t=0;for(;t=0;)t++;n.splice(t,0,e),e.record.name&&!vs(e)&&r.set(e.record.name,e)}return t=bs({strict:!1,end:!0,sensitive:!1},t),e.forEach((e=>o(e))),{addRoute:o,resolve:function(e,t){let o,s,l,i={};if("name"in e&&e.name){if(o=r.get(e.name),!o)throw ls(1,{location:e});l=o.record.name,i=Ao(function(e,t){let n={};for(let r of t)r in e&&(n[r]=e[r]);return n}(t.params,o.keys.filter((e=>!e.optional)).map((e=>e.name))),e.params),s=o.stringify(i)}else if("path"in e)s=e.path,o=n.find((e=>e.re.test(s))),o&&(i=o.parse(s),l=o.record.name);else{if(o=t.name?r.get(t.name):n.find((e=>e.re.test(t.path))),!o)throw ls(1,{location:e,currentLocation:t});l=o.record.name,i=Ao({},t.params,e.params),s=o.stringify(i)}const c=[];let a=o;for(;a;)c.unshift(a.record),a=a.parent;return{name:l,path:s,params:i,matched:c,meta:ys(c)}},removeRoute:s,getRoutes:function(){return n},getRecordMatcher:function(e){return r.get(e)}}}function gs(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(let r in e.components)t[r]="boolean"==typeof n?n:n[r];return t}function vs(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function ys(e){return e.reduce(((e,t)=>Ao(e,t.meta)),{})}function bs(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}const _s=/#/g,ws=/&/g,xs=/\//g,Es=/=/g,ks=/\?/g,Ss=/\+/g,Os=/%5B/g,Cs=/%5D/g,Rs=/%5E/g,As=/%60/g,Ps=/%7B/g,Fs=/%7C/g,js=/%7D/g,$s=/%20/g;function Ms(e){return encodeURI(""+e).replace(Fs,"|").replace(Os,"[").replace(Cs,"]")}function Is(e){return Ms(e).replace(Ss,"%2B").replace($s,"+").replace(_s,"%23").replace(ws,"%26").replace(As,"`").replace(Ps,"{").replace(js,"}").replace(Rs,"^")}function Ts(e){return function(e){return Ms(e).replace(_s,"%23").replace(ks,"%3F")}(e).replace(xs,"%2F")}function Us(e){try{return decodeURIComponent(""+e)}catch(t){}return""+e}function Vs(e){const t={};if(""===e||"?"===e)return t;const n=("?"===e[0]?e.slice(1):e).split("&");for(let r=0;re&&Is(e))):[r&&Is(r)]).forEach((e=>{void 0!==e&&(t+=(t.length?"&":"")+n,null!=e&&(t+="="+e))}))}return t}function Ls(e){const t={};for(let n in e){let r=e[n];void 0!==r&&(t[n]=Array.isArray(r)?r.map((e=>null==e?null:""+e)):null==r?r:""+r)}return t}function Bs(){let e=[];return{add:function(t){return e.push(t),()=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)}},list:()=>e,reset:function(){e=[]}}}function Ds(e,t,n,r,o){const s=r&&(r.enterCallbacks[o]=r.enterCallbacks[o]||[]);return()=>new Promise(((l,i)=>{const c=e=>{var c;!1===e?i(ls(4,{from:n,to:t})):e instanceof Error?i(e):"string"==typeof(c=e)||c&&"object"==typeof c?i(ls(2,{from:t,to:e})):(s&&r.enterCallbacks[o]===s&&"function"==typeof e&&s.push(e),l())},a=e.call(r&&r.instances[o],t,n,c);let u=Promise.resolve(a);e.length<3&&(u=u.then(c)),u.catch((e=>i(e)))}))}function qs(e,t,n,r){const o=[];for(const l of e)for(const e in l.components){let i=l.components[e];if("beforeRouteEnter"===t||l.instances[e])if("object"==typeof(s=i)||"displayName"in s||"props"in s||"__vccOpts"in s){const s=(i.__vccOpts||i)[t];s&&o.push(Ds(s,n,r,l,e))}else{let s=i();s=s.catch(console.error),o.push((()=>s.then((o=>{if(!o)return Promise.reject(new Error(`Couldn't resolve component "${e}" at "${l.path}"`));const s=(i=o).__esModule||wo&&"Module"===i[Symbol.toStringTag]?o.default:o;var i;l.components[e]=s;const c=(s.__vccOpts||s)[t];return c&&Ds(c,n,r,l,e)()}))))}}var s;return o}function zs(e){const t=pr(So),n=pr(Oo),r=Ir((()=>t.resolve(st(e.to)))),o=Ir((()=>{let{matched:e}=r.value,{length:t}=e;const o=e[t-1];let s=n.matched;if(!o||!s.length)return-1;let l=s.findIndex(Io.bind(null,o));if(l>-1)return l;let i=Ks(e[t-2]);return t>1&&Ks(o)===i&&s[s.length-1].path!==i?s.findIndex(Io.bind(null,e[t-2])):l})),s=Ir((()=>o.value>-1&&function(e,t){for(let n in t){let r=t[n],o=e[n];if("string"==typeof r){if(r!==o)return!1}else if(!Array.isArray(o)||o.length!==r.length||r.some(((e,t)=>e!==o[t])))return!1}return!0}(n.params,r.value.params))),l=Ir((()=>o.value>-1&&o.value===n.matched.length-1&&To(n.params,r.value.params)));return{route:r,href:Ir((()=>r.value.href)),isActive:s,isExactActive:l,navigate:function(n={}){return function(e){if(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;if(e.defaultPrevented)return;if(void 0!==e.button&&0!==e.button)return;if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}e.preventDefault&&e.preventDefault();return!0}(n)?t[st(e.replace)?"replace":"push"](st(e.to)):Promise.resolve()}}}const Ws=Mn({name:"RouterLink",props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"}},setup(e,{slots:t}){const n=He(zs(e)),{options:r}=pr(So),o=Ir((()=>({[Gs(e.activeClass,r.linkActiveClass,"router-link-active")]:n.isActive,[Gs(e.exactActiveClass,r.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive})));return()=>{const r=t.default&&t.default(n);return e.custom?r:Tr("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:o.value},r)}}});function Ks(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const Gs=(e,t,n)=>null!=e?e:null!=t?t:n;function Hs(e,t){if(!e)return null;const n=e(t);return 1===n.length?n[0]:n}const Xs=Mn({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},setup(e,{attrs:t,slots:n}){const r=pr(Co),o=Ir((()=>e.route||r.value)),s=pr(ko,0),l=Ir((()=>o.value.matched[s]));fr(ko,s+1),fr(Eo,l),fr(Co,o);const i=ot(c);var c;return vn((()=>[i.value,l.value,e.name]),(([e,t,n],[r,o,s])=>{t&&(t.instances[n]=e,o&&o!==t&&e&&e===r&&(t.leaveGuards.size||(t.leaveGuards=o.leaveGuards),t.updateGuards.size||(t.updateGuards=o.updateGuards))),!e||!t||o&&Io(t,o)&&r||(t.enterCallbacks[n]||[]).forEach((t=>t(e)))}),{flush:"post"}),()=>{const r=o.value,s=l.value,c=s&&s.components[e.name],a=e.name;if(!c)return Hs(n.default,{Component:c,route:r});const u=s.props[e.name],f=u?!0===u?r.params:"function"==typeof u?u(r):u:null,p=Tr(c,Ao({},f,t,{onVnodeUnmounted:e=>{e.component.isUnmounted&&(s.instances[a]=null)},ref:i}));return Hs(n.default,{Component:p,route:r})||p}}});function Js(e){const t=ms(e.routes,e);let n=e.parseQuery||Vs,r=e.stringifyQuery||Ns,o=e.history;const s=Bs(),l=Bs(),i=Bs(),c=ot(ns,!0);let a=ns;Ro&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=Po.bind(null,(e=>""+e)),f=Po.bind(null,Ts),p=Po.bind(null,Us);function d(e,s){if(s=Ao({},s||c.value),"string"==typeof e){let r=$o(n,e,s.path),l=t.resolve({path:r.path},s),i=o.createHref(r.fullPath);return Ao(r,l,{params:p(l.params),hash:Us(r.hash),redirectedFrom:void 0,href:i})}let l;"path"in e?l=Ao({},e,{path:$o(n,e.path,s.path).path}):(l=Ao({},e,{params:f(e.params)}),s.params=f(s.params));let i=t.resolve(l,s);const a=e.hash||"";i.params=u(p(i.params));const d=function(e,t){let n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}(r,Ao({},e,{hash:(h=a,Ms(h).replace(Ps,"{").replace(js,"}").replace(Rs,"^")),path:i.path}));var h;let m=o.createHref(d);return Ao({fullPath:d,hash:a,query:r===Ns?Ls(e.query):e.query},i,{redirectedFrom:void 0,href:m})}function h(e){return"string"==typeof e?$o(n,e,c.value.path):Ao({},e)}function m(e,t){if(a!==e)return ls(8,{from:t,to:e})}function g(e){return y(e)}function v(e){const t=e.matched[e.matched.length-1];if(t&&t.redirect){const{redirect:n}=t;let r="function"==typeof n?n(e):n;return"string"==typeof r&&(r=r.indexOf("?")>-1||r.indexOf("#")>-1?r=h(r):{path:r}),Ao({query:e.query,hash:e.hash,params:e.params},r)}}function y(e,t){const n=a=d(e),o=c.value,s=e.state,l=e.force,i=!0===e.replace,u=v(n);if(u)return y(Ao(h(u),{state:s,force:l,replace:i}),t||n);const f=n;let p;return f.redirectedFrom=t,!l&&function(e,t,n){let r=t.matched.length-1,o=n.matched.length-1;return r>-1&&r===o&&Io(t.matched[r],n.matched[o])&&To(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}(r,o,n)&&(p=ls(16,{to:f,from:o}),P(o,o,!0,!1)),(p?Promise.resolve(p):_(f,o)).catch((e=>is(e)?e:R(e))).then((e=>{if(e){if(is(e,2))return y(Ao(h(e.to),{state:s,force:l,replace:i}),t||f)}else e=x(f,o,!0,i,s);return w(f,o,e),e}))}function b(e,t){const n=m(e,t);return n?Promise.reject(n):Promise.resolve()}function _(e,t){let n;const[r,o,i]=function(e,t){const n=[],r=[],o=[],s=Math.max(t.matched.length,e.matched.length);for(let l=0;lIo(e,s)))?r.push(s):n.push(s));const i=e.matched[l];i&&(t.matched.find((e=>Io(e,i)))||o.push(i))}return[n,r,o]}(e,t);n=qs(r.reverse(),"beforeRouteLeave",e,t);for(const s of r)s.leaveGuards.forEach((r=>{n.push(Ds(r,e,t))}));const c=b.bind(null,e,t);return n.push(c),Qs(n).then((()=>{n=[];for(const r of s.list())n.push(Ds(r,e,t));return n.push(c),Qs(n)})).then((()=>{n=qs(o,"beforeRouteUpdate",e,t);for(const r of o)r.updateGuards.forEach((r=>{n.push(Ds(r,e,t))}));return n.push(c),Qs(n)})).then((()=>{n=[];for(const r of e.matched)if(r.beforeEnter&&t.matched.indexOf(r)<0)if(Array.isArray(r.beforeEnter))for(const o of r.beforeEnter)n.push(Ds(o,e,t));else n.push(Ds(r.beforeEnter,e,t));return n.push(c),Qs(n)})).then((()=>(e.matched.forEach((e=>e.enterCallbacks={})),n=qs(i,"beforeRouteEnter",e,t),n.push(c),Qs(n)))).then((()=>{n=[];for(const r of l.list())n.push(Ds(r,e,t));return n.push(c),Qs(n)})).catch((e=>is(e,8)?e:Promise.reject(e)))}function w(e,t,n){for(const r of i.list())r(e,t,n)}function x(e,t,n,r,s){const l=m(e,t);if(l)return l;const i=t===ns,a=Ro?history.state:{};n&&(r||i?o.replace(e.fullPath,Ao({scroll:i&&a&&a.scroll},s)):o.push(e.fullPath,s)),c.value=e,P(e,t,n,i),A()}let E;function k(){E=o.listen(((e,t,n)=>{let r=d(e);const s=v(r);if(s)return void y(Ao(s,{replace:!0}),r).catch(Fo);a=r;const l=c.value;var i,u;Ro&&(i=Ho(l.fullPath,n.delta),u=Ko(),Xo.set(i,u)),_(r,l).catch((e=>is(e,12)?e:is(e,2)?(y(e.to,r).catch(Fo),Promise.reject()):(n.delta&&o.go(-n.delta,!1),R(e)))).then((e=>{(e=e||x(r,l,!1))&&n.delta&&o.go(-n.delta,!1),w(r,l,e)})).catch(Fo)}))}let S,O=Bs(),C=Bs();function R(e){return A(e),C.list().forEach((t=>t(e))),Promise.reject(e)}function A(e){S||(S=!0,k(),O.list().forEach((([t,n])=>e?n(e):t())),O.reset())}function P(t,n,r,o){const{scrollBehavior:s}=e;if(!Ro||!s)return Promise.resolve();let l=!r&&function(e){const t=Xo.get(e);return Xo.delete(e),t}(Ho(t.fullPath,0))||(o||!r)&&history.state&&history.state.scroll||null;return Ot().then((()=>s(t,n,l))).then((e=>e&&Go(e))).catch(R)}const F=e=>o.go(e);let j;const $=new Set;return{currentRoute:c,addRoute:function(e,n){let r,o;return ts(e)?(r=t.getRecordMatcher(e),o=n):o=e,t.addRoute(o,r)},removeRoute:function(e){let n=t.getRecordMatcher(e);n&&t.removeRoute(n)},hasRoute:function(e){return!!t.getRecordMatcher(e)},getRoutes:function(){return t.getRoutes().map((e=>e.record))},resolve:d,options:e,push:g,replace:function(e){return g(Ao(h(e),{replace:!0}))},go:F,back:()=>F(-1),forward:()=>F(1),beforeEach:s.add,beforeResolve:l.add,afterEach:i.add,onError:C.add,isReady:function(){return S&&c.value!==ns?Promise.resolve():new Promise(((e,t)=>{O.add([e,t])}))},install(e){e.component("RouterLink",Ws),e.component("RouterView",Xs),e.config.globalProperties.$router=this,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>st(c)}),Ro&&!j&&c.value===ns&&(j=!0,g(o.location).catch((e=>{})));const t={};for(let r in ns)t[r]=Ir((()=>c.value[r]));e.provide(So,this),e.provide(Oo,He(t)),e.provide(Co,c);let n=e.unmount;$.add(e),e.unmount=function(){$.delete(e),$.size<1&&(E(),c.value=ns,j=!1,S=!1),n()}}}}function Qs(e){return e.reduce(((e,t)=>e.then((()=>t()))),Promise.resolve())}export{zn as F,or as a,ir as b,Yn as c,Mn as d,lr as e,Ur as f,mo as g,An as h,co as i,ao as j,Nt as k,go as l,Js as m,es as n,Jn as o,_o as p,Bn as r,u as t,io as v,zt as w}; diff --git a/build/public/index.html b/build/public/index.html index 64abc0c..b142203 100644 --- a/build/public/index.html +++ b/build/public/index.html @@ -4,9 +4,9 @@ 🧩 jigsaw.hyottoko.club - - - + + +
diff --git a/build/server/main.js b/build/server/main.js index d990551..bc60a57 100644 --- a/build/server/main.js +++ b/build/server/main.js @@ -1925,7 +1925,28 @@ app.get('/api/index-data', (req, res) => { gamesFinished: games.filter(g => !!g.finished), }); }); -app.post('/upload', (req, res) => { +app.post('/api/save-image', bodyParser.json(), (req, res) => { + const data = req.body; + db.update('images', { + title: data.title, + }, { + id: data.id, + }); + db.delete('image_x_category', { image_id: data.id }); + if (data.category) { + const title = data.category; + const slug = Util.slug(title); + const id = db.upsert('categories', { slug, title }, { slug }, 'id'); + if (id) { + db.insert('image_x_category', { + image_id: data.id, + category_id: id, + }); + } + } + res.send({ ok: true }); +}); +app.post('/api/upload', (req, res) => { upload(req, res, async (err) => { if (err) { log.log(err); diff --git a/src/frontend/components/EditImageDialog.vue b/src/frontend/components/EditImageDialog.vue new file mode 100644 index 0000000..311252a --- /dev/null +++ b/src/frontend/components/EditImageDialog.vue @@ -0,0 +1,132 @@ + + + +// TODO: scoped vs .edit-image-dialog + diff --git a/src/frontend/components/ImageLibrary.vue b/src/frontend/components/ImageLibrary.vue index 4ba4ef4..aea50f6 100644 --- a/src/frontend/components/ImageLibrary.vue +++ b/src/frontend/components/ImageLibrary.vue @@ -1,6 +1,6 @@ diff --git a/src/frontend/components/ImageTeaser.vue b/src/frontend/components/ImageTeaser.vue index 23d744c..770de91 100644 --- a/src/frontend/components/ImageTeaser.vue +++ b/src/frontend/components/ImageTeaser.vue @@ -1,5 +1,10 @@ + diff --git a/src/frontend/views/NewGame.vue b/src/frontend/views/NewGame.vue index b2332a6..724b420 100644 --- a/src/frontend/views/NewGame.vue +++ b/src/frontend/views/NewGame.vue @@ -30,8 +30,9 @@ in jigsawpuzzles.io - + + @@ -41,6 +42,7 @@ import { defineComponent } from 'vue' import ImageLibrary from './../components/ImageLibrary.vue' import NewImageDialog from './../components/NewImageDialog.vue' +import EditImageDialog from './../components/EditImageDialog.vue' import NewGameDialog from './../components/NewGameDialog.vue' import { GameSettings, Image } from '../../common/GameCommon' import Util from '../../common/Util' @@ -49,6 +51,7 @@ export default defineComponent({ components: { ImageLibrary, NewImageDialog, + EditImageDialog, NewGameDialog, }, data() { @@ -86,22 +89,46 @@ export default defineComponent({ async filtersChanged () { await this.loadImages() }, - imageClicked (image: Image) { + onImageClicked (image: Image) { this.image = image this.dialog = 'new-game' }, + onImageEditClicked (image: Image) { + this.image = image + this.dialog = 'edit-image' + }, async uploadImage (data: any) { const formData = new FormData(); formData.append('file', data.file, data.file.name); formData.append('title', data.title) formData.append('category', data.category) - const res = await fetch('/upload', { + const res = await fetch('/api/upload', { method: 'post', body: formData, }) return await res.json() }, + async saveImage (data: any) { + const res = await fetch('/api/save-image', { + method: 'post', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + id: data.id, + title: data.title, + category: data.category, + }), + }) + return await res.json() + }, + async onSaveImageClick(data: any) { + await this.saveImage(data) + this.dialog = '' + await this.loadImages() + }, async postToGalleryClick(data: any) { await this.uploadImage(data) this.dialog = '' diff --git a/src/server/main.ts b/src/server/main.ts index 6bc3903..146c547 100644 --- a/src/server/main.ts +++ b/src/server/main.ts @@ -90,7 +90,36 @@ app.get('/api/index-data', (req, res) => { }) }) -app.post('/upload', (req, res) => { +interface SaveImageRequestData { + id: number + title: string + category: string +} +app.post('/api/save-image', bodyParser.json(), (req, res) => { + const data = req.body as SaveImageRequestData + db.update('images', { + title: data.title, + }, { + id: data.id, + }) + + db.delete('image_x_category', { image_id: data.id }) + + if (data.category) { + const title = data.category + const slug = Util.slug(title) + const id = db.upsert('categories', { slug, title }, { slug }, 'id') + if (id) { + db.insert('image_x_category', { + image_id: data.id, + category_id: id, + }) + } + } + + res.send({ ok: true }) +}) +app.post('/api/upload', (req, res) => { upload(req, res, async (err: any) => { if (err) { log.log(err) diff --git a/vite.config.js b/vite.config.js index 715cf12..d0c52f8 100644 --- a/vite.config.js +++ b/vite.config.js @@ -13,7 +13,7 @@ export default vite.defineConfig({ }, server: { proxy: { - '^/((api|uploads)/.*|upload)': { + '^/(api|uploads)/.*': { target: `http://${cfg.http.hostname}:${cfg.http.port}`, secure: false, },