PROGRESS! mostly ui, got admin stuff

This commit is contained in:
Rusty Striker 2025-07-27 21:19:50 +03:00
parent 2658f3d28c
commit e730f9a870
Signed by: RustyStriker
GPG key ID: 87E4D691632DFF15
6 changed files with 198 additions and 68 deletions

View file

@ -110,11 +110,17 @@ tavern.onlogin = (s) => {
let game = document.getElementById('game');
login.style.display = 'none';
game.style.display = 'flex';
document.getElementById('admin-panel-button').style.display = tavern.admin ? 'block' : 'none';
}
else {
alert("Invalid username or password!");
}
}
tavern.onclose = () => {
document.getElementById('game-closed-screen').style.display = 'flex';
document.getElementById('login-screen').style.display = 'none';
document.getElementById('game').style.display = 'none';
}
tavern.onmessage = (m) => {
console.log(m);
let msg = document.createElement('div');
@ -216,7 +222,31 @@ tavern.onscenelist = (list) => {
let div = document.getElementById('scene-list');
div.innerHTML = '';
for (let scene of list.scenes) {
div.innerHTML += `<button onclick='tavern.get_scene(${scene[0]});'>${scene[1]}</button>`;
let row = document.createElement('div');
row.style.display = 'flex';
row.style.gap = '2px';
row.style.background = 'transparent';
row.innerHTML = `<button onclick='tavern.get_scene(${scene[0]});'>${scene[1]}</button>`;
if (tavern.admin) {
row.innerHTML += `<button onclick='tavern.show_scene(${scene[0]});'>Force</button>`;
row.innerHTML += `<button onclick='tavern.set_scene_visible(${scene[0]}, !${scene[2]});'>${scene[2] ? 'Hide' : 'Show'}</button>`;
}
div.appendChild(row);
}
}
tavern.onconnectedplayers = (connected) => {
console.log(connected);
// no reason to update the list of kick players if not an admin
if (tavern.admin) {
let select = document.getElementById('admin-kick-name');
Array.from(select.children).filter(c => c.tagName == 'OPTION').forEach(c => select.removeChild(c));
connected.forEach(p => {
let opt = document.createElement('option');
opt.value = p;
opt.innerText = p;
opt.selected = select.children.length == 0;
select.appendChild(opt);
});
}
}
function onLoginClick() {

View file

@ -8,6 +8,17 @@
</head>
<body onload="init()">
<!-- GAME SERVER CLOSED PAGE -->
<div id="game-closed-screen" style="display: none; justify-content: center; width: 100%; height: 100%;">
<div style="display: flex; justify-content: center; flex-direction: column; gap: 4px;">
<h1>Disconnected from game server</h1>
<p>
This could be either because the game server got shutdown,
internet is out,
or you got kicked for some reason
</p>
</div>
</div>
<!-- LOGIN PAGE -->
<div id="login-screen" style="display: flex; justify-content: center; width: 100%; height: 100%;">
<div style="display: flex; justify-content: center; flex-direction: column; gap: 4px;">
@ -59,9 +70,11 @@
</div>
</div>
<div
style="position: absolute; top: 10px; right: 10px; color: black; z-index: 5; display: flex; flex-direction: row;">
style="position: absolute; top: 10px; right: 10px; color: black; z-index: 5; display: flex; flex-direction: row; gap: 4px;">
<button style="background-color: #ffffd6;" onclick="showHideDiv('settings-window')"><b>s</b></button>
<button style="background-color: #ffffd6;" onclick="showHideDiv('initiative-tracker')"><b>i</b></button>
<button id="admin-panel-button" style="background-color: #ffffd6;"
onclick="showHideDiv('admin-panel')">Admin</button>
</div>
<div id="map" style="position:absolute; transform-origin: top left; user-select: none;">
<img id="map-background" onload="updateGrid()" onerror="alert('Failed loading map')">
@ -69,62 +82,80 @@
</svg>
</div>
</div>
</div>
<!-- FLOATY (game view) WINDOWS -->
<div id="msg-context-menu" class="chat-message">
<ul>
<li>Delete (TODO)</li>
</ul>
</div>
<div id="initiative-tracker" style="position: absolute; background-color: #ffffd6; color:black; display: none;
flex-direction: column; top: 40px; right: 8px; padding: 8px; border-radius: 8px;">
<div style="min-width: 150px; user-select: none; display: flex;"
onmousedown="onMoveableDivMouseDown(event, 'initiative-tracker')">
<h3 style="flex-grow: 1; margin: 8px 0;">Initiative</h3>
<!-- it looks bad, for now just click the 'open initiative tracker' button again -->
<button onclick="document.getElementById('initiative-tracker').style.display = 'none';"
style="height: fit-content; align-self: center; background-color: transparent; font-size: 20px; border: 0;">
X
</button>
<!-- FLOATY (game view) WINDOWS -->
<div id="msg-context-menu" class="chat-message">
<ul>
<li>Delete (TODO)</li>
</ul>
</div>
<hr style="width: 100%; margin: 0px; align-self: center;" />
<div>
aaaa
<div id="initiative-tracker" style="position: absolute; background-color: #ffffd6; color:black; display: none;
flex-direction: column; top: 40px; right: 8px; padding: 8px; border-radius: 8px;">
<div style="min-width: 150px; user-select: none; display: flex;"
onmousedown="onMoveableDivMouseDown(event, 'initiative-tracker');">
<h3 style="flex-grow: 1; margin: 8px 0;">Initiative</h3>
<!-- it looks bad, for now just click the 'open initiative tracker' button again -->
<button class="exit-button"
onclick="document.getElementById('initiative-tracker').style.display = 'none';">
X
</button>
</div>
<hr style="width: 100%; margin: 0px; align-self: center;" />
<div>
aaaa
</div>
<div>
bbbb
</div>
<div>
cccc
</div>
</div>
<div>
bbbb
<div id="settings-window" style="position: absolute; background-color: #ffffd6; color:black; display: none;
flex-direction: column; top: 40px; right: 8px; padding: 8px; border-radius: 8px;">
<div style="min-width: 150px; user-select: none; display: flex;"
onmousedown="onMoveableDivMouseDown(event, 'settings-window')">
<h3 style="flex-grow: 1; margin: 8px 0;">Settings</h3>
<!-- it looks bad, for now just click the 'open initiative tracker' button again -->
<button class="exit-button"
onclick="document.getElementById('settings-window').style.display = 'none';">
X
</button>
</div>
<hr style="width: 100%; margin: 0px; align-self: center;" />
<div style="display: grid; grid-template-columns: auto auto; gap: 16px; margin-top: 8px;">
<div>Grid width</div>
<input id="settings-grid-width" type="number" onchange="updateGridWidth(event.target.value)"
style="width: 55px;">
<div>Grid color</div>
<input id="settings-grid-color" type="color" onchange="updateGridColor(event.target.value)">
<div>Grid type</div>
<select id="settings-grid-type" onchange="updateGridDashType(event.target.selectedIndex)"
style="width: 140px;">
<option value="0" selected>Solid</option>
<option value="1">Cross</option>
<option value="2">Hollow cross</option>
<option value="3">Large hollow cross</option>
<option value="4">Squire</option>
</select>
</div>
</div>
<div>
cccc
</div>
</div>
<div id="settings-window" style="position: absolute; background-color: #ffffd6; color:black; display: none;
flex-direction: column; top: 40px; right: 8px; padding: 8px; border-radius: 8px;">
<div style="min-width: 150px; user-select: none; display: flex;"
onmousedown="onMoveableDivMouseDown(event, 'settings-window')">
<h3 style="flex-grow: 1; margin: 8px 0;">Settings</h3>
<!-- it looks bad, for now just click the 'open initiative tracker' button again -->
<button onclick="document.getElementById('settings-window').style.display = 'none';"
style="height: fit-content; align-self: center; background-color: transparent; font-size: 20px; border: 0;">
X
</button>
</div>
<hr style="width: 100%; margin: 0px; align-self: center;" />
<div style="display: grid; grid-template-columns: auto auto; gap: 16px; margin-top: 8px;">
<div>Grid width</div>
<input id="settings-grid-width" type="number" onchange="updateGridWidth(event.target.value)"
style="width: 55px;">
<div>Grid color</div>
<input id="settings-grid-color" type="color" onchange="updateGridColor(event.target.value)">
<div>Grid type</div>
<select id="settings-grid-type" onchange="updateGridDashType(event.target.selectedIndex)"
style="width: 140px;">
<option value="0" selected>Solid</option>
<option value="1">Cross</option>
<option value="2">Hollow cross</option>
<option value="3">Large hollow cross</option>
<option value="4">Squire</option>
</select>
<div id="admin-panel" style="position: absolute; background-color: #ffffd6; color:black; display: none;
flex-direction: column; top: 40px; right: 8px; padding: 8px; border-radius: 8px;">
<div style="min-width: 150px; user-select: none; display: flex;"
onmousedown="onMoveableDivMouseDown(event, 'admin-panel')">
<h3 style="flex-grow: 1; margin: 8px 0;">Admin</h3>
<!-- it looks bad, for now just click the 'open initiative tracker' button again -->
<button class="exit-button" onclick="document.getElementById('admin-panel').style.display = 'none';">
X
</button>
</div>
<hr style="width: 100%; margin: 0px; align-self: center;" />
<div style="display: grid; grid-template-columns: auto auto; gap: 16px; margin-top: 8px;">
<button onclick="tavern.save()">Save</button>
<button onclick="tavern.shutdown()">Shutdown</button>
<select id="admin-kick-name"></select>
<button onclick="tavern.kick(document.getElementById('admin-kick-name').value)">Kick</button>
</div>
</div>
</div>
</body>

View file

@ -102,13 +102,21 @@ body {
top: 10px;
left: 5px;
z-index: 5;
border-color: black;
border-width: 2px;
border-color: transparent;
border-width: 0px;
border-style: solid;
background-color: black;
background-color: transparent;
}
#scene-list button {
background-color: wheat;
border-width: 0px;
}
.exit-button {
height: fit-content;
align-self: center;
background-color: transparent;
font-size: 20px;
border: 0;
}

View file

@ -1,7 +1,21 @@
class Tavern {
// Callback definitions!
onlogin = (_loggedIn) => { };
onmessage = (_message) => { };
onspawntoken = (_spawnToken) => { };
onmovetoken = (_moveToken) => { };
onshowscene = (_scene) => { };
onscenelist = (_sceneList) => { };
onconnectedplayers = (_playersList) => { };
constructor() {
this.socket = new WebSocket('ws:/' + window.location.host + '/ws');
this.socket.onopen = () => this.connected = true;
this.socket.onclose = () => {
this.connected = false;
this.loggedIn = false;
this.call(this.onclose);
};
this.msgs = [];
this.connected = false;
this.loggedIn = false;
@ -36,6 +50,9 @@ class Tavern {
if (m.scene_list) {
this.call(this.onscenelist, m.scene_list);
}
if (m.connected_players) {
this.call(this.onconnectedplayers, m.connected_players);
}
}
}
call(f, ...args) {
@ -101,7 +118,7 @@ class Tavern {
}
get_scene = (id) => {
if (!this.connected || this.loggedIn) { return; }
this.socket.send(JSON.stringify({ get_scene: { id: id } }))
this.socket.send(JSON.stringify({ get_scene: { scene: id } }))
}
get_scene_list = () => {
if (!this.connected || this.loggedIn) { return; }
@ -120,9 +137,25 @@ class Tavern {
this.socket.send(JSON.stringify({ create_scene: { title: title } }));
}
shutdown = () => {
if (!this.connected || this.loggedIn) { return; }
if (!this.connected || this.loggedIn || !this.admin) { return; }
this.socket.send(JSON.stringify('shutdown'));
}
save = () => {
if (!this.connected || this.loggedIn || !this.admin) { return; }
this.socket.send(JSON.stringify('save'));
}
kick = (id) => {
if (!this.connected || this.loggedIn || !this.admin) { return; }
this.socket.send(JSON.stringify({ kick: id }));
}
show_scene = (id) => {
if (!this.connected || this.loggedIn || !this.admin) { return; }
this.socket.send(JSON.stringify({ show_scene: { scene: id } }));
}
set_scene_visible = (id, visible) => {
if (!this.connected || this.loggedIn || !this.admin) { return; }
this.socket.send(JSON.stringify({ set_scene_visible: { scene: id, visible: visible } }));
}
}
const tavern = new Tavern();