Compare commits
2 commits
e8291e15d9
...
af11db6f55
Author | SHA1 | Date | |
---|---|---|---|
af11db6f55 | |||
a6bfd86c24 |
6 changed files with 359 additions and 349 deletions
263
assets/web/app.js
Normal file
263
assets/web/app.js
Normal file
|
@ -0,0 +1,263 @@
|
|||
// init - game view (map)
|
||||
const GRID_SIZE = 200; // Grid size in pixels
|
||||
var mapScale = 1.0;
|
||||
var mapOffsetX = 0.0;
|
||||
var mapOffsetY = 0.0;
|
||||
var draggedToken = { token: null, offX: 0, offY: 0 };
|
||||
var draggedDiv = { div: null, offX: 0, offY: 0 };
|
||||
|
||||
function init() {
|
||||
let view = document.getElementById('game-view');
|
||||
view.onwheel = onGameViewScroll;
|
||||
view.onmousemove = onGameMouseMove;
|
||||
view.onmouseup = onGameMouseUp;
|
||||
view.oncontextmenu = () => false;
|
||||
// allow sending chat message using enter (and shift-enter for new line)
|
||||
document.getElementById('newmsg-content').onkeypress = (e) => {
|
||||
if(e.key == "Enter" && !e.shiftKey) {
|
||||
sendChatMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
document.getElementById('login-username').onkeypress = (e) => {
|
||||
if(e.key == 'Enter') {
|
||||
document.getElementById('login-pass').focus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
document.getElementById('login-pass').onkeypress = (e) => {
|
||||
if(e.key == 'Enter') {
|
||||
onLoginClick();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// focus on the username field for the sake of just pressing enter multiple times
|
||||
document.getElementById('login-username').focus();
|
||||
document.body.onclick = (e) => {
|
||||
document.getElementById('msg-context-menu').style.display = 'none';
|
||||
}
|
||||
document.body.onmousemove = onMoveableDivDrag;
|
||||
document.body.onmouseup = onMoveableDivMouseUp;
|
||||
// TODO: Remove when done dev-ing
|
||||
tavern.onmessage({ text: 'test', id: 1, source: 'rusty', character: 'bart' });
|
||||
}
|
||||
|
||||
tavern.onlogin = (s) => {
|
||||
if(s) {
|
||||
let login = document.getElementById('login-screen');
|
||||
let game = document.getElementById('game');
|
||||
login.style.display = 'none';
|
||||
game.style.display = 'flex';
|
||||
// get last 50 msgs (i think that is enough for now) when we get in
|
||||
tavern.get_last_msgs(50);
|
||||
tavern.get_tokens();
|
||||
}
|
||||
else {
|
||||
alert("Invalid username or password!");
|
||||
}
|
||||
}
|
||||
tavern.onmessage = (m) => {
|
||||
console.log(m);
|
||||
let msg = document.createElement('div');
|
||||
msg.className = 'chat-message';
|
||||
// #abusing_style_order_as_both_id_variable_and_forcing_chronological_order
|
||||
msg.style.order = m.id;
|
||||
msg.innerHTML = `
|
||||
<p style='align-self: center; margin: 4px 0;'>
|
||||
<b>${m.character ?? ''}</b>
|
||||
(${m.source})
|
||||
</p>
|
||||
<hr style='width: 75%;' />
|
||||
<p style='margin: 4px 2px;'>
|
||||
${m.text.replace('\n', '\n<br>\n')}
|
||||
</p>
|
||||
`
|
||||
msg.oncontextmenu = (e) => {
|
||||
if(e.shiftKey) { return true; }
|
||||
let cm = document.getElementById('msg-context-menu');
|
||||
cm.style.display = 'flex';
|
||||
cm.style.top = `${e.pageY}px`;
|
||||
cm.style.left = `${e.pageX}px`;
|
||||
return false;
|
||||
}
|
||||
if(m.actions) {
|
||||
let holder = document.createElement('div');
|
||||
holder.style.display = 'flex';
|
||||
holder.style.flexWrap = 'wrap';
|
||||
msg.appendChild(holder);
|
||||
for (const act of m.actions) {
|
||||
let button = document.createElement('button');
|
||||
button.innerText = act.display_name ?? act.name;
|
||||
button.action = act;
|
||||
button.onclick = () => console.log(button.action);
|
||||
button.style.margin = '2px';
|
||||
button.onclick = () => openRollsPopup(act);
|
||||
holder.appendChild(button);
|
||||
}
|
||||
}
|
||||
let history = document.getElementById('chat-history');
|
||||
// this is to force update everytime we get a duplicate msg to allow msg editing (yay)
|
||||
let exists = Array.from(history.children).filter(e => e.style.order == m.id)[0];
|
||||
if(exists) {
|
||||
history.removeChild(exists);
|
||||
}
|
||||
history.appendChild(msg);
|
||||
msg.scrollIntoView();
|
||||
}
|
||||
tavern.onspawntoken = (t) => {
|
||||
console.log(t);
|
||||
let map = document.getElementById('map');
|
||||
let token = document.createElement('div');
|
||||
token.className = 'token token-transition';
|
||||
token.style.top = `${t.y * GRID_SIZE}px`;
|
||||
token.style.left = `${t.x * GRID_SIZE}px`;
|
||||
token.token_id = t.token_id;
|
||||
token.innerHTML = `
|
||||
<img src='data:image/jpg;base64,${t.img}' ondragstart='return false;'>
|
||||
`
|
||||
token.onmousedown = (e) => {
|
||||
token.classList.remove('token-transition');
|
||||
draggedToken.token = token;
|
||||
draggedToken.offX = ((e.clientX - mapOffsetX) / mapScale) - parseInt(token.style.left);
|
||||
draggedToken.offY = ((e.clientY - mapOffsetY) / mapScale) - parseInt(token.style.top);
|
||||
token.children[0].style.cursor = 'grabbing';
|
||||
}
|
||||
map.appendChild(token);
|
||||
}
|
||||
tavern.onmovetoken = (m) => {
|
||||
let token = Array.from(document.getElementsByClassName('token')).filter(t => t.token_id == m.token_id)[0]
|
||||
if(token) {
|
||||
token.style.top = `${m.y * GRID_SIZE}px`;
|
||||
token.style.left = `${m.x * GRID_SIZE}px`;
|
||||
}
|
||||
}
|
||||
function onLoginClick() {
|
||||
let username = document.getElementById('login-username').value;
|
||||
let pass = document.getElementById('login-pass').value;
|
||||
if(username == 'test') {
|
||||
// TODO: Remove this for when im done dev-ing with this file
|
||||
tavern.onlogin(true);
|
||||
}
|
||||
tavern.login(username, pass);
|
||||
}
|
||||
function onGameViewScroll(event) {
|
||||
let map = document.getElementById('map');
|
||||
mapScale += (event.wheelDelta / 1800.0);
|
||||
if(mapScale < 0.1) { mapScale = 0.1; }
|
||||
map.style.transform = `scale(${mapScale})`;
|
||||
}
|
||||
function onGameMouseMove(event) {
|
||||
if(event.buttons == 2) {
|
||||
// right click
|
||||
let map = document.getElementById('map');
|
||||
let mult = event.ctrlKey ? 2.0 : 1.0;
|
||||
mapOffsetX += event.movementX * mult;
|
||||
mapOffsetY += event.movementY * mult;
|
||||
map.style.left = `${mapOffsetX}px`;
|
||||
map.style.top = `${mapOffsetY}px`;
|
||||
}
|
||||
else if(draggedToken.token != null && event.buttons == 1) {
|
||||
let top = (event.clientY - mapOffsetY) / mapScale - draggedToken.offY;
|
||||
let left = (event.clientX - mapOffsetX) / mapScale - draggedToken.offX;
|
||||
draggedToken.token.style.top = `${top}px`;
|
||||
draggedToken.token.style.left = `${left}px`;
|
||||
}
|
||||
}
|
||||
function onGameMouseUp() {
|
||||
if(draggedToken.token != null) {
|
||||
let t = draggedToken.token;
|
||||
let x = Math.floor(0.5 + parseInt(t.style.left) / GRID_SIZE);
|
||||
let y = Math.floor(0.5 + parseInt(t.style.top) / GRID_SIZE);
|
||||
let id = t.token_id;
|
||||
t.classList.add('token-transition');
|
||||
t.children[0].style.cursor = '';
|
||||
tavern.move_token(id, x, y);
|
||||
draggedToken.token = null;
|
||||
}
|
||||
}
|
||||
function sendChatMessage() {
|
||||
let tb = document.getElementById('newmsg-content');
|
||||
// get the msg and reset the textarea
|
||||
let text = tb.value;
|
||||
tb.value = '';
|
||||
tavern.simple_msg(text);
|
||||
}
|
||||
function openRollsPopup(action) {
|
||||
let holder = document.getElementById('dice-roll-holder');
|
||||
holder.innerHTML = ''; // remove all holder children
|
||||
holder.action = action;
|
||||
if(action.rolls != undefined && Array.isArray(action.rolls)) {
|
||||
for (const r of action.rolls) {
|
||||
// name (extra) (dice_amount)d(dice_type) + constant | enabled
|
||||
console.log(r);
|
||||
let row = document.createElement('div');
|
||||
row.style.display = 'flex';
|
||||
row.roll = r;
|
||||
row.innerHTML = `
|
||||
<p style='flex-grow: 1;'>${r.name} ${r.extra != null ? '(' + r.extra + ')' : ''}</p>
|
||||
<p style='margin-right: 8px;'>${r.dice_amount}d${r.dice_type} + ${r.constant}</p>
|
||||
<input type='checkbox' ${r.enabled ? 'checked' : ''} />
|
||||
`;
|
||||
holder.appendChild(row);
|
||||
}
|
||||
}
|
||||
document.getElementById('dice-roll-title').innerText = action.display_name ?? action.name;
|
||||
document.getElementById('dice-roll-popup').style.display = 'flex';
|
||||
}
|
||||
function rollPopup() {
|
||||
// TODO: Maybe let the server roll the dice?
|
||||
// first - hide the popup
|
||||
document.getElementById('dice-roll-popup').style.display = 'none';
|
||||
// get the holder and start rolling dice
|
||||
let rolls = [];
|
||||
let holder = document.getElementById('dice-roll-holder');
|
||||
for(const h of holder.children) {
|
||||
if(h.roll && h.children[2].checked) {
|
||||
let roll = { name: h.roll.name, extra: h.roll.extra };
|
||||
let msg = '';
|
||||
let sum = 0;
|
||||
for (let i = 0; i < h.roll.dice_amount; i++) {
|
||||
// Math.random gives a value in [0, 1), so we need to add 1 at the end
|
||||
let roll = Math.floor(Math.random() * h.roll.dice_type) + 1;
|
||||
sum += roll;
|
||||
msg += `${roll}`;
|
||||
if(i != h.roll.dice_amount - 1 || h.roll.constant != 0) {
|
||||
msg += ' + ';
|
||||
}
|
||||
}
|
||||
if(h.roll.constant != 0) {
|
||||
sum += h.roll.constant;
|
||||
msg += `${h.roll.constant}`;
|
||||
}
|
||||
roll.result = sum;
|
||||
roll.result_text = msg;
|
||||
rolls.push(roll);
|
||||
}
|
||||
}
|
||||
console.log(rolls);
|
||||
tavern.action_result(holder.action.name, 'Louise', [], rolls);
|
||||
}
|
||||
function onMoveableDivMouseDown(e, id) {
|
||||
if(e.buttons == 1) {
|
||||
let div = document.getElementById(id);
|
||||
let rect = div.getBoundingClientRect();
|
||||
draggedDiv.div = div;
|
||||
draggedDiv.offX = e.clientX - rect.x;
|
||||
draggedDiv.offY = e.clientY - rect.y;
|
||||
|
||||
}
|
||||
}
|
||||
function onMoveableDivDrag(e) {
|
||||
if(draggedDiv.div) {
|
||||
draggedDiv.div.style.right = '';
|
||||
draggedDiv.div.style.top = `${e.clientY - draggedDiv.offY}px`;
|
||||
draggedDiv.div.style.left = `${e.clientX - draggedDiv.offX}px`;
|
||||
}
|
||||
}
|
||||
function onMoveableDivMouseUp(e, id) {
|
||||
draggedDiv.div = null;
|
||||
}
|
||||
function showHideDiv(id) {
|
||||
let div = document.getElementById(id);
|
||||
div.style.display = div.style.display == 'none' ? 'flex' : 'none';
|
||||
}
|
|
@ -1,351 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="./socket.js"></script>
|
||||
<script>
|
||||
// init - game view (map)
|
||||
const GRID_SIZE = 200; // Grid size in pixels
|
||||
var mapScale = 1.0;
|
||||
var mapOffsetX = 0.0;
|
||||
var mapOffsetY = 0.0;
|
||||
var draggedToken = { token: null, offX: 0, offY: 0 };
|
||||
var draggedDiv = { div: null, offX: 0, offY: 0 };
|
||||
|
||||
function init() {
|
||||
let view = document.getElementById('game-view');
|
||||
view.onwheel = onGameViewScroll;
|
||||
view.onmousemove = onGameMouseMove;
|
||||
view.onmouseup = onGameMouseUp;
|
||||
view.oncontextmenu = () => false;
|
||||
// allow sending chat message using enter (and shift-enter for new line)
|
||||
document.getElementById('newmsg-content').onkeypress = (e) => {
|
||||
if(e.key == "Enter" && !e.shiftKey) {
|
||||
sendChatMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
document.getElementById('login-username').onkeypress = (e) => {
|
||||
if(e.key == 'Enter') {
|
||||
document.getElementById('login-pass').focus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
document.getElementById('login-pass').onkeypress = (e) => {
|
||||
if(e.key == 'Enter') {
|
||||
onLoginClick();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// focus on the username field for the sake of just pressing enter multiple times
|
||||
document.getElementById('login-username').focus();
|
||||
document.body.onclick = (e) => {
|
||||
document.getElementById('msg-context-menu').style.display = 'none';
|
||||
}
|
||||
document.body.onmousemove = onMoveableDivDrag;
|
||||
document.body.onmouseup = onMoveableDivMouseUp;
|
||||
// TODO: Remove when done dev-ing
|
||||
tavern.onmessage({ text: 'test', id: 1, source: 'rusty', character: 'bart' });
|
||||
}
|
||||
|
||||
tavern.onlogin = (s) => {
|
||||
if(s) {
|
||||
let login = document.getElementById('login-screen');
|
||||
let game = document.getElementById('game');
|
||||
login.style.display = 'none';
|
||||
game.style.display = 'flex';
|
||||
// get last 50 msgs (i think that is enough for now) when we get in
|
||||
tavern.get_last_msgs(50);
|
||||
tavern.get_tokens();
|
||||
}
|
||||
else {
|
||||
alert("Invalid username or password!");
|
||||
}
|
||||
}
|
||||
tavern.onmessage = (m) => {
|
||||
console.log(m);
|
||||
let msg = document.createElement('div');
|
||||
msg.className = 'chat-message';
|
||||
// #abusing_style_order_as_both_id_variable_and_forcing_chronological_order
|
||||
msg.style.order = m.id;
|
||||
msg.innerHTML = `
|
||||
<p style='align-self: center; margin: 4px 0;'>
|
||||
<b>${m.character ?? ''}</b>
|
||||
(${m.source})
|
||||
</p>
|
||||
<hr style='width: 75%;' />
|
||||
<p style='margin: 4px 2px;'>
|
||||
${m.text.replace('\n', '\n<br>\n')}
|
||||
</p>
|
||||
`
|
||||
msg.oncontextmenu = (e) => {
|
||||
if(e.shiftKey) { return true; }
|
||||
let cm = document.getElementById('msg-context-menu');
|
||||
cm.style.display = 'flex';
|
||||
cm.style.top = `${e.pageY}px`;
|
||||
cm.style.left = `${e.pageX}px`;
|
||||
return false;
|
||||
}
|
||||
if(m.actions) {
|
||||
let holder = document.createElement('div');
|
||||
holder.style.display = 'flex';
|
||||
holder.style.flexWrap = 'wrap';
|
||||
msg.appendChild(holder);
|
||||
for (const act of m.actions) {
|
||||
let button = document.createElement('button');
|
||||
button.innerText = act.display_name ?? act.name;
|
||||
button.action = act;
|
||||
button.onclick = () => console.log(button.action);
|
||||
button.style.margin = '2px';
|
||||
button.onclick = () => openRollsPopup(act);
|
||||
holder.appendChild(button);
|
||||
}
|
||||
}
|
||||
let history = document.getElementById('chat-history');
|
||||
// this is to force update everytime we get a duplicate msg to allow msg editing (yay)
|
||||
let exists = Array.from(history.children).filter(e => e.style.order == m.id)[0];
|
||||
if(exists) {
|
||||
history.removeChild(exists);
|
||||
}
|
||||
history.appendChild(msg);
|
||||
msg.scrollIntoView();
|
||||
}
|
||||
tavern.onspawntoken = (t) => {
|
||||
console.log(t);
|
||||
let map = document.getElementById('map');
|
||||
let token = document.createElement('div');
|
||||
token.className = 'token token-transition';
|
||||
token.style.top = `${t.y * GRID_SIZE}px`;
|
||||
token.style.left = `${t.x * GRID_SIZE}px`;
|
||||
token.token_id = t.token_id;
|
||||
token.innerHTML = `
|
||||
<img src='data:image/jpg;base64,${t.img}' ondragstart='return false;'>
|
||||
`
|
||||
token.onmousedown = (e) => {
|
||||
token.classList.remove('token-transition');
|
||||
draggedToken.token = token;
|
||||
draggedToken.offX = ((e.clientX - mapOffsetX) / mapScale) - parseInt(token.style.left);
|
||||
draggedToken.offY = ((e.clientY - mapOffsetY) / mapScale) - parseInt(token.style.top);
|
||||
token.children[0].style.cursor = 'grabbing';
|
||||
}
|
||||
map.appendChild(token);
|
||||
}
|
||||
tavern.onmovetoken = (m) => {
|
||||
let token = Array.from(document.getElementsByClassName('token')).filter(t => t.token_id == m.token_id)[0]
|
||||
if(token) {
|
||||
token.style.top = `${m.y * GRID_SIZE}px`;
|
||||
token.style.left = `${m.x * GRID_SIZE}px`;
|
||||
}
|
||||
}
|
||||
function onLoginClick() {
|
||||
let username = document.getElementById('login-username').value;
|
||||
let pass = document.getElementById('login-pass').value;
|
||||
if(username == 'test') {
|
||||
// TODO: Remove this for when im done dev-ing with this file
|
||||
tavern.onlogin(true);
|
||||
}
|
||||
tavern.login(username, pass);
|
||||
}
|
||||
function onGameViewScroll(event) {
|
||||
let map = document.getElementById('map');
|
||||
mapScale += (event.wheelDelta / 1800.0);
|
||||
if(mapScale < 0.1) { mapScale = 0.1; }
|
||||
map.style.transform = `scale(${mapScale})`;
|
||||
}
|
||||
function onGameMouseMove(event) {
|
||||
if(event.buttons == 2) {
|
||||
// right click
|
||||
let map = document.getElementById('map');
|
||||
let mult = event.ctrlKey ? 2.0 : 1.0;
|
||||
mapOffsetX += event.movementX * mult;
|
||||
mapOffsetY += event.movementY * mult;
|
||||
map.style.left = `${mapOffsetX}px`;
|
||||
map.style.top = `${mapOffsetY}px`;
|
||||
}
|
||||
else if(draggedToken.token != null && event.buttons == 1) {
|
||||
let top = (event.clientY - mapOffsetY) / mapScale - draggedToken.offY;
|
||||
let left = (event.clientX - mapOffsetX) / mapScale - draggedToken.offX;
|
||||
draggedToken.token.style.top = `${top}px`;
|
||||
draggedToken.token.style.left = `${left}px`;
|
||||
}
|
||||
}
|
||||
function onGameMouseUp() {
|
||||
if(draggedToken.token != null) {
|
||||
let t = draggedToken.token;
|
||||
let x = Math.floor(0.5 + parseInt(t.style.left) / GRID_SIZE);
|
||||
let y = Math.floor(0.5 + parseInt(t.style.top) / GRID_SIZE);
|
||||
let id = t.token_id;
|
||||
t.classList.add('token-transition');
|
||||
t.children[0].style.cursor = '';
|
||||
tavern.move_token(id, x, y);
|
||||
draggedToken.token = null;
|
||||
}
|
||||
}
|
||||
function sendChatMessage() {
|
||||
let tb = document.getElementById('newmsg-content');
|
||||
// get the msg and reset the textarea
|
||||
let text = tb.value;
|
||||
tb.value = '';
|
||||
tavern.simple_msg(text);
|
||||
}
|
||||
function openRollsPopup(action) {
|
||||
let holder = document.getElementById('dice-roll-holder');
|
||||
holder.innerHTML = ''; // remove all holder children
|
||||
holder.action = action;
|
||||
if(action.rolls != undefined && Array.isArray(action.rolls)) {
|
||||
for (const r of action.rolls) {
|
||||
// name (extra) (dice_amount)d(dice_type) + constant | enabled
|
||||
console.log(r);
|
||||
let row = document.createElement('div');
|
||||
row.style.display = 'flex';
|
||||
row.roll = r;
|
||||
row.innerHTML = `
|
||||
<p style='flex-grow: 1;'>${r.name} ${r.extra != null ? '(' + r.extra + ')' : ''}</p>
|
||||
<p style='margin-right: 8px;'>${r.dice_amount}d${r.dice_type} + ${r.constant}</p>
|
||||
<input type='checkbox' ${r.enabled ? 'checked' : ''} />
|
||||
`;
|
||||
holder.appendChild(row);
|
||||
}
|
||||
}
|
||||
document.getElementById('dice-roll-title').innerText = action.display_name ?? action.name;
|
||||
document.getElementById('dice-roll-popup').style.display = 'flex';
|
||||
}
|
||||
function rollPopup() {
|
||||
// TODO: Maybe let the server roll the dice?
|
||||
// first - hide the popup
|
||||
document.getElementById('dice-roll-popup').style.display = 'none';
|
||||
// get the holder and start rolling dice
|
||||
let rolls = [];
|
||||
let holder = document.getElementById('dice-roll-holder');
|
||||
for(const h of holder.children) {
|
||||
if(h.roll && h.children[2].checked) {
|
||||
let roll = { name: h.roll.name, extra: h.roll.extra };
|
||||
let msg = '';
|
||||
let sum = 0;
|
||||
for (let i = 0; i < h.roll.dice_amount; i++) {
|
||||
// Math.random gives a value in [0, 1), so we need to add 1 at the end
|
||||
let roll = Math.floor(Math.random() * h.roll.dice_type) + 1;
|
||||
sum += roll;
|
||||
msg += `${roll}`;
|
||||
if(i != h.roll.dice_amount - 1 || h.roll.constant != 0) {
|
||||
msg += ' + ';
|
||||
}
|
||||
}
|
||||
if(h.roll.constant != 0) {
|
||||
sum += h.roll.constant;
|
||||
msg += `${h.roll.constant}`;
|
||||
}
|
||||
roll.result = sum;
|
||||
roll.result_text = msg;
|
||||
rolls.push(roll);
|
||||
}
|
||||
}
|
||||
console.log(rolls);
|
||||
tavern.action_result(holder.action.name, 'Louise', [], rolls);
|
||||
}
|
||||
function onMoveableDivMouseDown(e, id) {
|
||||
if(e.buttons == 1) {
|
||||
let div = document.getElementById(id);
|
||||
let rect = div.getBoundingClientRect();
|
||||
draggedDiv.div = div;
|
||||
draggedDiv.offX = e.clientX - rect.x;
|
||||
draggedDiv.offY = e.clientY - rect.y;
|
||||
|
||||
}
|
||||
}
|
||||
function onMoveableDivDrag(e) {
|
||||
if(draggedDiv.div) {
|
||||
draggedDiv.div.style.right = '';
|
||||
draggedDiv.div.style.top = `${e.clientY - draggedDiv.offY}px`;
|
||||
draggedDiv.div.style.left = `${e.clientX - draggedDiv.offX}px`;
|
||||
}
|
||||
}
|
||||
function onMoveableDivMouseUp(e, id) {
|
||||
draggedDiv.div = null;
|
||||
}
|
||||
function showHideDiv(id) {
|
||||
let div = document.getElementById(id);
|
||||
div.style.display = div.style.display == 'none' ? 'flex' : 'none';
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
body{
|
||||
background-color: rgb(32, 35, 35);
|
||||
color: white;
|
||||
}
|
||||
#side-panel {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
resize: horizontal;
|
||||
overflow: auto;
|
||||
border: 0px solid black;
|
||||
width: 20%;
|
||||
min-width: 10%;
|
||||
max-width: 50%;
|
||||
background-image: linear-gradient(135deg, #0f0f2f 0px, #0f0f2f 99%, rgb(188, 255, 185) 100%);
|
||||
}
|
||||
#chat-history {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
resize: none;
|
||||
overflow: auto;
|
||||
margin-top: 10px;
|
||||
background-color:#0f0f2f;
|
||||
}
|
||||
.chat-message {
|
||||
background-color: #ffffd6;
|
||||
color: #000000;
|
||||
border-width: 2px;
|
||||
border-color: rgb(73, 49, 49);
|
||||
border-style: solid;
|
||||
border-radius: 8px;
|
||||
padding: 4px 16px;
|
||||
margin: 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#msg-context-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
padding: 4px;
|
||||
}
|
||||
#msg-context-menu ul {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
list-style: none;
|
||||
}
|
||||
#msg-context-menu ul li {
|
||||
padding: 4px;
|
||||
|
||||
}
|
||||
#msg-context-menu ul li:hover {
|
||||
background: darkgray;
|
||||
cursor: pointer;
|
||||
}
|
||||
.token {
|
||||
position: absolute;
|
||||
}
|
||||
.token-transition {
|
||||
transition:
|
||||
top 0.5s ease-in,
|
||||
left 0.5s ease-in;
|
||||
}
|
||||
.token img {
|
||||
cursor: grab;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="./style.css">
|
||||
<script src="./tavern.js"></script>
|
||||
<script src="./app.js"></script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<!-- 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;" >
|
||||
<input type="text" id="login-username" placeholder="Username..." >
|
||||
|
@ -355,6 +16,7 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- GAME VIEW PAGE -->
|
||||
<div id="game" style="display: none; width: 100%; height: 100%;" >
|
||||
<div id="side-panel">
|
||||
<div style="display: flex; flex-direction: column; width: calc(100% - 15px); height: 100%;" >
|
||||
|
@ -397,6 +59,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- FLOATY (game view) WINDOWS -->
|
||||
<div id="msg-context-menu" class="chat-message">
|
||||
<ul>
|
||||
<li>Delete (TODO)</li>
|
||||
|
|
74
assets/web/style.css
Normal file
74
assets/web/style.css
Normal file
|
@ -0,0 +1,74 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
body{
|
||||
background-color: rgb(32, 35, 35);
|
||||
color: white;
|
||||
}
|
||||
#side-panel {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
resize: horizontal;
|
||||
overflow: auto;
|
||||
border: 0px solid black;
|
||||
width: 20%;
|
||||
min-width: 10%;
|
||||
max-width: 50%;
|
||||
background-image: linear-gradient(135deg, #0f0f2f 0px, #0f0f2f 99%, rgb(188, 255, 185) 100%);
|
||||
}
|
||||
#chat-history {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
resize: none;
|
||||
overflow: auto;
|
||||
margin-top: 10px;
|
||||
background-color:#0f0f2f;
|
||||
}
|
||||
.chat-message {
|
||||
background-color: #ffffd6;
|
||||
color: #000000;
|
||||
border-width: 2px;
|
||||
border-color: rgb(73, 49, 49);
|
||||
border-style: solid;
|
||||
border-radius: 8px;
|
||||
padding: 4px 16px;
|
||||
margin: 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#msg-context-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
padding: 4px;
|
||||
}
|
||||
#msg-context-menu ul {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
list-style: none;
|
||||
}
|
||||
#msg-context-menu ul li {
|
||||
padding: 4px;
|
||||
|
||||
}
|
||||
#msg-context-menu ul li:hover {
|
||||
background: darkgray;
|
||||
cursor: pointer;
|
||||
}
|
||||
.token {
|
||||
position: absolute;
|
||||
}
|
||||
.token-transition {
|
||||
transition:
|
||||
top 0.5s ease-in,
|
||||
left 0.5s ease-in;
|
||||
}
|
||||
.token img {
|
||||
cursor: grab;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
|
@ -91,8 +91,9 @@ impl<'a, C: Character<A> + Serialize + Deserialize<'a>, A: entry::GameEntry + Se
|
|||
}
|
||||
|
||||
fn character_short(&self, character_id: usize) -> Option<CharacterShort> {
|
||||
// self.characters.get(character_id).map(|c| c.char)
|
||||
todo!()
|
||||
self.characters
|
||||
.get(character_id)
|
||||
.map(|c| c.short())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -12,7 +12,9 @@ async fn main() {
|
|||
let bsend2 = bsend.clone();
|
||||
let app = Router::new()
|
||||
.route("/", routing::get(root))
|
||||
.route("/socket.js", routing::get(socket))
|
||||
.route("/tavern.js", routing::get(socket))
|
||||
.route("/app.js", routing::get(app_js))
|
||||
.route("/style.css", routing::get(style))
|
||||
.route("/ws", routing::get(move |w| ws_handler(w, msend, bsend2.clone().subscribe())));
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await.unwrap();
|
||||
|
@ -135,7 +137,14 @@ async fn root() -> axum::response::Html<&'static str> {
|
|||
response::Html(include_str!("../assets/web/index.html"))
|
||||
}
|
||||
|
||||
async fn socket() -> &'static str {
|
||||
include_str!("../assets/web/socket.js")
|
||||
async fn socket() -> impl response::IntoResponse {
|
||||
([(axum::http::header::CONTENT_TYPE, "text/javascript")], include_str!("../assets/web/tavern.js"))
|
||||
}
|
||||
|
||||
async fn app_js() -> impl response::IntoResponse {
|
||||
([(axum::http::header::CONTENT_TYPE, "text/javascript")], include_str!("../assets/web/app.js"))
|
||||
}
|
||||
|
||||
async fn style() -> impl response::IntoResponse {
|
||||
([(axum::http::header::CONTENT_TYPE, "text/css")], include_str!("../assets/web/style.css"))
|
||||
}
|
Loading…
Reference in a new issue