diff options
author | Kyle Gunger <corechg@gmail.com> | 2020-09-15 20:03:52 -0400 |
---|---|---|
committer | Kyle Gunger <corechg@gmail.com> | 2020-09-15 20:03:52 -0400 |
commit | 2ce432034eb35f763182de03fb7b42d2a07afc4b (patch) | |
tree | e57d7bc40d12c32c79f1f16ba669a5426ae80525 | |
parent | 20201f77b5cf5cbb1c70b1cc51c4108d620a3202 (diff) |
Webcards update from local git server
-rw-r--r-- | webcards/client.html | 62 | ||||
-rw-r--r-- | webcards/images/vanilla.png | bin | 0 -> 3191 bytes | |||
-rw-r--r-- | webcards/index.html | 78 | ||||
-rw-r--r-- | webcards/scripts/cards/card.js | 123 | ||||
-rw-r--r-- | webcards/scripts/cards/deck.js | 180 | ||||
-rw-r--r-- | webcards/scripts/cards/drag.js | 111 | ||||
-rw-r--r-- | webcards/scripts/client.js | 146 | ||||
-rw-r--r-- | webcards/scripts/cookie.js | 27 | ||||
-rw-r--r-- | webcards/scripts/gui/chat.js | 149 | ||||
-rw-r--r-- | webcards/scripts/gui/input.js | 182 | ||||
-rw-r--r-- | webcards/scripts/gui/lobby.js | 212 | ||||
-rw-r--r-- | webcards/scripts/gui/table.js | 75 | ||||
-rw-r--r-- | webcards/scripts/socket/message.js | 18 | ||||
-rw-r--r-- | webcards/scripts/socket/sock.js | 48 | ||||
-rw-r--r-- | webcards/scripts/theme.js | 32 | ||||
-rw-r--r-- | webcards/styles/client/base.css | 122 | ||||
-rw-r--r-- | webcards/styles/client/card.css | 48 | ||||
-rw-r--r-- | webcards/styles/client/desktop.css | 2 | ||||
-rw-r--r-- | webcards/styles/client/mobile.css | 4 | ||||
-rw-r--r-- | webcards/styles/home/base.css | 56 | ||||
-rw-r--r-- | webcards/styles/input.css | 6 | ||||
-rw-r--r-- | webcards/styles/themes/colors-base.css | 26 | ||||
-rw-r--r-- | webcards/styles/themes/colors-dark.css | 26 |
23 files changed, 1164 insertions, 569 deletions
diff --git a/webcards/client.html b/webcards/client.html index e9cf664..c5d7cc7 100644 --- a/webcards/client.html +++ b/webcards/client.html @@ -34,6 +34,7 @@ <script src="scripts/gui/input.js"></script> <script src="scripts/gui/lobby.js"></script> <script src="scripts/gui/table.js"></script> + <script src="scripts/gui/chat.js"></script> <script src="scripts/socket/message.js"></script> <script src="scripts/socket/sock.js"></script> @@ -45,14 +46,14 @@ <body> - <div class="table" state="closed" onmouseup="md.stopDraggingAll()"> + <div class="table" state="closed"> </div> <div class="topbar" style="height: auto;"> <div class="top-buttons"> - <button id="newgame" class="top-button" onclick="game.lob.newGame()"></button> - <button id="settings" class="top-button" onclick="game.lob.mobileSettings()"></button> + <button id="newgame" class="top-button" onclick="game.lobby.newGame()"></button> + <button id="settings" class="top-button" onclick="game.lobby.mobileSettings()"></button> <button id="reset" class="top-button" onclick="game.reset()"></button> </div> @@ -113,50 +114,25 @@ </div> </div> + <div class="chat"> + <button class="toggle-chat">Toggle Chat</button> + + <div class="chat-select"> + </div> + + <div class="chat-text"> + </div> + + <div class="chat-input"> + <input type="text" placeholder="Chat..."/> + <button>Send</button> + </div> + </div> + <script> var params = new URLSearchParams((new URL(window.location)).search); var game = new Client(params.get("s"), params.get("g")); setTimeout(game.init.bind(game), 100); - - - // Live testing purposes only - var md = new MultiDrag(); - var c1 = new Card({ - all: [ - { - type: "image", - image: "assets/standard/diamond.svg" - } - ] - }); - var c2 = new Card({ - all: [ - { - type: "image", - image: "assets/standard/heart.svg" - }, - { - type: "image", - image: "assets/standard/heart.svg" - }, - { - type: "image", - image: "assets/standard/heart.svg" - } - ] - }); - var d = new Deck(); - d.appendCard(c2); - d.appendCard(c1); - function test() { - c1.e.addEventListener("mousedown", md.startDragging.bind(md)); - c1.e.addEventListener("mouseup", md.stopDraggingAll.bind(md)); - c2.e.addEventListener("mousedown", md.startDragging.bind(md)); - c2.e.addEventListener("mouseup", md.stopDraggingAll.bind(md)); - - game.tab.root.append(d.e); - game.tab.openTable(); - } </script> </body> diff --git a/webcards/images/vanilla.png b/webcards/images/vanilla.png Binary files differnew file mode 100644 index 0000000..26b3011 --- /dev/null +++ b/webcards/images/vanilla.png diff --git a/webcards/index.html b/webcards/index.html index d34a950..2f20bc5 100644 --- a/webcards/index.html +++ b/webcards/index.html @@ -35,21 +35,84 @@ <p style="font-size: 30px; font-weight: normal;">Web<span style="color: #0084ff; font-weight: bold;">Cards</span></p> <div> <div class="input-container" tabindex="0" type="select"> - <div id="protocol" tabindex="0" selected="0" class="input-select"> - <div value="ws://" onmousedown="customSelectOption(this)" selected="true">ws</div> - <div value="wss://" onmousedown="customSelectOption(this)">wss</div> + <div id="protocol" tabindex="0" selected="1" class="input-select"> + <div value="ws://" onmousedown="MakeInput.selOption(this)">ws</div> + <div value="wss://" onmousedown="MakeInput.selOption(this)" selected="true">wss</div> </div> </div> - <input id="addr" type="text" value="127.0.0.1"> + <input id="addr" type="text" value="localhost"> <input id="port" type="number" value="4040"> </div> - <button id="conn" onclick="connect()">Connect</a> + <button id="conn" onclick="connect()">Connect</button> + + <div id="prev" class="prev"> + + </div> + + <a style="border: none; padding: 0; display: contents; margin: 0;" href="http://vanilla-js.com/"><img src="images/vanilla.png"></a> </div> <script> + var prev = Cookies.getCookie("prevAddr"); + var prevEl = document.getElementById("prev"); + + function hasAddr(url) { + let urls = prev.split(","); + + for(let i in urls) + { + if(urls[i] == url) + return true; + } + + return false; + } + + function addAddr(url) { + if(hasAddr(url)) + return; + + if(prev != "") + prev = prev + "," + url; + else + prev = url; + + Cookies.setYearCookie("prevAddr", prev); + } + + function delAddr(el, btn) { + let url = el.innerText; + let urls = prev.split(","); + urls.splice(urls.indexOf(url), 1); + Cookies.setCookie("prevAddr", urls.join()); + el.remove(); + btn.remove(); + prev = Cookies.getCookie("prevAddr"); + } + + let urls = prev.split(","); + for(let i in urls) { + if(urls[i] == "") + continue; + + let a = document.createElement("a"); + a.innerText = urls[i]; + a.href = "client.html?s=" + urls[i] + "&g=-1"; + + let b = document.createElement("button"); + b.innerText = "X"; + b.onclick = delAddr.bind(null, a, b); + + prevEl.appendChild(a); + prevEl.append(b); + } + + </script> + + <script> var proto = document.getElementById("protocol"); var addr = document.getElementById("addr"); var port = document.getElementById("port"); @@ -60,9 +123,10 @@ //p.onchange = updateLink; function connect() { - var url = "client.html?s=" + customSelectValue(proto) + addr.value + ":" + port.value + "&g=-1"; + let concat = MakeInput.selValue(proto) + addr.value + ":" + port.value; + addAddr(concat); //c.setAttribute("href", url); - window.location = url; + window.location = "client.html?s=" + concat + "&g=-1"; } </script> </body> diff --git a/webcards/scripts/cards/card.js b/webcards/scripts/cards/card.js index 932a22c..750d124 100644 --- a/webcards/scripts/cards/card.js +++ b/webcards/scripts/cards/card.js @@ -1,103 +1,110 @@ +'use strict'; + +// Possible positions of content in a card const CardPos = ["top", "topl", "topr", "mid", "midt", "midb", "bot", "botl", "botr", "all"]; // Card class represents one card. // Every card should have a deck. // Use deck.appendCard or deck.prependCard to make a card visible -function Card (data) { - this.e = document.createElement("card"); - this.generateElements(data); - this.e.style.left = "0px"; - this.e.style.top = "0px"; -} - -// Internal -Card.prototype = { - // Main generation func, only for use in contructor - generateElements: function (data) { - while(this.e.firstElementChild != null) - this.e.firstElementChild.remove(); - - switch (typeof data) { - case "object": - this.generateObjectCard(data, this.e); - break; - case "string": - this.generateBasicCard(data, this.e); - break; - default: - this.generateErrorCard(this.e); - } - }, +class Card { + constructor (data) + { + this.e = document.createElement("card"); + this.generateElements(data); + this.e.style.left = "0px"; + this.e.style.top = "0px"; + } // Generate a card with basic text only - generateBasicCard: function (data, el) { + static generateBasicCard (data, el) + { let t = document.createElement("carea"); t.className = "mid"; t.innerText = data; el.appendChild(t); - }, - - // Generate a card with rich visuals - generateObjectCard: function (data, el) { - - // Check for an asset URL - if (typeof data.assetURL != "string") { - data.assetURL = ""; - } - - // Set card styles - for (let i in data.style) { - el.style[i] = data.style[i]; - } + } - // Generate card areas. - for (let i in CardPos) { - if (typeof data[CardPos[i]] == "object") - el.appendChild(this.generateCArea(data[CardPos[i]], CardPos[i], data.assetURL)); - } - }, + // Generate a card with a simple error message. + static generateErrorCard (el) + { + Card.generateBasicCard("Card Error: data", el); + } - generateCArea: function (data, carea, assetURL) { + // Generate an area of a card + static generateCArea (data, carea, assetURL) + { // Create and set area let area = document.createElement("carea"); area.className = carea; // Create inner area text and images - for (let i in data) { + for (let i in data) + { if (i == "style") + { for (j in data.style) area.style[j] = data.style[j]; + } - if (data[i].type == "text") { + if (data[i].type == "text") + { let e = document.createElement("ctext"); e.innerText = data[i].text; - for (let j in data[i].style) { + for (let j in data[i].style) e.style[j] = data[i].style[j]; - } area.appendChild(e); - } else if (data[i].type == "image") { + } + else if (data[i].type == "image") + { let e = document.createElement("cimage"); e.style.backgroundImage = "url(\"" + assetURL + data[i].image + "\")"; + for (let j in data[i].style) + e.style[j] = data[i].style[j]; + area.appendChild(e); } } return area; - }, + } + + // Generate a card with rich visuals + static generateObjectCard (data, el) + { + // Generate card areas. + for (let i in CardPos) + { + if (typeof data[CardPos[i]] == "object") + el.appendChild(this.generateCArea(data[CardPos[i]], CardPos[i], data.assetURL)); + } + } - generateErrorCard: function(el) + generateElements (data) { - this.generateBasicCard("Card Error: data", el); - }, + while(this.e.firstElementChild != null) + this.e.firstElementChild.remove(); - setPos: function(p) + switch (typeof data) + { + case "object": + Card.generateObjectCard(data, this.e); + break; + case "string": + Card.generateBasicCard(data, this.e); + break; + default: + Card.generateErrorCard(this.e); + } + } + + setPos (p) { this.e.style.setProperty("--cpos", p); } -};
\ No newline at end of file +} diff --git a/webcards/scripts/cards/deck.js b/webcards/scripts/cards/deck.js index a02142d..6da24b0 100644 --- a/webcards/scripts/cards/deck.js +++ b/webcards/scripts/cards/deck.js @@ -1,67 +1,87 @@ +'use strict'; + // Deck class represents multiple cards. // Can be arranged in multiple ways. -function Deck (options = {mode: "stack", smode: "one", sct: 0, pos: [0, 0]}){ - this.cards = []; - - // View mode - // infdraw - infinite draw. always appears as if there are multiple cards - // stack - stack mode - // strip - // horizontal - // left (strip-hl) - // right (strip-hr) - // vertical - // up (strip-vu) - // down (strip-vd) - this.inf = options.mode == "infdraw"; - - // Select mode - controls what other cards are selected when one card is selected - // above - selectes cards above the selected one - // below - selects cards below the selected one - // around - selects cards above and below - // one - selects only card chosen - // all - selects all cards when card selected - this.smode = options.smode; - - // Select count (negative defaults to 0) - // above - controls number of cards above clicked are selected - // below - controls number of cards below clicked are selected - // around - // number - number above and below selected - // array - [first number: number above selected] [second number: number below selected] - // one - no effect - // all - no effect - this.sct = options.sct > 0 ? options.sct : 0; +// Decks work as FIFO +class Deck { - // Position - // array of where the deck is centered - this.x = options.pos[0]; - this.y = options.pos[1]; - - this.e = document.createElement("deck"); - this.e.style.left = this.x + "px"; - this.e.style.top = this.y + "px"; - this.e.setAttribute("mode", options.mode); -} + cards = []; + inf = false; + smode = ""; + sct = 0; + x = 0; + y = 0; + e = null; + + constructor(options = {mode: "stack", smode: "one", sct: 0, pos: [0, 0]}) + { + // View mode + // infdraw - infinite draw. always appears as if there are multiple cards + // stack - stack mode + // strip + // horizontal + // left (strip-hl) + // right (strip-hr) + // vertical + // up (strip-vu) + // down (strip-vd) + this.inf = options.mode == "infdraw"; + + // Select mode - controls what other cards are selected when one card is selected + // above - selectes cards above the selected one + // below - selects cards below the selected one + // around - selects cards above and below + // one - selects only card chosen + // all - selects all cards when card selected + this.smode = options.smode; + + // Select count (negative defaults to 0) + // above - controls number of cards above clicked are selected + // below - controls number of cards below clicked are selected + // around + // number - number above and below selected + // array - [first number: number above selected] [second number: number below selected] + // one - no effect + // all - no effect + this.sct = options.sct > 0 ? options.sct : 0; + + // Position + // array of where the deck is centered + this.x = options.pos[0]; + this.y = options.pos[1]; + + this.e = document.createElement("deck"); + this.e.style.left = this.x + "px"; + this.e.style.top = this.y + "px"; + this.e.setAttribute("mode", options.mode); + } -//Decks work as FIFO -Deck.prototype = { - // Add a card to the front of the deck - appendCard: function(card) { + updatePos() + { + let len = this.cards.length - 1; + for(let i in this.cards) + this.cards[i].setPos(len-i); + this.updateCount(); + } + + appendCard(card) + { this.cards.push(card); this.e.appendChild(card.e); this.updatePos(); - }, + + } - // Add a card to the back of the deck - prependCard: function(card) { + prependCard(card) + { this.cards.unshift(card); this.e.prepend(card.e); card.setPos(this.cards.length - 1); - }, + this.updateCount(); + } - // Add a card at the index specified - addCardAt: function(card, index) { + addCardAt(card, index) + { if(index < 0 || index > this.cards.length) return @@ -74,11 +94,12 @@ Deck.prototype = { temp[temp.length - 1].e.after(card.e); temp.push(card); this.cards.unshift(...temp); + this.updatePos(); } - }, + } - // Swap the cards at the specified indexes - swapCard: function(index1, index2) { + swapCards(index1, index2) + { if(index1 < 0 || index1 >= this.cards.length || index2 < 0 || index2 >= this.cards.length) return @@ -88,31 +109,38 @@ Deck.prototype = { this.cards[index1 - 1].e.after(this.cards[index1]); this.cards[index2 - 1].e.after(this.cards[index2]); - }, - - // Remove the card at the front of the deck (index length - 1), returns the card removed (if any) - removeFront: function() { - return this.removeCard(this.cards.length - 1); - }, - - // Remove the card at the back of the deck (index 0), returns the card removed (if any) - removeBack: function() { - return this.removeCard(0); - }, - - // Remove a card from the deck, returning the card element - removeCard: function(index) { + } + removeCard(index) + { if(index < 0 || index >= this.cards.length) return this.e.removeChild(this.cards[index].e); - return this.cards.splice(index, 1)[0]; - }, + let c = this.cards.splice(index, 1)[0]; - updatePos: function() { - let len = this.cards.length - 1; - for(let i in this.cards) - this.cards[i].setPos(len-i); + this.updatePos(); + return c; + } + + removeFront() + { + return this.removeCard(this.cards.length - 1); + } + + removeBack() + { + return this.removeCard(0); } -};
\ No newline at end of file + + updateCount () + { + this.e.style.setProperty("--ccount", this.cards.length - 1); + } + + isInside(x, y) + { + var rect = this.e.getBoundingClientRect(); + return (x > rect.left && x < rect.right && y > rect.top && y < rect.bottom) + } +} diff --git a/webcards/scripts/cards/drag.js b/webcards/scripts/cards/drag.js index 54fb797..3b02eff 100644 --- a/webcards/scripts/cards/drag.js +++ b/webcards/scripts/cards/drag.js @@ -1,17 +1,23 @@ -function MultiDrag() { - this.del = false; - this.drag = []; - window.addEventListener("mousemove", this.update.bind(this)); - document.body.addEventListener("mouseleave", this.stopDraggingAll.bind(this)); -} +'use strict'; -MultiDrag.prototype = { - addDragEl: function(el, ox, oy, px, py, pt) { +class MultiDrag extends EventTarget { + del = false; + drag = []; + cbs = []; + + constructor() { + super(); + + window.addEventListener("mousemove", this.update.bind(this)); + document.body.addEventListener("mouseleave", this.stopDraggingAll.bind(this)); + } + + addDragEl(el, ox, oy, px, py, pt) { if(this.del) return; - + el.style.transitionDuration = "0.04s"; - + this.drag.push({ e: el, osx: ox, @@ -20,76 +26,103 @@ MultiDrag.prototype = { pry: py, ptd: pt }); - + return this.drag.length - 1; - }, + } - dragging: function(e) { + dragging(e) { for(let i in this.drag) { if(this.drag[i].e == e) return true; } return false; - }, + } - startDragging: function(e) { + startDragging(e) { if(this.del) return; - + console.log(e); - + if(e.button != 0) return; - - let pos - if(e.target.parentElement != null) - pos = e.target.parentElement.getBoundingClientRect(); - else - pos = e.target.getBoundingClientRect(); + + this.dispatchEvent(new Event("dragstart", {target: e.target})); return this.addDragEl( e.target, - e.pageX, - e.pageY, + e.pageX - parseInt(e.target.style.left), + e.pageY - parseInt(e.target.style.top), e.target.style.left, e.target.style.top, e.target.style.transitionDuration ); - }, - - stopDragging: function(i) { + } + + stopDragging(i) { + if(this.del) + return; + this.del = true; - + if (i < 0 || i >= this.drag.length) return; + var cap = {target: null, x: 0, y: 0}; + this.drag[i].e.style.transitionDuration = this.drag[i].ptd; + + cap.x = parseInt(this.drag[i].e.style.left); this.drag[i].e.style.left = this.drag[i].prx; + + cap.y = parseInt(this.drag[i].e.style.top); this.drag[i].e.style.top = this.drag[i].pry; + + cap.target = this.drag.splice(i, 1).e; + + this.del = false; - this.drag.splice(i, 1); + this.dispatchEvent(new Event("dragstop", cap)); + } - this.del = false; - }, + stopDraggingEl(el) { + for(let d of this.drag) { + if(d.e === el) + this.stopDragging(this.drag.indexOf(d)); + } + } - stopDraggingAll: function() { + stopDraggingAll() { + if(this.del) + return; + this.del = true; - + while (this.drag.length > 0) { this.drag[0].e.style.transitionDuration = this.drag[0].ptd; this.drag[0].e.style.left = this.drag[0].prx; this.drag[0].e.style.top = this.drag[0].pry; - + this.drag.shift(); } - + this.del = false; - }, - update: function(e) { + this.dispatchEvent(new Event("dragstopall")); + } + + update(e) { for (let i = 0; i < this.drag.length && !this.del; i++) { this.drag[i].e.style.left = e.pageX - this.drag[i].osx + "px"; this.drag[i].e.style.top = e.pageY - this.drag[i].osy + "px"; } } -};
\ No newline at end of file + + addTarget(e) { + e.addEventListener("mousedown", this.startDragging.bind(this)); + e.addEventListener("mouseup", this.stopDraggingEl.apply(this, [e])) + } + + removeTarget (e) { + } +}
\ No newline at end of file diff --git a/webcards/scripts/client.js b/webcards/scripts/client.js index 0bf2e75..acb3d90 100644 --- a/webcards/scripts/client.js +++ b/webcards/scripts/client.js @@ -1,110 +1,128 @@ +const VERSION = "1.0.0"; + // Client acts as the message hub for the whole game. // WebSocket messages come into Client and Client redirects them to the lobby or table based on the state of the game. // Client also performs the handshake for first starting the connection and messages everyone if the connection errors or closes. -function Client(serveraddr, game) { - this.state = "handshake"; - - this.soc = new SockWorker(serveraddr, "1", this.cb.bind(this)); +class Client{ - this.lob = new Lobby(document.getElementsByClassName("lobby")[0], this.soc); - this.tab = new Table(document.getElementsByClassName("table")[0], this.soc); + constructor (serveraddr, game) + { + this.socket = new SockWorker(serveraddr, VERSION); + this.socket.addEventListener("error", this.socketError.bind(this)); + this.socket.addEventListener("closed", this.socketClose.bind(this)); + this.socket.addEventListener("handshake", this.handshake.bind(this)); + this.socket.addEventListener("menu", this.menu.bind(this)); + this.socket.addEventListener("game", this.game.bind(this)); - this.game = game; -} + this.lobby = new Lobby(document.getElementsByClassName("lobby")[0], this.socket); + + this.drag = new MultiDrag(); + + this.table = new Table(document.getElementsByClassName("table")[0], this.drag, this.socket); + + this.chat = new Chat(document.getElementsByClassName("chat")[0], this.socket); + this.chat.addChannel("global"); + this.chat.switchChannel("global"); + + this.game = game; + } -Client.prototype = { // Initialize the connection - init: function() { - this.soc.init(); - }, - - // Entry point for a message from the server. - // If it's a close message, we close the game if it is open and change the lobby to reflect the error/close. - cb: function(m) { - console.log(m); - - if(m.type == "error" || m.type == "closed") { - var t = m.type; - t = t[0].toUpperCase() + t.slice(1) - this.lob.setState(t, "closed", this.soc.server); - this.tab.handleClose(); - return; - } + init () + { + this.socket.init(); + } - switch(this.state) { - case "handshake": - this.lob.setState("Connected", "ok", this.soc.server); - this.handshake(m); - break; - case "lobby": - this.lobby(m); - break; - case "game": - break; - } - }, + // Callbacks for if the socket fails or closes + + socketError() { + this.lobby.setState("Error", "closed", this.socket.server); + this.table.handleClose(); + } - // Called when negotiating with the server for the first time and we are determining versions - handshake: function(m) { + socketClose() { + this.lobby.setState("Closed", "closed", this.socket.server); + this.table.handleClose(); + } + + // Callback when negotiating with the server for the first time and we are determining versions + handshake (m) + { switch (m.type) { case "verr": - this.soc.close(); + this.socket.close(); alert(`Error connecting to server: version of client (${this.version}) not accepted.`); console.error(`Error connecting to server: version of client (${this.version}) not accepted.`); console.error(m.data); return; - case "lobby": - this.state = "lobby"; - this.soc.send("ready", ""); + case "ready": + this.socket.send("ready", ""); return; } - }, + } - // Lobby switch, called when in the lobby and a message arrives from the server - lobby: function (m) { + // Menu switch, called when in the lobby and a message arrives from the server + menu (m) + { switch (m.type) { case "plist": - this.lob.packList(m.data); + this.lobby.packList(m.data); break; case "glist": - this.lob.gameList(m.data, this.game); + this.lobby.gameList(m.data, this.game); this.game = null; break; case "players": - this.lob.players(m.data); + this.lobby.players(m.data); break; case "gdel": - this.lob.removeGame(m.data); + this.lobby.removeGame(m.data); break; case "gadd": - this.lob.addGame(m.data); + this.lobby.addGame(m.data); break; case "pdel": - this.lob.removePlayer(m.data); + this.lobby.removePlayer(m.data); break; case "padd": - this.lob.addPlayer(m.data); + this.lobby.addPlayer(m.data); break; case "pmove": - this.lob.movePlayer(m.data); + this.lobby.movePlayer(m.data); break; } - }, + } // Game switch, called when in game and a message arrives from the server - game: function (m) { + game (m) + { switch (m.type) { } - }, + } - // Reset the lobby and table, then attempt to reopen the connection to the server. - reset: function() { - this.state = "handshake"; + // Callback when a chat event is recieved from the server + chat (m) + { + switch (m.type) { + case "delchan": + this.chat.deleteChannel(m.data); + break; + case "newchan": + this.chat.addChannel(m.data); + break; + + case "message": + this.chat.recieveMessage(m.data.type, m.data.data); + } + } - this.lob.reset(); - this.tab.reset(); + // Reset the lobby and table, then attempt to reopen the connection to the server. + reset () + { + this.lobby.reset(); + this.table.reset(); - this.soc.init(); + this.socket.init(); } -}; +} diff --git a/webcards/scripts/cookie.js b/webcards/scripts/cookie.js index 2eb5977..d614af7 100644 --- a/webcards/scripts/cookie.js +++ b/webcards/scripts/cookie.js @@ -1,8 +1,7 @@ -function CookieManager() { -} +'use strict'; -CookieManager.prototype = { - getCookie: function(name){ +class Cookies { + static getCookie(name){ let cookies = document.cookie.split(";"); for(let i in cookies) { let cname = cookies[i].trim().split("=")[0]; @@ -11,9 +10,9 @@ CookieManager.prototype = { } } return ""; - }, + } - setCookie: function(name, value, data={}) { + static setCookie(name, value, data = {}) { let extra = ""; for(let key in data) @@ -22,18 +21,16 @@ CookieManager.prototype = { } document.cookie = name + "=" + value + extra; - }, + } - setYearCookie: function(name, value) { + static setYearCookie(name, value) { var date = new Date(Date.now()); date.setFullYear(date.getFullYear() + 1); - this.setCookie(name, value, {expires: date.toUTCString()}); - }, + Cookies.setCookie(name, value, {expires: date.toUTCString()}); + } - removeCookie: function(name) { + static removeCookie(name) { var date = new Date(0); - this.setCookie(name, "", {expires: date.toUTCString()}); + Cookies.setCookie(name, "", {expires: date.toUTCString()}); } -}; - -var Cookies = new CookieManager();
\ No newline at end of file +} diff --git a/webcards/scripts/gui/chat.js b/webcards/scripts/gui/chat.js new file mode 100644 index 0000000..68b8f5d --- /dev/null +++ b/webcards/scripts/gui/chat.js @@ -0,0 +1,149 @@ +'use strict'; + +class Chat { + constructor(e) + { + this.chats = []; + this.root = e; + e.getElementsByClassName("toggle-chat")[0].onclick = this.toggle.bind(this); + } + + getChannel (name) + { + for(let i in this.chats) + { + if (this.chats[i].name == name) + { + return this.chats[i]; + } + } + + return null; + } + + isActive (name) + { + for(let i in this.chats) + { + if (this.chats[i].name == name) + { + if(this.chats[i].btn.getAttribute("active") == "true") + return true; + return false; + } + } + + return false; + } + + addChannel (name, follow = true) + { + if(this.getChannel(name) != null) + return; + + let d = document.createElement("div"); + let b = document.createElement("button"); + + this.root.getElementsByClassName("chat-select")[0].appendChild(b); + + b.setAttribute("active", false); + + b.onclick = this.switchChannel.bind(this, name); + + b.innerText = name[0].toUpperCase() + name.slice(1).toLowerCase(); + + d.className = "chat-text"; + + this.chats.push({name: name, e: d, btn: b}); + + if(follow) + this.switchChannel(name) + } + + getActiveChannel () + { + for(let i in this.chats) + { + if (this.chats[i].btn.getAttribute("active") == "true") + { + return this.chats[i]; + } + } + + return null; + } + + switchChannel (name) + { + let c = this.getChannel(name); + + if(c == null) + return; + + if(this.getActiveChannel() != null) + this.getActiveChannel().btn.setAttribute("active", false); + + c.btn.setAttribute("active", true); + var ct = this.root.getElementsByClassName("chat-text")[0]; + ct.replaceWith(c.e); + + c.e.scroll({ + top: c.e.scrollTopMax + }); + } + + recieveMessage (channel, msg) + { + let c = this.getChannel(channel); + + if(c == null) + return; + + let autoscroll = c.e.scrollTop == c.e.scrollTopMax; + + let csp = document.createElement("span"); + csp.style.color = msg.color; + csp.innerText = msg.user + ": "; + let tsp = document.createElement("span"); + tsp.innerText = msg.text; + let d = document.createElement("div"); + d.appendChild(csp); + d.appendChild(tsp); + + c.e.appendChild(d); + + if(autoscroll) + c.e.scroll({top: c.e.scrollTopMax}); + } + + clearChannel (name) + { + let c = this.getChannel(name); + if(c == null) + return; + + while(c.e.firstElementChild != null) + c.e.firstElementChild.remove(); + } + + deleteChannel (name) + { + let c = this.getChannel(name); + if(c == null) + return; + + while(c.e.firstElementChild != null) + c.e.firstElementChild.remove(); + + c.btn.remove(); + + this.chats.splice(this.chats.indexOf(c), 1); + } + + toggle () { + if(this.root.getAttribute("show") != "true") + this.root.setAttribute("show", "true"); + else + this.root.setAttribute("show", "false"); + } +} diff --git a/webcards/scripts/gui/input.js b/webcards/scripts/gui/input.js index b0bbec0..6ed3d39 100644 --- a/webcards/scripts/gui/input.js +++ b/webcards/scripts/gui/input.js @@ -1,29 +1,9 @@ -function customSelectValue (el) { - var sel = el.getAttribute("selected"); - - if(typeof sel != "undefined") { - return el.children[parseInt(sel)].getAttribute("value"); - } - - return ""; -} - -function customSelectOption (el) { - var sn = Array.prototype.indexOf.call(el.parentElement.children, el); - var psn = el.parentElement.getAttribute("selected"); - - if(typeof psn == "string") - el.parentElement.children[parseInt(psn)].setAttribute("selected", false); +'use strict'; - if(typeof sn == "string") - el.parentElement.setAttribute("selected", parseInt(sn)); - - el.setAttribute("selected", true); - el.parentElement.setAttribute("selected", parseInt(sn)); -} - -var InputFuncs = { - createInput: function(type = "text", id) { +//This whole clusterfuq of functions needs fixing. +class MakeInput { + static createInput(type = "text", id) + { var el = document.createElement("input"); el.setAttribute("type", type); @@ -35,38 +15,41 @@ var InputFuncs = { } return el; - }, + } - inputLabel(text, id) { + static inputLabel(text, id) + { var el = document.createElement("label"); el.innerText = text; if(typeof id == "string") el.setAttribute("for", id); return el; - }, + } - colorInput: function(value, id) { - var el = this.createInput("color", id); + static colorInput (value, id) { + var el = MakeInput.createInput("color", id); el.value = value; return el; - }, + } - textInput: function(value, placeholder, id) { - var el = this.createInput("text", id); + static textInput (value, placeholder, id) + { + var el = MakeInput.createInput("text", id); el.setAttribute("placeholder", placeholder); el.value = value; return el; - }, + } - numberInput: function(value, id) { - var el = this.createInput("number", id); + static numberInput (value, id) + { + var el = MakeInput.createInput("number", id); el.value = value; return el; - }, + } //To fix - fileInput: function(value, id) { - var el = this.createInput("file", id); + static fileInput (value, id) { + var el = MakeInput.createInput("file", id); el.value = value; @@ -89,38 +72,38 @@ var InputFuncs = { } return el; - }, + } - checkboxInput: function(checked = false, id) { - var el = this.createInput("checkbox", false, id); + static checkboxInput (checked = false, id) { + var el = MakeInput.createInput("checkbox", false, id); if(checked) el.setAttribute("checked"); return el; - }, + } - radioInput: function(group, value, checked = false, id) { - var el = this.createInput("radio", false, id); + static radioInput (group, value, checked = false, id) { + var el = MakeInput.createInput("radio", false, id); el.setAttribute("name", group); el.setAttribute("value", value); if(checked) el.checked = true; return el; - }, + } - radioInputs: function(group, names, values, checked = 0, id) { + static radioInputs (group, names, values, checked = 0, id) { let toWrap = []; for(let i = 0; i < values.length; i++) { - toWrap.push(this.inputLabel(names[i], group+"-"+i)); + toWrap.push(MakeInput.inputLabel(names[i], group+"-"+i)); if(i == checked) - toWrap.push(this.radioInput(group, values[i], true, group+"-"+i)); + toWrap.push(MakeInput.radioInput(group, values[i], true, group+"-"+i)); else - toWrap.push(this.radioInput(group, values[i], false, group+"-"+i)); + toWrap.push(MakeInput.radioInput(group, values[i], false, group+"-"+i)); toWrap.push(document.createElement("br")); } - var wrapper = this.wrapInputs("radio", ...toWrap); + var wrapper = MakeInput.wrapInputs("radio", ...toWrap); wrapper.getValue = function() { for(let i = 0; i < this.children.length; i++){ @@ -133,9 +116,9 @@ var InputFuncs = { wrapper.setAttribute("id", id); return wrapper; - }, + } - selectOption: function(text, value, selected) { + static selectOption (text, value, selected) { var so = document.createElement("div"); so.innerText = text; so.setAttribute("value", value); @@ -145,9 +128,9 @@ var InputFuncs = { so.setAttribute("selected", true); return so - }, + } - selectInput: function(names, values, id, select = 0) { + static selectInput (names, values, id, select = 0) { var se = document.createElement("div"); se.className = "input-select"; se.setAttribute("tabindex", 0); @@ -155,20 +138,20 @@ var InputFuncs = { for(let i in names) { - se.appendChild(this.selectOption(names[i], values[i], i == select)); + se.appendChild(MakeInput.selectOption(names[i], values[i], i == select)); } if(typeof id == "string") se.setAttribute("id", id); - var wrapper = this.wrapInputs("select", se); - wrapper.getValue = customSelectValue.bind(null, se); + var wrapper = MakeInput.wrapInputs("select", se); + wrapper.getValue = MakeInput.selValue.bind(null, se); wrapper.setAttribute("tabindex", 0); return wrapper; - }, + } - wrapInputs: function(type, ...el) { + static wrapInputs (type, ...el) { var wrapper = document.createElement("div"); wrapper.className = "input-container"; @@ -181,37 +164,68 @@ var InputFuncs = { return wrapper; } -}; -function Settings (settings = {}) { - this.settings = settings; - - this.genSettings(); + static selValue (el) { + let sel = parseInt(el.getAttribute("selected")); + + if(typeof sel != "undefined") { + return el.children[sel].getAttribute("value"); + } + + return ""; + } + + static selOption (el) { + let sn = Array.prototype.indexOf.call(el.parentElement.children, el); + let psn = parseInt(el.parentElement.getAttribute("selected")); + + if(Number.isInteger(psn)) + el.parentElement.children[psn].setAttribute("selected", false); + + el.parentElement.setAttribute("selected", sn); + el.setAttribute("selected", true); + } } -Settings.prototype = { - getSettings: function() { - var out = {}; - for(let key in this.settings) { - - } - }, +class Settings { + constructor (template = {}) + { + this.settings = Settings.genSettings(template); + } - putSettings: function (el) { - for(let key in this.settings) { - el.appendChild(this.settings[key]); - } - }, + static genSettings (template) + { + var out = {}; - genSettings: function() { - for(let key in this.settings) { - switch(this.settings[key].type) { + for(let key in template) + { + switch(template[key].type) + { case "radio": - this.settings[key] = inputFuncs.radioInputs(...this.settings[key].args); + out[key] = MakeInput.radioInputs(...template[key].args); + break; default: - if(typeof inputFuncs[this.settings[key].type+"Input"] != null) - this.settings[key] = inputFuncs[this.settings[key].type+"Input"](...this.settings[key].args); + if(typeof MakeInput[template[key].type+"Input"] != null) + out[key] = MakeInput[template[key].type+"Input"](...template[key].args); } } + + return out; + } + + getSettings () + { + var out = {}; + + for(let key in this.settings) + out[key] = this.settings[key].getValue(); + + return out; } -};
\ No newline at end of file + + putSettings (el) + { + for(let key in this.settings) + el.appendChild(this.settings[key]); + } +} diff --git a/webcards/scripts/gui/lobby.js b/webcards/scripts/gui/lobby.js index 07f8223..7d2b6cd 100644 --- a/webcards/scripts/gui/lobby.js +++ b/webcards/scripts/gui/lobby.js @@ -1,39 +1,93 @@ -// Lobby manages the players and games provided by the server and allows users to join or create their own games. -function Lobby(el){ - this.root = el; - - this.e = { - status: el.getElementsByClassName("status")[0], - addr: el.getElementsByClassName("addr")[0], - games: el.getElementsByClassName("games")[0], - settings: el.getElementsByClassName("settings")[0], - - stats: { - game: document.getElementById("game"), - packs: document.getElementById("packs"), - online: document.getElementById("online"), - ingame: document.getElementById("ingame"), - pubgame: document.getElementById("pubgame") - } - }; - - this.top = new TopBar(document.getElementsByClassName("topbar")[0]); - - this.init = false; - this.online = []; - this.games = []; - this.packs = []; - this.players = []; +// ############### +// # TopBar Code # +// ############### + +// TopBar represents the bar at the top of the screen when client is in the lobby. + +class TopBar{ + constructor (el) + { + this.root = el; + + this.newGame = el.getElementsByClassName("new-game")[0]; + this.mobileSettings = el.getElementsByClassName("mobile-settings")[0]; + this.status = el.getElementsByClassName("status")[0]; + } + + // Set color of status bar + setStatus (s) { + this.status.setAttribute("s", s); + } + + // Toggle showing the new game screen + toggleNewGame () { + if (this.newGame.style.display !== "none") + this.newGame.style.display = "none"; + else + this.newGame.style.display = "block"; + } + + // Toggle showing the mobile settings + toggleMobileSettings () { + if (this.mobileSettings.style.display !== "none") + this.mobileSettings.style.display = "none"; + else + this.mobileSettings.style.display = "block"; + } } -Lobby.prototype = { +// ############# +// # Game code # +// ############# + +// Game represents a single game in the lobby view. It has methods for setting up the elements and such. +class Game{ + constructor (name, packs, maxp, id) + { + } +} + +// ############## +// # Lobby Code # +// ############## + +// Lobby manages the players and games provided by the server and allows users to join or create their own games. +class Lobby { + constructor (el) + { + this.root = el; + + this.e = { + status: el.getElementsByClassName("status")[0], + addr: el.getElementsByClassName("addr")[0], + games: el.getElementsByClassName("games")[0], + settings: el.getElementsByClassName("settings")[0], + + stats: { + game: document.getElementById("game"), + packs: document.getElementById("packs"), + online: document.getElementById("online"), + ingame: document.getElementById("ingame"), + pubgame: document.getElementById("pubgame") + } + }; + + this.top = new TopBar(document.getElementsByClassName("topbar")[0]); + + this.init = false; + this.online = []; + this.games = []; + this.packs = []; + this.players = []; + } + // Set initial pack list // {data array} array of strings representing pack names - packList: function(data) { + packList (data) { this.packs = data; this.top.setPacks(this.packs) this.e.stats.packs.innerText = this.packs.length(); - }, + } // Set initial game list. // { data object } object containing {games} and {name} @@ -43,20 +97,20 @@ Lobby.prototype = { // { data.games[n].packs } list of the pack names used by this game // { data.games[n].id } room identifier (uuid) // { data.games[n].max } max players in room - gameList: function(data) { + gameList (data) { while (this.e.games.firstChild != null) { this.e.games.remove(this.elements.games.firstChild) } for (let i in data.games) { - let gel = new GameEl(i.name, i.packs, i.id); + let gel = new Game(i.name, i.packs, i.id); this.games.push(gel); this.e.games.appendChild(gel.getElement()); } this.e.stats.game.innerText = data.name; this.e.stats.pubgame.innerText = this.games.length(); - }, + } // Set the initial player list. // { data array } represents a list of player objects from the server @@ -64,26 +118,26 @@ Lobby.prototype = { // { data[n].game string } id of the game room (empty if not in game). // { data[n].color string } css color chosen by player. // { data[n].uuid string } uuid of the player - players: function(data) { + players (data) { this.e.stats.online.innerText = this.players.length(); this.init = true; - }, + } // Called when a new public game is created on the server // { data object } the game object // { data.name } room name // { data.packs } list of the pack names used by this game // { data.id } room identifier (uuid) - addGame: function(data) { + addGame (data) { - }, + } // Called when a new public game is removed on the server // { data string } the uuid of the game to delete - removeGame: function(data) { + removeGame (data) { - }, + } // Called when a new player enters the lobby. // { data object } an object representing the player @@ -91,56 +145,60 @@ Lobby.prototype = { // { data.game string } id of the game room (empty if not in game). // { data.color string } css color chosen by player. // { data.uuid string } uuid of the player - addPlayer: function(data) { + addPlayer (data) { - }, + } // Called when a player modifies their settings in the lobby. // { data object } new player settings // { data.name string } non null if the player has changed their name // { data.color string } non null if the player has changed their color // { data.uuid string } uuid of player changing their settings - modPlayer: function(data) { + modPlayer (data) { - }, + } // Called when a player moves between the lobby and a game, or between two games // { data object } new location // { data.player } uuid of player changing location // { data.loc } uuid of room player is moving to (empty if moving to lobby) - movePlayer: function(data) { + movePlayer (data) { - }, + } // Called when a player exits the game (from lobby or game) - // {data string } uuid of player - removePlayer: function(data) { + // { data string } uuid of player + removePlayer (data) { - }, + } // Called when the client wants to toggle the new game screen - newGame: function() { + newGame () { //if(this.init) return; this.top.toggleNewGame(); - }, + } // Called when the client wants to toggle the mobile settings screen - mobileSettings: function() { + mobileSettings () { //if(this.init) return; this.top.toggleMobileSettings(); - }, + } // Called when the WebSocket state has changed. - setState: function(text, s, server) { + setState (text, s, server) { this.e.status.setAttribute("s", s); if(this.e.status.innerText != "Error" || ( this.e.status.innerText == "Error" && text != "Closed")) this.e.status.innerText = text; this.e.addr.innerText = server; this.top.setStatus(s); - }, + } + + getState () { + return this.e.status.innerText.toLowerCase(); + } // Called when we are resetting the game. - reset: function() { + reset () { while (this.e.games.firstElementChild != null) { this.e.games.removeChild(this.e.games.firstElementChild) } @@ -148,50 +206,4 @@ Lobby.prototype = { this.setState("Connecting", "loading", this.e.addr.innerText); this.init = false; } -}; - -// ############### -// # TopBar Code # -// ############### - -// TopBar represents the bar at the top of the screen when client is in the lobby. - -function TopBar(el) { - this.root = el; - - this.newGame = el.getElementsByClassName("new-game")[0]; - this.mobileSettings = el.getElementsByClassName("mobile-settings")[0]; - this.status = el.getElementsByClassName("status")[0]; } - -TopBar.prototype = { - // Set color of status bar - setStatus: function(s) { - this.status.setAttribute("s", s); - }, - - // Toggle showing the new game screen - toggleNewGame: function() { - if (this.newGame.style.display !== "none") - this.newGame.style.display = "none"; - else - this.newGame.style.display = "block"; - }, - - // Toggle showing the mobile settings - toggleMobileSettings: function() { - if (this.mobileSettings.style.display !== "none") - this.mobileSettings.style.display = "none"; - else - this.mobileSettings.style.display = "block"; - } -}; - -// ############# -// # Game code # -// ############# - -// GameEl represents a single game in the lobby view. It has methods for setting up the elements and such. -function GameEl(name, packs, maxp, id) { - -}
\ No newline at end of file diff --git a/webcards/scripts/gui/table.js b/webcards/scripts/gui/table.js index 2776f80..c4878a0 100644 --- a/webcards/scripts/gui/table.js +++ b/webcards/scripts/gui/table.js @@ -1,32 +1,79 @@ // Table represents and manages the actual game. It accepts inputs from the server and tries to query the server when the player makes a move. -function Table(el, soc) { - this.root = el; - this.soc = soc; -} +class Table{ + constructor(e, drag, socket) { + this.root = e; + this.drag = drag; + + this.root.addEventListener("mouseup", drag.stopDraggingAll.bind(drag)); + + //drag.addEventListener("dragstop", ); + + this.socket = socket; + + this.decks = []; + } -Table.prototype = { - - openTable: function(){ + openTable () + { let state = this.root.getAttribute("state") if((state == "close" || state == "closed") && state != "") { this.root.setAttribute("state", "closed"); setTimeout(this.root.setAttribute.bind(this.root), 50, "state", "open"); } - }, + } - closeTable: function(){ + closeTable () + { let state = this.root.getAttribute("state") if(state != "close" && state != "closed") { this.root.setAttribute("state", ""); setTimeout(this.root.setAttribute.bind(this.root), 50, "state", "close"); } - }, + } - handleClose: function() { + handleClose () + { this.reset(); - }, + } + + reset () + { + while(this.root.firstElementChild != null) + this.root.firstElementChild.remove(); + + this.decks = []; - reset: function() { this.closeTable(); + this.drag.stopDraggingAll(); } -}
\ No newline at end of file + + /* Deck and card functions */ + newDeck(options) + { + var d = new Deck(options); + this.decks.push(d); + this.root.appendChild(d.e); + } + + newCard(data, deck = 0) + { + var c = new Card(data); + this.decks[deck].appendCard(c); + this.drag.addTarget(c.e); + } + + checkDeck(x, y) + { + for(let d of this.decks) + { + if(d.isInside(x, y)) + return true; + } + return false; + } + + dragCheck(cap) + { + console.log(cap); + } +} diff --git a/webcards/scripts/socket/message.js b/webcards/scripts/socket/message.js index 5e821c4..044027d 100644 --- a/webcards/scripts/socket/message.js +++ b/webcards/scripts/socket/message.js @@ -1,14 +1,18 @@ -function Message(type, data){ - this.t = type; - this.d = data; -} +'use strict'; + +class Message{ + constructor (type, data) + { + this.t = type; + this.d = data; + } -Message.prototype = { - stringify: function(){ + stringify () + { var dat = this.d if(typeof dat !== "string"){ dat = JSON.stringify(dat); } return JSON.stringify({type: this.t, data: dat}); } -}; +} diff --git a/webcards/scripts/socket/sock.js b/webcards/scripts/socket/sock.js index cf06a5e..4eacc18 100644 --- a/webcards/scripts/socket/sock.js +++ b/webcards/scripts/socket/sock.js @@ -1,13 +1,15 @@ // A wrapper around the wrapper -function SockWorker(serveraddr, version, callback) { - this.server = serveraddr; - this.version = version; - this.cb = callback; -} +class SockWorker extends EventTarget{ + constructor (serveraddr, version) + { + super(); + + this.server = serveraddr; + this.version = version; + } -SockWorker.prototype = { // Initialize the connection. - init: function() { + init () { if(this.server == "" || this.server == null) { return; } @@ -22,42 +24,42 @@ SockWorker.prototype = { } catch (e) { this.err(); } - }, + } // Called when the connection connects to the server - o: function() { + o () { this.send("version", this.version); - }, + } // Called when the connection gets a message from the server // Attempts to turn the message into a usable object and pass it to the callback - msg: function(e) { + msg (e) { if(typeof e.data == "string") { var dat = JSON.parse(e.data) - this.cb(dat); + this.dispatchEvent(new Event(dat.type, dat.data)); } - }, + } // Called when the connection closes. // Passes a close object to the callback. - c: function() { - this.cb({type: "close", data: ""}); - }, + c () { + this.dispatchEvent(new Event("closed")); + } // Called when the connection encounters an error. // Passes an error to the callback - err: function() { - this.cb({type: "error", data: ""}); - }, + err () { + this.dispatchEvent(new Event("error")); + } // Call to close the connection to the server - close: function() { + close () { this.socket.close(); - }, + } // Send a message to the server - send: function(type, data) { + send (type, data) { var m = new Message(type, data); this.socket.send(m.stringify()) } -};
\ No newline at end of file +} diff --git a/webcards/scripts/theme.js b/webcards/scripts/theme.js index 8e69377..e93f5b5 100644 --- a/webcards/scripts/theme.js +++ b/webcards/scripts/theme.js @@ -1,24 +1,26 @@ -function Theme(){ - this.t = document.getElementById("theme"); -} +'use strict'; + +class Theme{ + static theme = document.getElementById("theme"); -Theme.prototype = { - init: function() { + static init() + { if(Cookies.getCookie("theme") == ""){ Cookies.setYearCookie("theme", "styles/themes/colors-base.css"); } - }, + } - restore: function() { - this.init(); - this.t.setAttribute("href", Cookies.getCookie("theme") + "?v=" + Date.now()); - }, + static restore() + { + Theme.init(); + Theme.theme.setAttribute("href", Cookies.getCookie("theme") + "?v=" + Date.now()); + } - set: function(sheet) { + static set(sheet) + { Cookies.setYearCookie("theme", sheet); - this.restore(); + Theme.restore(); } -}; +} -var GlobalTheme = new Theme(); -GlobalTheme.restore(); +Theme.restore();
\ No newline at end of file diff --git a/webcards/styles/client/base.css b/webcards/styles/client/base.css index 52c2722..ba06e3c 100644 --- a/webcards/styles/client/base.css +++ b/webcards/styles/client/base.css @@ -13,6 +13,8 @@ html, body { background-color: var(--main-bg); color: var(--main-color); + + overflow: hidden; } /* Topbar rules */ @@ -140,6 +142,9 @@ div.game { box-shadow: var(--gui-shadow-game) 3px 3px 2px; box-sizing: border-box; margin-bottom: 10px; + padding: 5px; + + text-align: left; } div.game:last-child { @@ -162,7 +167,7 @@ div.settings { animation-duration: 0.8s; - background-color: rgba(0, 0, 0, 0.5); + background-color: var(--table-bg); overflow: hidden; } @@ -195,3 +200,118 @@ div.settings { opacity: 1; } } + +/* Chat */ + +div.chat { + border-top-left-radius: 10px; + background-color: var(--chat-bg); + color: var(--chat-color); + + width: 50vw; + height: 50vh; + display: flex; + flex-direction: column; + position: absolute; + right: -50vw; + + box-sizing: border-box; + + top: 50vh; + + transition-duration: 0.2s; + + padding: 5px; + + z-index: 4; +} + +div.chat[show=true] { + right: 0; +} + +button.toggle-chat { + position: absolute; + bottom: 5px; + left: -5px; + transform-origin: bottom left; + transform: rotate(-90deg); +} + +div.chat > div { + box-sizing: border-box; + margin: 5px; +} + +div.chat-select, div.chat-input { + flex-basis: content; + display: flex; +} + +div.chat-text { + flex: 1; + overflow-y: auto; + overflow-x: hidden; + padding: 5px; + background-color: var(--chat-bg-text); + border-radius: 10px; + border: 5px solid rgba(0, 0, 0, 0); +} + +div.chat-select > button { + flex: 1; + + margin-right: 2px; + margin-left: 2px; +} + +div.chat-select > button[active="false"] { + background-color: var(--chat-bg-inactive); +} + +div.chat-select > button[active="false"]:hover { + background-color: var(--chat-bg-inactive-hover); +} + +div.chat-select > button[active="false"]:active { + background-color: var(--chat-bg-inactive-active); +} + +div.chat-select > button:first-child { + margin-left: 0; +} + +div.chat-select > button:last-child { + margin-right: 0; +} + +div.chat-input > input { + flex: 5; + + margin: 0; + margin-right: 5px; + + border-radius: 5px; + + transition-duration: 0.2s; + border: none; + + background-color: var(--chat-bg-input); +} + +div.chat-input > input:hover { + background-color: var(--chat-bg-input-hover); +} + +div.chat-input > input:focus { + background-color: var(--chat-bg-input-active); +} + +div.chat-input > button { + flex: 1; +} + +div.chat-text > div { + word-wrap: break-word; + word-break: break-all; +}
\ No newline at end of file diff --git a/webcards/styles/client/card.css b/webcards/styles/client/card.css index 2f52255..de49175 100644 --- a/webcards/styles/client/card.css +++ b/webcards/styles/client/card.css @@ -125,43 +125,67 @@ card[drag=true] /* Deck */ deck { + --ccount: 0; + position: absolute; - min-width: 160px; - min-height: 240px; + width: 166px; + height: 250px; top: 0; left: 0; overflow: visible; - display: flex; - justify-content: center; - align-content: center; border-radius: 10px; transition-duration: 0.2s; + + border: 3px solid var(--deck-shadow); + box-sizing: border-box; } deck:hover { - box-shadow: 0 0 5px var(--deck-hover); + border: 3px solid var(--deck-hover); +} + +/* Deck modes */ + +deck[mode="stack"] > card { + transform: translate(5px, calc(var(--cpos) * 3px + 7px)); } -deck > card { - transform: translate(0, calc(var(--cpos) * 3px )); +deck[mode="stack"] { + height: calc(var(--ccount) * 3px + 250px); } deck[mode="strip-hl"] > card { - transform: translate(calc(var(--cpos) * -75px), 0); + transform: translate(calc(var(--ccount) * 75px + var(--cpos) * -75px + 5px), 7px); +} + +deck[mode="strip-hl"] { + width: calc(var(--ccount) * 75px + 160px); } deck[mode="strip-hr"] > card { - transform: translate(calc(var(--cpos) * 75px), 0); + transform: translate(calc(var(--cpos) * 75px + 5px), 7px); +} + +deck[mode="strip-hr"] { + width: calc(var(--ccount) * 75px + 160px); } deck[mode="strip-vu"] > card { - transform: translate(0, calc(var(--cpos) * -115px )); + transform: translate(5px, calc(var(--ccount) * 115px + var(--cpos) * -115px + 7px)); +} + +deck[mode="strip-vu"] { + height: calc(var(--ccount) * 115px + 240px); } deck[mode="strip-vd"] > card { - transform: translate(0, calc(var(--cpos) * 115px )); + transform: translate(5px, calc(var(--cpos) * 115px + 7px)); } + +deck[mode="strip-vd"] { + height: calc(var(--ccount) * 115px + 240px); +}
\ No newline at end of file diff --git a/webcards/styles/client/desktop.css b/webcards/styles/client/desktop.css index f072a71..10caa15 100644 --- a/webcards/styles/client/desktop.css +++ b/webcards/styles/client/desktop.css @@ -28,6 +28,7 @@ div.lobby { min-width: 70vw; min-height: 70vh; + max-height: 70vh; display: flex; text-align: center; @@ -145,5 +146,4 @@ /* Chat */ - } diff --git a/webcards/styles/client/mobile.css b/webcards/styles/client/mobile.css index 1afc4fb..ed2e19d 100644 --- a/webcards/styles/client/mobile.css +++ b/webcards/styles/client/mobile.css @@ -10,6 +10,10 @@ display: none; } + div.chat { + display: none; + } + /* TopBar for mobile */ diff --git a/webcards/styles/home/base.css b/webcards/styles/home/base.css index 80d0948..a082ec2 100644 --- a/webcards/styles/home/base.css +++ b/webcards/styles/home/base.css @@ -35,7 +35,7 @@ div.content { } a, button { - font-size: 24px; + font-size: 1em; display: block; color: white; box-sizing: border-box; @@ -51,4 +51,58 @@ a, button { text-decoration: none; margin-top: 10px; +} + + + +div.content > div.prev { + width: 100%; + margin: 10px; + + border-radius: 5px; + + display: block; + + padding: 0; +} + +div.prev > a{ + display: inline-block; + width: 80%; + margin: 0; + padding: 5px; + border-radius: 0; +} + +div.prev > a:first-of-type { + border-top-left-radius: 5px; +} + +div.prev > a:last-of-type { + border-bottom-left-radius: 5px; +} + +div.prev > button { + display: inline-block; + width: 20%; + margin: 0; + background-color: #ff1e00; + padding: 5px; + border-radius: 0; +} + +div.prev > button:first-of-type { + border-top-right-radius: 5px; +} + +div.prev > button:last-of-type { + border-bottom-right-radius: 5px; +} + +div.prev > button:hover { + background-color: #ff5741; +} + +div.prev > button:active { + background-color: #9c1200; }
\ No newline at end of file diff --git a/webcards/styles/input.css b/webcards/styles/input.css index 0553fc2..42656a0 100644 --- a/webcards/styles/input.css +++ b/webcards/styles/input.css @@ -17,7 +17,7 @@ input, select /* Button input */ -input[type=button], input[type=submit], button +input[type=button], input[type=submit], button, a { padding: 10px; @@ -34,12 +34,12 @@ input[type=button], input[type=submit], button cursor: pointer; } -input[type=button]:hover, input[type=submit]:hover, button:hover +input[type=button]:hover, input[type=submit]:hover, button:hover, a:hover { background-color: var(--input-bg-button-hover); } -input[type=button]:active, input[type=submit]:active, button:active +input[type=button]:active, input[type=submit]:active, button:active, a:active { background-color: var(--input-bg-button-active); } diff --git a/webcards/styles/themes/colors-base.css b/webcards/styles/themes/colors-base.css index fa2b60e..62665a2 100644 --- a/webcards/styles/themes/colors-base.css +++ b/webcards/styles/themes/colors-base.css @@ -18,15 +18,16 @@ --gui-shadow-game: gray; --top-border: black; - --top-bg: white; - --top-bg-button: white; - --top-bg-button-hover: #ddd; - --top-bg-button-active: ; + --top-bg: #eee; + --top-bg-button: #eee; + --top-bg-button-hover: #ccc; + --top-bg-button-active: white; --top-color-button: black; --top-color-button-hover: black; --top-color-button-active: black; /* Table */ + --table-bg: rgb(20, 110, 50); /* Card defaults */ --card-color: black; @@ -34,7 +35,8 @@ --card-border: #bbb; --card-hover: #0f0; - --deck-hover: #3ea2ff; + --deck-shadow: #2696ff; + --deck-hover: #73bbff; /* Input */ @@ -75,4 +77,18 @@ --input-bg-multi: rgba(30, 30, 30, 0.3); --input-bg-multi-hover: rgba(200, 200, 200, 0.3); + + /* Chat */ + --chat-color: black; + --chat-bg: white; + + --chat-bg-text: rgba(0, 0, 0, 0.2); + + --chat-bg-input: rgb(220, 220, 220); + --chat-bg-input-hover: rgb(220, 220, 220); + --chat-bg-input-active: rgb(220, 220, 220); + + --chat-bg-inactive: rgb(80, 80, 80); + --chat-bg-inactive-hover: rgb(130, 130, 130); + --chat-bg-inactive-active: rgb(40, 40, 40); }
\ No newline at end of file diff --git a/webcards/styles/themes/colors-dark.css b/webcards/styles/themes/colors-dark.css index 2f6ef3e..f630ac0 100644 --- a/webcards/styles/themes/colors-dark.css +++ b/webcards/styles/themes/colors-dark.css @@ -15,7 +15,7 @@ --gui-bg-main: #555; --gui-bg-game: #777; --gui-color-game: white; - --gui-shadow-game: #222; + --gui-shadow-game: #444; --top-border: #999; --top-bg: #333; @@ -27,6 +27,7 @@ --top-color-button-active: white; /* Table */ + --table-bg: rgb(20, 110, 50); /* Card defaults */ --card-color: black; @@ -34,6 +35,7 @@ --card-border: #bbb; --card-hover: #0f0; + --deck-shadow: #2696ff; --deck-hover: #3ea2ff; /* Input */ @@ -76,4 +78,26 @@ --input-bg-multi: rgba(30, 30, 30, 0.3); --input-bg-multi-hover: rgba(200, 200, 200, 0.3); + + /* Chat */ + --chat-color: white; + --chat-bg: #555; + + --chat-bg-text: #444; + + --chat-bg-input: #555; + --chat-bg-input-hover: #777; + --chat-bg-input-active: #444; + + --chat-bg-select: #444; + --chat-bg-select-hover: #777; + --chat-bg-select-active: #333; + + --chat-bg-inactive: #444; + --chat-bg-inactive-hover: #777; + --chat-bg-inactive-active: #333; + + --chat-bg-active: rgb(255, 133, 34); + --chat-bg-active-hover: rgb(255, 165, 92); + --chat-bg-active-active: rgb(226, 102, 0); }
\ No newline at end of file |