mirror of https://github.com/dirtbags/moth.git
URL in scoreboard (configurable)
This commit is contained in:
parent
d18de0fe8b
commit
bb4859e7a9
|
@ -113,36 +113,7 @@ input:invalid {
|
||||||
cursor: help;
|
cursor: help;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Scoreboard */
|
/** Development mode information */
|
||||||
#rankings {
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
#rankings div:nth-child(6n){
|
|
||||||
background-color: #8881;
|
|
||||||
}
|
|
||||||
#rankings div:nth-child(6n+3) {
|
|
||||||
background-color: #0f01;
|
|
||||||
}
|
|
||||||
#rankings span.teamname {
|
|
||||||
height: auto;
|
|
||||||
font-size: inherit;
|
|
||||||
color: white;
|
|
||||||
background-color: #000e;
|
|
||||||
border-radius: 3px;
|
|
||||||
position: absolute;
|
|
||||||
right: 0.2em;
|
|
||||||
}
|
|
||||||
#rankings div * {white-space: nowrap;}
|
|
||||||
.cat0, .cat8, .cat16 {background-color: #a6cee3; color: black;}
|
|
||||||
.cat1, .cat9, .cat17 {background-color: #1f78b4; color: white;}
|
|
||||||
.cat2, .cat10, .cat18 {background-color: #b2df8a; color: black;}
|
|
||||||
.cat3, .cat11, .cat19 {background-color: #33a02c; color: white;}
|
|
||||||
.cat4, .cat12, .cat20 {background-color: #fb9a99; color: black;}
|
|
||||||
.cat5, .cat13, .cat21 {background-color: #e31a1c; color: white;}
|
|
||||||
.cat6, .cat14, .cat22 {background-color: #fdbf6f; color: black;}
|
|
||||||
.cat7, .cat15, .cat23 {background-color: #ff7f00; color: black;}
|
|
||||||
|
|
||||||
.debug {
|
.debug {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
@ -203,11 +174,9 @@ li[draggable] {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
@media (prefers-color-scheme: light) {
|
||||||
/*
|
/* We uses the alpha channel to apply hue tinting to elements, to get a
|
||||||
* This uses the alpha channel to apply hue tinting to elements, to get a
|
|
||||||
* similar effect in light or dark mode. That means there aren't a whole lot of
|
* similar effect in light or dark mode. That means there aren't a whole lot of
|
||||||
* things to change between light and dark mode.
|
* things to change between light and dark mode.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
body {
|
body {
|
||||||
background-color: #b9cbd8;
|
background-color: #b9cbd8;
|
||||||
|
|
|
@ -5,6 +5,9 @@ const Millisecond = 1
|
||||||
const Second = Millisecond * 1000
|
const Second = Millisecond * 1000
|
||||||
const Minute = Second * 60
|
const Minute = Second * 60
|
||||||
|
|
||||||
|
/** URL to the top of this MOTH server */
|
||||||
|
const BaseURL = new URL(".", location)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a transient message to the user.
|
* Display a transient message to the user.
|
||||||
*
|
*
|
||||||
|
@ -53,11 +56,29 @@ function Truthy(s) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the configuration object for this theme.
|
||||||
|
*
|
||||||
|
* @returns {Promise.<Object>}
|
||||||
|
*/
|
||||||
|
async function Config() {
|
||||||
|
let resp = await fetch(
|
||||||
|
new URL("config.json", BaseURL),
|
||||||
|
{
|
||||||
|
cache: "no-cache"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return resp.json()
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Millisecond,
|
Millisecond,
|
||||||
Second,
|
Second,
|
||||||
Minute,
|
Minute,
|
||||||
|
BaseURL,
|
||||||
Toast,
|
Toast,
|
||||||
WhenDOMLoaded,
|
WhenDOMLoaded,
|
||||||
Truthy,
|
Truthy,
|
||||||
|
Config,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
"TrackSolved": true,
|
"TrackSolved": true,
|
||||||
|
"URLInScoreboard": true,
|
||||||
"__sentry__": "this is here so you don't have to remember to take the comma off the last item"
|
"__sentry__": "this is here so you don't have to remember to take the comma off the last item"
|
||||||
}
|
}
|
|
@ -6,7 +6,6 @@ import * as common from "./common.mjs"
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
constructor(basePath=".") {
|
constructor(basePath=".") {
|
||||||
this.configURL = new URL("config.json", location)
|
|
||||||
this.config = {}
|
this.config = {}
|
||||||
|
|
||||||
this.server = new moth.Server(basePath)
|
this.server = new moth.Server(basePath)
|
||||||
|
@ -74,8 +73,7 @@ class App {
|
||||||
* load, since configuration should (hopefully) change less frequently.
|
* load, since configuration should (hopefully) change less frequently.
|
||||||
*/
|
*/
|
||||||
async UpdateConfig() {
|
async UpdateConfig() {
|
||||||
let resp = await fetch(this.configURL)
|
this.config = await common.Config()
|
||||||
this.config = await resp.json()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,7 +148,7 @@ class App {
|
||||||
for (let puzzle of this.state.Puzzles(cat)) {
|
for (let puzzle of this.state.Puzzles(cat)) {
|
||||||
let i = l.appendChild(document.createElement("li"))
|
let i = l.appendChild(document.createElement("li"))
|
||||||
|
|
||||||
let url = new URL("puzzle.html", window.location)
|
let url = new URL("puzzle.html", common.BaseURL)
|
||||||
url.hash = `${puzzle.Category}:${puzzle.Points}`
|
url.hash = `${puzzle.Category}:${puzzle.Points}`
|
||||||
let a = i.appendChild(document.createElement("a"))
|
let a = i.appendChild(document.createElement("a"))
|
||||||
a.textContent = puzzle.Points
|
a.textContent = puzzle.Points
|
||||||
|
|
|
@ -542,6 +542,7 @@ class Server {
|
||||||
return fetch(url, {
|
return fetch(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body,
|
body,
|
||||||
|
cache: "no-cache",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ function writeObject(e, obj) {
|
||||||
*/
|
*/
|
||||||
async function loadPuzzle(category, points) {
|
async function loadPuzzle(category, points) {
|
||||||
console.groupCollapsed("Loading puzzle:", category, points)
|
console.groupCollapsed("Loading puzzle:", category, points)
|
||||||
let contentBase = new URL(`content/${category}/${points}/`, location)
|
let contentBase = new URL(`content/${category}/${points}/`, common.BaseURL)
|
||||||
|
|
||||||
// Tell user we're loading
|
// Tell user we're loading
|
||||||
puzzleElement().appendChild(document.createElement("progress"))
|
puzzleElement().appendChild(document.createElement("progress"))
|
||||||
|
@ -209,7 +209,7 @@ async function init() {
|
||||||
|
|
||||||
// Make all links absolute, because we're going to be changing the base URL
|
// Make all links absolute, because we're going to be changing the base URL
|
||||||
for (let e of document.querySelectorAll("[href]")) {
|
for (let e of document.querySelectorAll("[href]")) {
|
||||||
e.href = new URL(e.href, location)
|
e.href = new URL(e.href, common.BaseURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
let hashpart = location.hash.split("#")[1] || ""
|
let hashpart = location.hash.split("#")[1] || ""
|
||||||
|
|
|
@ -47,6 +47,18 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.location {
|
||||||
|
color: #acf;
|
||||||
|
background-color: #0008;
|
||||||
|
position: fixed;
|
||||||
|
right: 30vw;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight:bold;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
.qrcode {
|
.qrcode {
|
||||||
width: 30vw;
|
width: 30vw;
|
||||||
}
|
}
|
||||||
|
@ -60,23 +72,34 @@
|
||||||
max-width: 40%;
|
max-width: 40%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Scoreboard */
|
||||||
#rankings {
|
#rankings {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: rgba(0, 0, 0, 0.8);
|
background-color: #000c;
|
||||||
|
}
|
||||||
|
#rankings div {
|
||||||
|
height: 1.4rem;
|
||||||
|
}
|
||||||
|
#rankings div:nth-child(6n){
|
||||||
|
background-color: #ccc1;
|
||||||
|
}
|
||||||
|
#rankings div:nth-child(6n+3) {
|
||||||
|
background-color: #0f01;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rankings span {
|
#rankings span {
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 1.7em;
|
height: 1.4em;
|
||||||
}
|
}
|
||||||
#rankings span.teamname {
|
#rankings span.teamname {
|
||||||
|
height: auto;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
color: white;
|
color: white;
|
||||||
text-shadow: 0 0 3px black;
|
background-color: #000e;
|
||||||
opacity: 0.8;
|
border-radius: 3px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0.2em;
|
right: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,8 @@
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@0.2.1"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@0.2.1"></script>
|
||||||
<script type="module" src="scoreboard.mjs"></script>
|
<script type="module" src="scoreboard.mjs"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="wide">
|
<body>
|
||||||
<section class="rotate">
|
|
||||||
<div id="rankings"></div>
|
<div id="rankings"></div>
|
||||||
</section>
|
<div class="location"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -2,8 +2,8 @@ import * as moth from "./moth.mjs"
|
||||||
import * as common from "./common.mjs"
|
import * as common from "./common.mjs"
|
||||||
|
|
||||||
const server = new moth.Server(".")
|
const server = new moth.Server(".")
|
||||||
const ReplayDuration = 3 * common.Second
|
const ReplayDuration = 0.3 * common.Second
|
||||||
const MaxFrameRate = 24
|
const MaxFrameRate = 60
|
||||||
/** Don't let any team's score exceed this percentage width */
|
/** Don't let any team's score exceed this percentage width */
|
||||||
const MaxScoreWidth = 95
|
const MaxScoreWidth = 95
|
||||||
|
|
||||||
|
@ -23,6 +23,12 @@ function sleep(timeout) {
|
||||||
* The update is animated, because I think that looks cool.
|
* The update is animated, because I think that looks cool.
|
||||||
*/
|
*/
|
||||||
async function update() {
|
async function update() {
|
||||||
|
let config = await common.Config()
|
||||||
|
for (let e of document.querySelectorAll(".location")) {
|
||||||
|
e.textContent = common.BaseURL
|
||||||
|
e.classList.toggle("hidden", !config.URLInScoreboard)
|
||||||
|
}
|
||||||
|
|
||||||
let state = await server.GetState()
|
let state = await server.GetState()
|
||||||
let rankingsElement = document.querySelector("#rankings")
|
let rankingsElement = document.querySelector("#rankings")
|
||||||
let logSize = state.PointsLog.length
|
let logSize = state.PointsLog.length
|
||||||
|
|
Loading…
Reference in New Issue