pushing unfinished work for the night

This commit is contained in:
TaiAurori 2022-06-24 23:25:49 -04:00
parent 27f4047cf7
commit 7e089795c7
14 changed files with 760 additions and 156 deletions

15
web/index.html Normal file
View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Tripwire Web Panel</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' media='screen' href='./web/main.css'>
<script src="https://unpkg.com/mithril/mithril.js"></script>
<script src="https://unpkg.com/js-cookie"></script>
<script src='./web/main.js' type="module"></script>
</head>
<body>
<noscript>JavaScript must be enabled to use this application.</noscript>
</body>
</html>

90
web/main.css Normal file
View file

@ -0,0 +1,90 @@
:root {
background-color: #222;
color: #CCC;
font-family: Arial, sans-serif;
--border-radius: 6px;
--header-height: 50px;
--accent-color: #5f00aa;
--accent-color-secondary: #4f0099;
--error-color: #cc4444;
}
body {
margin: 0;
}
header {
position: absolute;
width: 100%;
height: var(--header-height);
line-height: var(--header-height);
background-color: #141414;
align-items: center;
vertical-align: middle;
padding: 0px 15px;
box-sizing: border-box;
}
#header-spacer {
padding-bottom: var(--header-height);
}
#header-title {
font-size: 1.3em;
}
a {
color: inherit;
text-decoration: inherit;
}
.align-right {
float: right;
}
button, a.button {
background-color: var(--accent-color);
transition: background-color 0.3s;
color: inherit;
border: 0;
border-radius: var(--border-radius);
padding: 8px 10px;
cursor: pointer;
color: white;
}
button:hover, a.button:hover {
background-color: var(--accent-color-secondary);
}
input {
display: block;
background-color: #141414;
color: inherit;
border: 0;
border-radius: var(--border-radius);
padding: 8px 10px;
color: white;
margin-bottom: 5px;
}
.center {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
text-align: center;
}
.errorText {
color: var(--error-color);
display: block;
}
.errorInput {
outline: 1px solid var(--error-color);
}
#playerHead {
vertical-align: middle;
margin-top: -4px;
margin-right: 12px;
}

200
web/main.js Normal file
View file

@ -0,0 +1,200 @@
import htm from 'https://unpkg.com/htm?module'
const html = htm.bind(m);
var root = document.body
var currentUser = null;
try {
currentUser = JSON.parse(Cookies.get("currentUser"))
} catch {}
var loggingIn = false;
var logInError = ""
var PlayerHead = {
oncreate: function (vnode) {
const ctx = vnode.dom.getContext('2d');
ctx.imageSmoothingEnabled = false
let img = new Image();
img.src = `/getTexture/${currentUser.uuid}?type=skin`
img.onload = function(){
ctx.drawImage(img, 8, 8, 8, 8, 0, 0, 32, 32);
}
},
view: function(vnode) {
return html `
<canvas id="playerHead" width="32" height="32" />
`
}
}
var Header = {
view: function() {
return html`
<header>
<a href="#!/" id="header-title">Tripwire</span>
<div class="align-right">
${currentUser ?
html`
<${PlayerHead} />
<span>Hello, ${currentUser.username}</span>
` :
html`<a class="button" href="#!/login">Log In</a>`
}
</div>
</header>
<div id="header-spacer"></div>
`
}
}
var ErrorText = {
view: function(vnode) {
return html`
<span class="errorText">${vnode.attrs.error.errorMessage}</span>
`
}
}
m.route(root, "/", {
"/": {
view: function() {
return html`
<${Header} />
${currentUser ?
html`
<div class="center">
<a class="button" href="#!/skinchanger">Change skin</a>
</div>
` :
html`<span>Please log in to continue.</span>`
}
`
}
},
"/skinchanger": function SkinChanger() {
var pageError = null;
var success = false;
return {
view: function() {
if (!currentUser) {
m.route.set("/login")
}
return html`
<${Header} />
${currentUser ?
success ?
html `
<div class="center">
<span style="font-size: 1.5em;">Texture successfully uploaded!</span><br/><br/>
<a class="button" href="#!/">Go back</a>
</div>
` :
html`
<div class="center">
<span style="font-size: 1.5em;">Select Skin/Cape </span>
<span>(only .PNG supported)</span><br/><br/>
<input style="display: inline;"
type="radio"
id="skinRadio"
name="textureId"
value="skin"
checked
/>
<label for="skinRadio">Skin</label>
<input style="display: inline;"
type="radio"
id="capeRadio"
name="textureId"
value="cape"
/>
<label for="capeRadio">Cape</label>
<input id="textureFile"
style="width: 100%"
type="file"
accept="image/png"
onchange=${() => {
pageError = null
}}
/>
${pageError && html`<${ErrorText} error=${pageError}/>`}
<button onclick=${() => {
let input = document.getElementById("textureFile")
if (input.files.length == 0) {
return
}
let file = input.files[0]
let body = new FormData()
body.append("file", file)
body.append("token", currentUser.token)
m.request({
method: "POST",
url: "/setTexture/"+currentUser.uuid+"?type=" +
(document.getElementById("skinRadio").checked ? "skin" : "cape"),
body: body,
}).then((res) => {
success = true
}, (res) => {
pageError = res.response
})
}}>Let it rip</button>
</div>
` :
html`<span>Please log in to continue.</span>`
}
`
}
}
},
"/login": {
view: function() {
if (currentUser) {
m.route.set("/")
}
let oninput = () => {
logInError = null
}
return html`
<${Header} />
<div class="center">
<input id="usernameLogin"
placeholder="Username"
type="text"
class=${logInError && "errorInput"}
oninput=${oninput}
/>
<input id="passwordLogin"
placeholder="Password"
type="text"
class=${logInError && "errorInput"}
oninput=${oninput}
/>
${logInError && html`
<${ErrorText} error=${logInError} />
`}
<button disabled=${loggingIn} onclick=${function() {
loggingIn = true;
m.request({
method: "POST",
url: "/webapi/logIn",
body: {
username: document.getElementById("usernameLogin").value,
password: document.getElementById("passwordLogin").value,
}
})
.then(function(result) {
currentUser = result
Cookies.set("currentUser", JSON.stringify(result))
loggingIn = false
}, function(result) {
logInError = result.response
loggingIn = false
})
}}>Log In</button>
</div>
`
}
}
})