all repos — felt @ 81876f9f36998c20f796c692dcc37f0db381c6f8

virtual tabletop for dungeons and dragons (and similar) using Go, MongoDB, and websockets

add style, implement dicelog
Iris Lightshard nilix@nilfm.cc
PGP Signature
-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEEkFh6dA+k/6CXFXU4O3+8IhROY5gFAmPzsIkACgkQO3+8IhRO
Y5j+sA/+MlQqQOKTI3mHn9pgqqFK3x4DP4AKpwceLt1/93MWnKLBuPuRuYMwAG14
Uu7VnAr3+7oggCRPUqQwoX0tQnBijpXw7x//nYhD9A90SGfNYGyB2bIFW74lUto7
tRzh6v5e90kb7Cz3CZN1PrNBhMSJ+uK8nCtX/ZPw24qSHWasO1YNDRD/+skJajIm
om5PHwhpkiSRoZwTHBHaa3SUQTK+G3+x0PQ8Iu4vStK/D6ij/t2nwGyhwO19XOf8
Pc/nLhoEDC627pePUZdF2TIERlWBHQoyLIbMvG2fGvkCuhWLdGnUMoAiHlOnIbJs
6QqTiQwfkQqRzzrsdpcGKy1op4ZjJ05lu+PpzZzfnDq0X2laUq7yHmLvfvn8AiAS
hNAKXYnUUBJjMKYzZKXW6GEj50edrNE7S8cb2Jcmf09XvoxUgHNyWyAidH5YqYaJ
Jb0B/YBPet+LHN0Ily6FrUTeg9582fzPovP3ZI3tdPLmtfYtX2Azc7o5tFmo2eCM
vUbZSXurupLEdc26b3AIcekLzejV3A8hMKZ9uTNeZ9StsGFQCIDl0aHY6HrhKBmc
OqQwLbES44+Ag0aTP2B3AL6ASI/SLiFXcFUggkLKcAE5S1TwkKCmJCWF9Z4iE43B
0UAGVFScLRNFdqI9ANReLHigU15IX6CwtILUYEeshbqggbbDE5Q=
=Fmzj
-----END PGP SIGNATURE-----
commit

81876f9f36998c20f796c692dcc37f0db381c6f8

parent

b8994d80a976013648e028c851160ddfa94d42b5

4 files changed, 122 insertions(+), 4 deletions(-)

jump to
M static/index.htmlstatic/index.html

@@ -9,20 +9,21 @@ </head>

<body> <div id="errWrapper" style='display:none'><button id="closeErr" onclick="closeErr()">x</button><div id="errDiv"></div></div> <nav> + <label for="name_entry">username</label> <input id="name_entry" onblur="saveName()"> <button id="goto_table" onclick="showAdminModal(false);showTableModal(true)">Join Table</button> <button id="admin_login" onclick="showTableModal(false);showAdminModal(true)">Admin Login</button> </nav> <form id="table_modal" onsubmit="return false" style="display:none;"> - <label>Table Name<input id="input_table_name"></label> - <label>Table Passcode<input id="input_table_pass"></label> + <label>table.name<br><input id="input_table_name"></label><br> + <label>table.passcode<br><input id="input_table_pass"></label><br> <button type="submit" id="table_join" onclick="dial();showTableModal(false);">Join</button> </form> <form id="admin_modal" onsubmit="return false" style="display:none;"> <label>pass<input type="password" id="input_admin_pass"></label> <button type="submit" id="admin_login" onclick="doLogin();showAdminModal(false)">login</button> </form> - <div id="dice_log"></div> + <main id="tabletop" style="display:none;"> <select id="num_dice"> <option>1</option> <option>2</option>

@@ -55,6 +56,7 @@ <option>12</option>

<option>20</option> </select> <input id="dice_note"><button id="dice_submit" onclick="rollDice()">Roll</button> + <div id="dice_log"></div> <div id="map"></div> <div id="adminWrapper" style="display:none;"> <div id="adminCtrl">

@@ -68,6 +70,7 @@ </form>

</div> <div id="adminZone"></div> </div> + </main> </body> <script src="./util.js" type="text/javascript"></script> <script src="./socket.js" type="text/javascript"></script>
M static/socket.jsstatic/socket.js

@@ -14,6 +14,31 @@ modal.style.display = show ? "block" : "none";

} } +function formatDice(r) { + const date = new Date(r.timestamp) + + return `<p>${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()} ${r.player} rolled ${r.roll.length}d${r.faces} ${(r.note ? "(" + r.note + ")" : "")}<br>[${r.roll}] (total ${r.roll.reduce((a,c)=>a+c,0)})</p>` +} + +function logDice(dice, many) { + const diceLog = document.getElementById("dice_log"); + if (diceLog) { + if (many) { + for(const r of dice) { + diceLog.innerHTML += formatDice(r); + } + } else { + diceLog.innerHTML += formatDice(dice); + } + } +} + +function makeUpToDate(table) { + if (table && table.diceRolls) { + logDice(table.diceRolls, true); + } +} + function dial() { // get tableKey from UI const tblNameInput = document.getElementById("input_table_name");

@@ -27,12 +52,27 @@ conn.addEventListener("close", e => {

if (e.code !== 1001) { // TODO: add message to let user know they are reconnecting setTimeout(dial, 1000) + } else { + tabletop = document.getElementById("tabletop"); + if (tabletop) { + tabletop.style.display = "none"; + } + table = null; } }); conn.addEventListener("open", e => { // TODO: add message to let user know they are at the table console.info("socket connected"); + tabletop = document.getElementById("tabletop"); + if (tabletop) { + tabletop.style.display = "block"; + } }); + conn.addEventListener("error", e => { + setErr(JSON.stringify(e)); + conn.close(); + }) + conn.addEventListener("message", e => { const data = JSON.parse(e.data); if (table == null) {

@@ -41,8 +81,11 @@ data.diceRolls.forEach(r=>{

r.roll = Uint8Array.from(atob(r.roll), c => c.charCodeAt(0)) }) table = data; + makeUpToDate(table); } else { - // UPDATE THE TABLE! + if (data.diceRoll) { + logDice(data.diceRoll); + } } console.log(data); });
A static/style.css

@@ -0,0 +1,72 @@

+* { + box-sizing: border-box; + padding: 0; + margin: 0; + appearance: none; + outline: none; +} + +body { + background: url('./bg.png'); + background-repeat: repeat; +} + +nav, #table_modal, #admin_modal { + color: #fff; + background: #000; + padding: 0.5em; +} + +label { + font-size: 80%; +} + +input, select { + background: #fff; + color: #000; + border: solid 1px gray; + margin-right: 1ch; +} + +input:active, input:focus, select:active, select:focus { + border: solid 1px cyan; +} + +button { + padding: 0.5ch; + background: #000; + color: #fff; + border: solid 2px lightseagreen; + margin-right: 1ch; +} + +button:hover { + color: #000; + background: lightseagreen; +} + +#errWrapper { + color: #fff; + background: crimson; + padding: 1em; +} +#closeErr { + display: inline; + border: dotted 1px #fff; + color: #fff; + background: crimson; + padding: 0 1ch; + margin-right: 1ch; +} +#errDiv { + display: inline; +} + +#dice_log { + background: #fff; + color: #000; +} + +#dice_log p { + margin: 0.5ch; +}