Migrate player client to Alpine.js.
This commit is contained in:
parent
5b13eb5ece
commit
7357528bb5
4 changed files with 122 additions and 14 deletions
45
src/main/kotlin/de/pheerai/buzzer/alpine/attributes.kt
Normal file
45
src/main/kotlin/de/pheerai/buzzer/alpine/attributes.kt
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package de.pheerai.buzzer.alpine
|
||||||
|
|
||||||
|
import kotlinx.html.HTMLTag
|
||||||
|
|
||||||
|
fun HTMLTag.xData(data: String) {
|
||||||
|
attributes["x-data"] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
fun HTMLTag.xInit(init: String) {
|
||||||
|
attributes["x-init"] = init
|
||||||
|
}
|
||||||
|
|
||||||
|
fun HTMLTag.xOn(event: String, handler: String, debounce: Boolean = false, debounceMs: Int = 0) {
|
||||||
|
val debounceString = if (debounce && debounceMs > 0) {
|
||||||
|
".debounce.${debounceMs}ms"
|
||||||
|
} else if (debounce) {
|
||||||
|
".debounce"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
attributes["x-on:${event}$debounceString"] = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
fun HTMLTag.xModel(model: String, debounce: Boolean = false, debounceMs: Int = 0) {
|
||||||
|
val debounceString = if (debounce && debounceMs > 0) {
|
||||||
|
".debounce.${debounceMs}ms"
|
||||||
|
} else if (debounce) {
|
||||||
|
".debounce"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
attributes["x-model$debounceString"] = model
|
||||||
|
}
|
||||||
|
|
||||||
|
fun HTMLTag.xShow(data: String) {
|
||||||
|
attributes["x-show"] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
fun HTMLTag.xText(text: String) {
|
||||||
|
attributes["x-text"] = text
|
||||||
|
}
|
||||||
|
|
||||||
|
fun HTMLTag.xBind(type: String, data: String) {
|
||||||
|
attributes["x-bind:$type"] = data
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package de.pheerai.buzzer.clients
|
package de.pheerai.buzzer.clients
|
||||||
|
|
||||||
|
import de.pheerai.buzzer.alpine.*
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
|
|
||||||
fun HTML.createPlayerDocument() {
|
fun HTML.createPlayerDocument() {
|
||||||
|
@ -11,23 +12,55 @@ fun HTML.createPlayerDocument() {
|
||||||
rel = "stylesheet",
|
rel = "stylesheet",
|
||||||
type = "text/css"
|
type = "text/css"
|
||||||
)
|
)
|
||||||
script { src = "https://code.jquery.com/jquery-3.6.0.min.js" }
|
script {
|
||||||
script { src = "/assets/playerClient.js" }
|
src = "https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"
|
||||||
|
defer = true
|
||||||
|
}
|
||||||
|
script {
|
||||||
|
src = "/assets/playerClient.js"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
div(classes = "parent") {
|
div(classes = "parent") {
|
||||||
attributes["foo"] = "bar"
|
xInit("startWebSocket()")
|
||||||
|
xData("{playerName: \"\"}")
|
||||||
div(classes = "input") {
|
div(classes = "input") {
|
||||||
label { +"Player" }
|
label { +"Player" }
|
||||||
div(classes = "bumper") {}
|
div(classes = "bumper") {}
|
||||||
input {
|
input {
|
||||||
|
xModel("playerName", debounce = true)
|
||||||
|
type = InputType.text
|
||||||
id = "username"
|
id = "username"
|
||||||
placeholder = "<name>"
|
placeholder = "<name>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
div(classes = "submit disabled") {
|
||||||
|
xShow("!playerName")
|
||||||
|
+"Enter a name first!"
|
||||||
|
}
|
||||||
button(classes = "submit") {
|
button(classes = "submit") {
|
||||||
onClick = "sendUsername()"
|
xShow("playerName")
|
||||||
+"I know that!"
|
xData("{clicked: false}")
|
||||||
|
xOn(
|
||||||
|
"click",
|
||||||
|
"""
|
||||||
|
() => {
|
||||||
|
sendUsername(playerName);
|
||||||
|
clicked = true
|
||||||
|
setTimeout(() => {
|
||||||
|
clicked = false
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
""".trimMargin()
|
||||||
|
)
|
||||||
|
xOn("mousedown", "clicked = true")
|
||||||
|
xOn("touchstart", "clicked = true")
|
||||||
|
xBind("class", "{'active': clicked}")
|
||||||
|
+"I'm "
|
||||||
|
span {
|
||||||
|
xText("playerName")
|
||||||
|
}
|
||||||
|
+" and I know this!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,9 @@ div > .submit {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
white-space: pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
div > .button:hover {
|
div > button.active {
|
||||||
background-color: #5B1D4A;
|
background-color: #5B1D4A;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,46 @@
|
||||||
|
|
||||||
let webSocket;
|
let webSocket;
|
||||||
|
|
||||||
$.when($.ready).then(function () {
|
function startWebSocket() {
|
||||||
let protocolPrefix = (window.location.protocol === 'https:') ? 'wss:' : 'ws:';
|
let protocolPrefix = (window.location.protocol === 'https:') ? 'wss:' : 'ws:';
|
||||||
webSocket = new WebSocket(`${protocolPrefix}//${location.host}/socket/player`);
|
webSocket = new WebSocket(`${protocolPrefix}//${location.host}/socket/player`);
|
||||||
});
|
webSocket.onerror = (ev) => {
|
||||||
|
switch (ev.code) {
|
||||||
|
case 1000:
|
||||||
|
console.log("[WS]: Closed normally")
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log("[WS]: Closed abnormally")
|
||||||
|
reconnectWebSocket();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
webSocket.onclose = (ev) => {
|
||||||
|
switch (ev.code) {
|
||||||
|
case 'ECONNREFUSED':
|
||||||
|
reconnectWebSocket();
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
webSocket.onerror(ev);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function sendUsername() {
|
function reconnectWebSocket() {
|
||||||
const username = $('#username').val()
|
setTimeout(() => {
|
||||||
if (username !== null && username !== '') {
|
console.log("[WS]: Reconnecting...")
|
||||||
console.log(`Username: ${username}`)
|
startWebSocket()
|
||||||
webSocket.send(username)
|
}, 2000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendUsername(username) {
|
||||||
|
if (
|
||||||
|
username !== undefined
|
||||||
|
&& username !== null
|
||||||
|
&& username !== ''
|
||||||
|
) {
|
||||||
|
console.log(`Username: ${username}`);
|
||||||
|
webSocket.send(username);
|
||||||
} else {
|
} else {
|
||||||
alert("Please enter a name!")
|
alert("Please enter a name!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue