Skip to content
This repository was archived by the owner on Apr 8, 2019. It is now read-only.

Commit 34cd7ac

Browse files
committedApr 11, 2018
Much better front-end
Ditch jQuery for Vue.js Use spectre.css for style Add .vscode folder because why not
1 parent 1d418c7 commit 34cd7ac

15 files changed

+4179
-266
lines changed
 

‎.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
.vscode
21
node_modules
32
config.json
43
stop-server

‎.todo

+15-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,23 @@ To Do:
99
- Get command from text input, create Websocket connection on "Go" button click and send command.
1010
- If command is valid, server executes it and responds with output, live.
1111
- End connection on command end.
12-
- Test with test.cmd for the time being
12+
- Test with test.cmd for the time being.
1313
✔ Make use of sourcequery @done(18-04-10 16:46)
1414
✔ Config page to modify all config.json variables on the fly @done(18-04-10 19:38)
1515
✔ "Authorization" header support, for Discord Bot and !rocket command? @done(18-04-10 21:07)
1616
✔ Wrap both WS and HTTP response into a same object for code readability @done(18-04-10 21:07)
17+
☐ Make good front-end
18+
✔ Use spectre.css @done(18-04-11 07:08)
19+
✔ Implement Vue.js @done(18-04-11 07:08)
20+
☐ Pug locals to clientside JavaScript
21+
☐ Find a better way than setting "values" manually everytime (see app.js:77)
22+
☐ Use mixins in Pug to avoid repetition and confusion (config.pug is especially confusing)
23+
☐ Add toasts / notifications to tell when command has ended or config has been saved
24+
☐ Customize navbar
25+
☐ Customize colors more
26+
☐ Center panels vertically
27+
☐ Check responsiveness
28+
☐ More?
1729
☐ Implement our own custom commands
18-
☐ Clean up code
19-
☐ Beautify page look (use some template or something, lazy)
30+
☐ Clean up code in general
31+

‎.vscode/launch.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "launch",
10+
"name": "Launch Program",
11+
"args": [],
12+
"program": "${workspaceFolder}\\bin\\www"
13+
}
14+
]
15+
}

‎.vscode/tasks.json

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Sass configuration
2+
{
3+
// See https://go.microsoft.com/fwlink/?LinkId=733558
4+
// for the documentation about the tasks.json format
5+
"version": "2.0.0",
6+
"options": {
7+
"shell": {
8+
"executable": "bash.exe",
9+
"args": [
10+
"-c"
11+
]
12+
}
13+
},
14+
"tasks": [
15+
{
16+
"label": "Sass Compile",
17+
"type": "shell",
18+
"command": "node-sass style.scss public/css/style.css",
19+
"group": {
20+
"kind": "build",
21+
"isDefault": true
22+
},
23+
"problemMatcher": [
24+
"$node-sass"
25+
]
26+
}
27+
]
28+
}

‎app.js

+11-7
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ app.use(steam.middleware({
4040
apiKey: app.config.apikey}
4141
))
4242
app.use((req, res, next) => {
43-
res.locals.user = req.user;
44-
next();
45-
});
43+
res.locals.user = req.user
44+
next()
45+
})
4646

4747
/* GET home page. */
4848

