Merge pull request 'playerFeedback' (#1) from playerFeedback into master
Reviewed-on: https://git.pheerai.de/pheerai/webbuzzer/pulls/1
This commit is contained in:
commit
45e07d9393
7 changed files with 150 additions and 13 deletions
|
@ -43,3 +43,7 @@ fun HTMLTag.xText(text: String) {
|
|||
fun HTMLTag.xBind(type: String, data: String) {
|
||||
attributes["x-bind:$type"] = data
|
||||
}
|
||||
|
||||
fun HTMLTag.xEffect(effect: String) {
|
||||
attributes["x-effect"] = effect
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@ fun HTML.createGameMasterDocument() {
|
|||
rel = "stylesheet",
|
||||
type = "text/css"
|
||||
)
|
||||
link(
|
||||
href = "/assets/gamemaster.css",
|
||||
rel = "stylesheet",
|
||||
type = "text/css"
|
||||
)
|
||||
script {
|
||||
src = "https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"
|
||||
defer = true
|
||||
|
@ -19,28 +24,61 @@ fun HTML.createGameMasterDocument() {
|
|||
script { src = "/assets/buzzerWebSocket.js" }
|
||||
}
|
||||
body {
|
||||
xData("{receivedNames: [], buzzerWebSocket: null}")
|
||||
xData("{receivedNames: [], buzzerWebSocket: null, firstPlayer: null }")
|
||||
xInit(
|
||||
//language=JavaScript
|
||||
"""
|
||||
() => {
|
||||
startWebSocket('/socket/master', (ev) => {
|
||||
if (receivedNames.length === 0) {
|
||||
firstPlayer = ev.data
|
||||
}
|
||||
receivedNames.push(ev.data)
|
||||
});
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
div(classes = "parent") {
|
||||
button {
|
||||
xOn("click", "receivedNames = []")
|
||||
+"Reset"
|
||||
xEffect(
|
||||
//language=JavaScript
|
||||
"""
|
||||
if (firstPlayer !== null) {
|
||||
Alpine.data.buzzerWebSocket.send(`PLAYER:${"$"}{firstPlayer}`);
|
||||
} else {
|
||||
Alpine.data.buzzerWebSocket.send("CLEAR:");
|
||||
}
|
||||
ol {
|
||||
""".trimIndent()
|
||||
)
|
||||
div(classes = "parent") {
|
||||
div(classes = "player") {
|
||||
xShow("firstPlayer")
|
||||
xText("firstPlayer")
|
||||
}
|
||||
div { xShow("!firstPlayer") }
|
||||
div(classes = "playerlist") list@{
|
||||
template {
|
||||
attributes["x-for"] = "name in receivedNames"
|
||||
this@ol.li { xText("name") }
|
||||
this@list.div(classes = "listedname") { xText("name") }
|
||||
}
|
||||
}
|
||||
button(classes = "submit") {
|
||||
xData("{clicked: false}")
|
||||
xOn(
|
||||
"click",
|
||||
//language=JavaScript
|
||||
"""
|
||||
() => {
|
||||
receivedNames = []
|
||||
firstPlayer = null
|
||||
clicked = true
|
||||
setTimeout(() => {clicked = false}, 50)
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
xOn("mousedown", "clicked = true")
|
||||
xOn("touchstart", "clicked = true")
|
||||
xBind("class", "{'active': clicked}")
|
||||
+"Reset"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,13 +29,23 @@ fun HTML.createPlayerDocument() {
|
|||
}
|
||||
}
|
||||
body {
|
||||
xData("{playerName: \"\", buzzerWebSocket: null}")
|
||||
xData("{playerName: \"\", buzzerWebSocket: null, firstPlayer: null}")
|
||||
div(classes = "parent") {
|
||||
xEffect("console.log(firstPlayer)")
|
||||
xInit(
|
||||
//language=JavaScript
|
||||
"""
|
||||
() => {
|
||||
startWebSocket('/socket/player')
|
||||
startWebSocket('/socket/player', (ev) => {
|
||||
console.log("received: " + ev.data)
|
||||
if (ev.data === "CLEAR:") {
|
||||
firstPlayer = null;
|
||||
} else {
|
||||
let newName = ev.data.split(":")[1]
|
||||
console.log(newName)
|
||||
setTimeout(() => { firstPlayer = newName }, 500)
|
||||
}
|
||||
});
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
@ -54,7 +64,7 @@ fun HTML.createPlayerDocument() {
|
|||
+"Enter a name first!"
|
||||
}
|
||||
button(classes = "submit") {
|
||||
xShow("playerName")
|
||||
xShow("playerName && !firstPlayer")
|
||||
xData("{clicked: false}")
|
||||
xOn(
|
||||
"click",
|
||||
|
@ -78,6 +88,11 @@ fun HTML.createPlayerDocument() {
|
|||
}
|
||||
p { +"and I know this!" }
|
||||
}
|
||||
div(classes = "lockindicator") {
|
||||
xShow("firstPlayer")
|
||||
xBind("class", "{'self': firstPlayer === playerName, 'other': firstPlayer !== playerName }")
|
||||
xText("firstPlayer")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@ import de.pheerai.buzzer.data.GameMasterSocket
|
|||
import de.pheerai.buzzer.data.SessionStorage
|
||||
import io.ktor.http.cio.websocket.*
|
||||
import kotlinx.coroutines.isActive
|
||||
import org.slf4j.Logger
|
||||
|
||||
suspend fun WebSocketSession.handleGameMasterSocket() {
|
||||
suspend fun WebSocketSession.handleGameMasterSocket(log: Logger) {
|
||||
SessionStorage.gameMasterSessions.add(GameMasterSocket(this))
|
||||
for (frame in incoming) {
|
||||
when (frame) {
|
||||
is Frame.Text -> {
|
||||
val text = frame.readText()
|
||||
log.info("GM Socket received $text")
|
||||
SessionStorage.playerSessions.filter { it.session.isActive }
|
||||
.forEach { it.session.send(text) }
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ fun Application.configureRoutes() {
|
|||
|
||||
private fun Routing.websocketRoutes(log: Logger) {
|
||||
webSocket("/socket/player") { handlePlayerSocket(log) }
|
||||
webSocket("/socket/master") { handleGameMasterSocket() }
|
||||
webSocket("/socket/master") { handleGameMasterSocket(log) }
|
||||
}
|
||||
|
||||
private fun Routing.clientRoutes() {
|
||||
|
|
58
src/main/resources/css/gamemaster.css
Normal file
58
src/main/resources/css/gamemaster.css
Normal file
|
@ -0,0 +1,58 @@
|
|||
body, html {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
font-size: var(--font-size);
|
||||
box-sizing: border-box;
|
||||
padding: var(--bumper-small-size);
|
||||
margin: 0;
|
||||
background-color: var(--background);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
div.parent {
|
||||
display: grid;
|
||||
grid-template-rows: 3fr auto 1fr;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.player {
|
||||
background-color: var(--foreground02);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.playerlist {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.listedname + .listedname::before {
|
||||
content: "»";
|
||||
padding-left: var(--bumper-small-size);
|
||||
padding-right: var(--bumper-small-size);
|
||||
}
|
||||
|
||||
.submit {
|
||||
border-radius: var(--border-radius);
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
font-size: var(--font-size);
|
||||
height: 100%;
|
||||
border: solid 0.25vh var(--highlight-dark);
|
||||
background-color: var(--foreground);
|
||||
color: var(--text);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.submit.active {
|
||||
background-color: var(--highlight01);
|
||||
}
|
||||
|
|
@ -59,6 +59,26 @@ div > .submit {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
div > button.active {
|
||||
div > .submit.active {
|
||||
background-color: var(--highlight01);
|
||||
}
|
||||
|
||||
.lockindicator {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
border: solid 0.25vh var(--highlight-dark);
|
||||
border-radius: var(--border-radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.lockindicator.self {
|
||||
background-color: darkgreen;
|
||||
}
|
||||
|
||||
.lockindicator.other {
|
||||
background-color: darkred;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue