143 lines
4 KiB
Gleam
143 lines
4 KiB
Gleam
|
|
import gleam/int
|
||
|
|
import gleam/list
|
||
|
|
import gleam/option.{None, Some}
|
||
|
|
import lustre/attribute.{class}
|
||
|
|
import lustre/element.{type Element}
|
||
|
|
import lustre/element/html
|
||
|
|
import lustre/event
|
||
|
|
import lustre/server_component
|
||
|
|
import model.{
|
||
|
|
type Model, type Msg, AwaitPlayers, Empty, EnterPin, JoinLive, JoinSingle,
|
||
|
|
KeyPin, PickPlayer, SelectGamestyle, SelectedPlayer, SelectedRoom,
|
||
|
|
}
|
||
|
|
import shared.{type Room}
|
||
|
|
|
||
|
|
pub fn view(model: Model) -> Element(Msg) {
|
||
|
|
case model.state {
|
||
|
|
Empty -> view_room_list(model.rooms)
|
||
|
|
EnterPin(_, _) -> view_enter_pin()
|
||
|
|
SelectGamestyle(_, _) -> view_live_or_single()
|
||
|
|
AwaitPlayers(_, _) -> html.text("FETCHING USERS FOR ROOM")
|
||
|
|
PickPlayer(_, _, players) -> view_player_list(players)
|
||
|
|
JoinLive(room:, pin:) -> view_join_live(room, pin)
|
||
|
|
JoinSingle(room:, pin:, player:) -> view_join_single(room, pin, player)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fn layout(header: String, ohno: option.Option(String), body: List(Element(Msg))) {
|
||
|
|
html.div([], [
|
||
|
|
html.div([class("terminal-header")], [
|
||
|
|
html.div([class("terminal-status")], [
|
||
|
|
html.span([class("status-blink")], [html.text("●")]),
|
||
|
|
html.div([], [
|
||
|
|
html.text(" SYSTEM READY"),
|
||
|
|
]),
|
||
|
|
html.div([], [
|
||
|
|
case ohno {
|
||
|
|
None -> element.none()
|
||
|
|
Some(x) -> html.h3([], [html.text("Fail: " <> x)])
|
||
|
|
},
|
||
|
|
]),
|
||
|
|
html.span([class("ml-8")], [
|
||
|
|
html.text("<< Please Log On to use QuizTerm. >>"),
|
||
|
|
]),
|
||
|
|
]),
|
||
|
|
]),
|
||
|
|
html.div([attribute.class("terminal-section")], [
|
||
|
|
html.div([attribute.class("terminal-label mb-4")], [
|
||
|
|
html.text(header),
|
||
|
|
]),
|
||
|
|
html.div([attribute.class("participants-grid")], body),
|
||
|
|
]),
|
||
|
|
])
|
||
|
|
}
|
||
|
|
|
||
|
|
fn view_room_list(items: List(Room)) -> Element(Msg) {
|
||
|
|
layout("Select room to play in", None, case items {
|
||
|
|
[] -> [html.text("No items in your list yet.")]
|
||
|
|
_ -> {
|
||
|
|
list.index_map(items, fn(item, index) {
|
||
|
|
room_cell(index, item, SelectedRoom)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
fn view_enter_pin() -> Element(Msg) {
|
||
|
|
layout("Enter PIN code for room", None, [
|
||
|
|
html.input([
|
||
|
|
attribute.type_("password"),
|
||
|
|
event.on_input(KeyPin),
|
||
|
|
attribute.autofocus(True),
|
||
|
|
]),
|
||
|
|
])
|
||
|
|
}
|
||
|
|
|
||
|
|
fn view_join_live(room: String, pin: String) -> Element(Msg) {
|
||
|
|
html.div([attribute.class("terminal-section")], [
|
||
|
|
html.div([attribute.class("terminal-label mb-4")], [
|
||
|
|
server_component.element(
|
||
|
|
[server_component.route("/socket/live/" <> room)],
|
||
|
|
[],
|
||
|
|
),
|
||
|
|
server_component.element(
|
||
|
|
[server_component.route("/socket/control/" <> room)],
|
||
|
|
[],
|
||
|
|
),
|
||
|
|
]),
|
||
|
|
])
|
||
|
|
}
|
||
|
|
|
||
|
|
fn view_join_single(room: String, pin: String, player: String) -> Element(Msg) {
|
||
|
|
html.div([attribute.class("terminal-section")], [
|
||
|
|
html.div([attribute.class("terminal-label mb-4")], [
|
||
|
|
server_component.element(
|
||
|
|
[server_component.route("/socket/single/" <> room)],
|
||
|
|
[],
|
||
|
|
),
|
||
|
|
]),
|
||
|
|
])
|
||
|
|
}
|
||
|
|
|
||
|
|
fn view_live_or_single() -> Element(Msg) {
|
||
|
|
layout("Select type of play", None, [
|
||
|
|
click_cell(1, "Live Game", model.SelectedGamestyle),
|
||
|
|
click_cell(2, "Single Game", model.SelectedGamestyle),
|
||
|
|
])
|
||
|
|
}
|
||
|
|
|
||
|
|
fn view_player_list(items: List(String)) -> Element(Msg) {
|
||
|
|
layout("Select or enter your player", None, case items {
|
||
|
|
[] -> [html.text("No items in your list yet.")]
|
||
|
|
_ -> {
|
||
|
|
list.index_map(items, fn(item, index) {
|
||
|
|
click_cell(index, item, SelectedPlayer)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
fn click_cell(
|
||
|
|
number: Int,
|
||
|
|
player: String,
|
||
|
|
on_click: fn(String) -> msg,
|
||
|
|
) -> Element(msg) {
|
||
|
|
html.div([class("participant-login"), event.on_click(on_click(player))], [
|
||
|
|
html.div([class("participant-name")], [
|
||
|
|
html.text("► " <> "[#" <> int.to_string(number) <> "] " <> player),
|
||
|
|
]),
|
||
|
|
])
|
||
|
|
}
|
||
|
|
|
||
|
|
fn room_cell(
|
||
|
|
number: Int,
|
||
|
|
room: Room,
|
||
|
|
on_click: fn(String) -> msg,
|
||
|
|
) -> Element(msg) {
|
||
|
|
html.div([class("participant-login"), event.on_click(on_click(room.id))], [
|
||
|
|
html.div([class("participant-name")], [
|
||
|
|
html.text("► " <> "[#" <> int.to_string(number) <> "] Team " <> room.name),
|
||
|
|
]),
|
||
|
|
])
|
||
|
|
}
|