@@ -74,10 +74,12 @@ app.get("/", function(req, res) {
7474
sq.getPlayers(function(err, players) {
7575
server.players = players
7676

77-
res.render("index", {
77+
var locals = {
7878
server: server,
7979
util: util
80-
})
80+
}
81+
locals.values = JSON.stringify(locals)
82+
res.render("index", locals)
8183
})
8284
})
8385
})
@@ -136,9 +138,11 @@ app.get("/logout", steam.enforceLogin("/"), function(req, res) {
136138

137139
app.get("/config", function(req, res) {
138140
ifAuthed(req, res, function() {
139-
res.render("config", {
141+
var locals = {
140142
config: app.config
141-
})
143+
}
144+
locals.values = JSON.stringify(locals)
145+
res.render("config", locals)
142146
})
143147
})
144148

‎package-lock.json

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"morgan": "~1.9.0",
1717
"pug": "2.0.3",
1818
"sourcequery": "0.0.2",
19+
"spectre.css": "^0.5.1",
1920
"steam-login": "^0.1.7",
2021
"ws": "^5.1.1"
2122
}

‎public/css/style.css

+3,906-82
Large diffs are not rendered by default.
File renamed without changes.

‎public/img/logo.png

103 KB
Loading

‎public/js/main.js

+37-87
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,61 @@
11

2-
$(function() {
3-
var ws
4-
5-
$("input[name='cmd']").on("keyup", function(event) {
6-
if (event.key !== "Enter") return
7-
$("button[type='submit']").click()
8-
event.preventDefault()
9-
})
10-
11-
function togglePassword() {
12-
var option = $(this).parent().siblings("input[name='textinput']")
13-
if (option[0]) {
14-
option.attr("type", $(this).is(":checked") ? "text" : "password")
15-
}
16-
}
17-
function removeItem() {
18-
var item = $(this).parent()
19-
if (item[0] && item.is("li")) {
20-
item.remove()
21-
}
22-
}
23-
$("input[type='checkbox']").change(togglePassword)
24-
$("button[name='remove']").click(removeItem)
25-
$("button[name='add']").click(function() {
26-
var option = $(this).parents("div.config-option")
27-
if (option[0]) {
28-
var item = $("<li>")
29-
30-
var value = $("<input>")
31-
value.attr("type", option.attr("name") == "authorized" ? "password" : "text")
32-
value.appendTo(item)
33-
34-
var remove = $("<button>")
35-
remove.attr("name", "remove")
36-
remove.text("-")
37-
remove.click(removeItem)
38-
remove.appendTo(item)
39-
40-
if (option.attr("name") == "authorized") {
41-
value.attr("name", "textinput")
42-
43-
var label = $("<label>")
44-
var checkbox = $("<input>", {
45-
type: "checkbox",
46-
autocomplete: "off"
47-
})
48-
checkbox.change(togglePassword)
49-
checkbox.appendTo(label)
50-
label.append("Show")
51-
label.appendTo(item)
52-
}
53-
item.appendTo(option.find("ul"))
2+
document.addEventListener("DOMContentLoaded", function() {
3+
var app = new Vue({
4+
el: "#app",
5+
data: {
6+
displayAuthorized: "password",
7+
displayApiKey: "password",
8+
displaySecret: "password",
9+
10+
cmd: "",
11+
output: "",
12+
13+
config: pugLocals.config
14+
},
15+
methods: {
16+
sendCommand: function() {
17+
var app = this
18+
sendData(function() {
19+
ws.send(JSON.stringify({
20+
cmd: app.cmd
21+
}))
22+
})
23+
},
24+
sendConfig: function() {
25+
var app = this
26+
sendData(function() {
27+
ws.send(JSON.stringify({
28+
config: app.config
29+
}))
30+
})
31+
},
5432
}
5533
})
5634

57-
$("button[type='submit']").click(function() {
35+
var ws
36+
function sendData(callback) {
5837
if (!ws) {
59-
$("pre.output").empty()
38+
app.output = ""
6039
ws = new WebSocket("ws://" + location.host)
6140

6241
ws.onopen = function(event) {
6342
console.log("Connection opened")
6443

65-
switch (location.pathname) {
66-
case "/config": {
67-
var config = {}
68-
config.admins = []
69-
$("div.config-option[name='admins'] ul li input").map(function() {
70-
config.admins.push($(this).val())
71-
})
72-
config.authorized = []
73-
$("div.config-option[name='authorized'] ul li input").map(function() {
74-
config.authorized.push($(this).val())
75-
})
76-
config.apikey = $("div.config-option[name='apikey'] input[name='textinput']").val()
77-
config.secret = $("div.config-option[name='secret'] input[name='textinput']").val()
78-
config.server = $("div.config-option[name='server'] input[name='textinput']").val()
79-
var json = JSON.stringify({
80-
config: config
81-
})
82-
ws.send(json)
83-
break
84-
}
85-
case "/": {
86-
ws.send(JSON.stringify({
87-
cmd: $("input").val()
88-
}))
89-
break
90-
}
91-
default: {
92-
console.log("Nothing to do")
93-
ws.close()
94-
}
95-
}
44+
callback()
9645
}
9746

9847
ws.onerror = function(event) {
9948
console.log("Connection error")
10049
}
10150
ws.onmessage = function(event) {
102-
$("pre.output").append(event.data)
51+
app.output += event.data
10352
// console.log(event.data)
10453
}
10554
ws.onclose = function(event) {
10655
ws = undefined
10756
console.log("Connection closed")
10857
}
10958
}
110-
})
59+
}
11160
})
61+

‎style.scss

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
// Define variables to override default ones
3+
// https://github.com/picturepan2/spectre/blob/master/src/_variables.scss
4+
$primary-color: rgba(49, 108, 218, 1);
5+
$dark-color: rgb(53, 71, 104);
6+
7+
// Import full Spectre source code
8+
@import "node_modules/spectre.css/src/spectre";
9+
@import "node_modules/spectre.css/src/spectre-exp";
10+
@import "node_modules/spectre.css/src/spectre-icons";
11+
12+
.columns.cols-centered {
13+
justify-content: center;
14+
}
15+
.ml-auto {
16+
margin-left: auto;
17+
}
18+
.mr-auto {
19+
margin-right: auto;
20+
}
21+
.mx-auto {
22+
margin-left: auto;
23+
margin-right: auto;
24+
}
25+
.align-center {
26+
align-items: center;
27+
}
28+
.navbar {
29+
border-bottom: 1px solid $gray-color-light;
30+
}

‎views/config.pug

+65-45
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,68 @@
11
extends layout
22

33
block content
4-
h1 Re-Dream Control Panel Config
5-
h2 ONLY CHANGE THIS IF YOU KNOW WHAT YOU ARE DOING!
6-
| You are under the risk of making the control panel disfunctional by entering an invalid API key or accidentally removing yourself from the admin list.
7-
div.config-option(name="admins")
8-
h3 Admins
9-
button(name="add") #{"+"}
10-
| They are Steam users represented by their SteamID64.
11-
ul
12-
each admin in config.admins
13-
li
14-
input(type="text" value=admin)
15-
button(name="remove") #{"-"}
16-
div.config-option(name="authorized")
17-
h3 Authorized
18-
button(name="add") #{"+"}
19-
| Valid values you can pass to the "Authorization" header when POSTing to run commands.
20-
ul
21-
each authorized in config.authorized
22-
li
23-
input(name="textinput" type="password" value=authorized)
24-
button(name="remove") #{"-"}
25-
label
26-
input(type="checkbox" autocomplete="off")
27-
| Show
28-
div.config-option(name="apikey")
29-
h3 API Key:
30-
input(name="textinput" type="password" value=config.apikey)
31-
label
32-
input(type="checkbox" autocomplete="off")
33-
| Show
34-
div.config-option(name="secret")
35-
h3 Secret:
36-
input(name="textinput" type="password" value=config.secret)
37-
label
38-
input(type="checkbox" autocomplete="off")
39-
| Show
40-
div.config-option(name="server")
41-
h3 Server Address:
42-
input(name="textinput" type="text" value=config.server)
43-
br
44-
pre.output
45-
button(type="submit") Save
46-
br
47-
br
48-
a(href="/") Go home
4+
.container
5+
.columns.cols-centered
6+
.column.col-6.col-lg-12.col-xl-9
7+
.panel
8+
.panel-header.text-center
9+
h4.panel-title Configuration
10+
b.panel-subtitle ONLY CHANGE THIS IF YOU KNOW WHAT YOU ARE DOING!
11+
.panel-subtitle You are under the risk of making the control panel disfunctional by entering an invalid API key or accidentally removing yourself from the admin list.
12+
.panel-body
13+
.form-horizontal
14+
.form-group
15+
.col-4.col-sm-12
16+
.input-group.my-1.align-center
17+
button.btn.btn-primary.btn-sm(v-on:click="config.admins.push('')")
18+
i.icon.icon-plus
19+
label.form-label.ml-2 Administrators
20+
.col-8.col-sm-12
21+
.input-group.my-1(v-for="(item, index) in config.admins")
22+
input.form-input(type="text" v-model="config.admins[index]" placeholder="SteamID64")
23+
button.btn.btn-primary.input-group-btn(v-on:click="config.admins.splice(index, 1)")
24+
i.icon.icon-minus
25+
.form-group
26+
.col-4.col-sm-12
27+
.input-group.my-1.align-center
28+
button.btn.btn-primary.btn-sm(v-on:click="config.authorized.push('')")
29+
i.icon.icon-plus
30+
label.form-label.mx-2 Authorized
31+
label.form-checkbox
32+
input(type="checkbox" v-model="displayAuthorized" true-value="text" false-value="password")
33+
i.form-icon
34+
| Show
35+
.col-8.col-sm-12
36+
.input-group.my-1(v-for="(item, index) in config.authorized")
37+
input.form-input(v-bind:type="displayAuthorized" v-model="config.authorized[index]")
38+
button.btn.btn-primary.input-group-btn(v-on:click="config.authorized.splice(index, 1)")
39+
i.icon.icon-minus
40+
.form-group
41+
.col-4.col-sm-12
42+
label.form-label.my-1 API key
43+
.col-8.col-sm-12
44+
.input-group.my-1
45+
input.form-input(v-bind:type="displayApiKey" v-model="config.apikey")
46+
label.form-checkbox.ml-2.pr-0
47+
input(type="checkbox" v-model="displayApiKey" true-value="text" false-value="password")
48+
i.form-icon
49+
| Show
50+
.form-group
51+
.col-4.col-sm-12
52+
label.form-label.my-1 Secret
53+
.col-8.col-sm-12
54+
.input-group.my-1
55+
input.form-input(v-bind:type="displaySecret" v-model="config.secret")
56+
label.form-checkbox.ml-2.pr-0
57+
input(type="checkbox" v-model="displaySecret" true-value="text" false-value="password")
58+
i.form-icon
59+
| Show
60+
.form-group(name="address")
61+
.col-4.col-sm-12
62+
label.form-label.my-1 Server address
63+
.col-8.col-sm-12
64+
.input-group.my-1
65+
input.form-input(type="text" v-model="config.server")
66+
.panel-footer
67+
pre.code(v-html="output")
68+
button.btn.btn-primary.btn-block(type="submit" v-on:click="sendConfig") Save

‎views/index.pug

+48-34
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,51 @@
11
extends layout
22

33
block content
4-
h1 Re-Dream Control Panel
5-
p Welcome, <b>#{user.username}</b>! Is there anything you need to do today?
6-
pre.output
7-
input(type="text" name="cmd")
8-
button(type="submit") Go
9-
br
10-
br
11-
a(href="/logout") Log Out
12-
| #{" - "}
13-
a(href="/config") Config
14-
br
15-
br
16-
h2 Server status
17-
if server.info && server.players
18-
h3= server.info.name
19-
small
20-
| Map: <code>#{server.info.map}</code>
21-
br
22-
| <b>#{server.info.players}</b> players out of <b>#{server.info.maxplayers}</b>:
23-
if server.info.players > 0
24-
-
25-
function pad(num) {
26-
return ("00" + num).slice(-2)
27-
}
28-
pre
29-
each ply in server.players
30-
-
31-
var h = Math.floor(ply.online / 60 / 60)
32-
var m = Math.floor(ply.online / 60 - h * 60)
33-
var s = Math.floor(ply.online - m * 60 - h * 60 * 60)
34-
var time = h > 1 ? util.format("%s:%s:%s", pad(h), pad(m), pad(s)) : util.format("%s:%s", pad(m), pad(s));
35-
| #{ply.name} - #{time + "\n"}
36-
else
37-
h3 Server seems offline..?
4+
.container
5+
.columns.cols-centered
6+
.column.col-3
7+
.panel
8+
.panel-header.text-center
9+
h4.panel-title Control Panel
10+
.panel-body
11+
pre.code(v-html="output || 'Start with the help command.'")
12+
.panel-footer
13+
.input-group
14+
input.form-input(type="text" v-model="cmd" v-on:keyup.enter="sendCommand" placeholder="help")
15+
button.btn.btn-primary.input-group-btn(type="submit" v-on:click="sendCommand") Run
16+
.column.col-3
17+
.panel
18+
.panel-header.text-center
19+
h4.panel-title Server Status
20+
if server.info
21+
.panel-subtitle= server.info.name
22+
.panel-body
23+
if server.info && server.players
24+
pre.py-0.my-1
25+
.icon.icon-location.mx-1
26+
= server.info.map
27+
.py-0.my-1
28+
.icon.icon-people.mx-1
29+
= server.info.players + " / " + server.info.maxplayers
30+
.panel-footer
31+
if !server.info
32+
.text-error Server offline
33+
else if server.info && server.players
34+
if server.info.players > 0
35+
table.table.table-striped
36+
thead: tr
37+
th Name
38+
th Time online
39+
tbody: tr
40+
-
41+
function pad(num) {
42+
return ("00" + num).slice(-2)
43+
}
44+
each ply in server.players
45+
-
46+
var h = Math.floor(ply.online / 60 / 60)
47+
var m = Math.floor(ply.online / 60 - h * 60)
48+
var s = Math.floor(ply.online - m * 60 - h * 60 * 60)
49+
var time = h > 1 ? util.format("%s:%s:%s", pad(h), pad(m), pad(s)) : util.format("%s:%s", pad(m), pad(s));
50+
td= ply.name
51+
td= time

‎views/layout.pug

+18-7
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,22 @@ doctype html
22
html
33
head
44
title Re-Dream Control Panel
5-
link(rel="stylesheet", href="/css/style.css")
6-
if user && user.username
7-
script(src="http://code.jquery.com/jquery-3.3.1.min.js")
8-
script(src="/js/main.js")
5+
link(rel="stylesheet" href="/css/style.css")
6+
if values
7+
script var pugLocals = !{values.replace(/#<\//g, "<\\/")}
8+
script(src="http://code.jquery.com/jquery-3.3.1.min.js")
9+
script(src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js")
10+
script(src="/js/main.js")
911
body
10-
.container
11-
.content
12-
block content
12+
#app
13+
header.navbar
14+
section.navbar-section
15+
a.btn.btn-link(href="/") Home
16+
section.navbar-center
17+
img(src="/img/logo.png" height=32 style="padding: 4px;")
18+
section
19+
section.navbar-section
20+
a.btn.btn-link(href="/logout") Logout
21+
a.btn.btn-link(href="/config") Configuration
22+
h1.text-center Re-Dream
23+
block content

0 commit comments

Comments
 (0)
This repository has been archived.