quizterm/client/src/client.gleam

84 lines
1.9 KiB
Gleam
Raw Normal View History

import gleam/json
import gleam/list
import gleam/result
import lustre
import lustre/attribute
import lustre/effect.{type Effect}
import lustre/element.{type Element}
import lustre/element/html
import plinth/browser/document
import plinth/browser/element as plinth_element
import shared
pub fn main() {
let initial_items =
document.query_selector("#model")
|> result.map(plinth_element.inner_text)
|> result.try(fn(json) {
json.parse(json, shared.grocery_list_decoder())
|> result.replace_error(Nil)
})
|> result.unwrap([])
let app = lustre.application(init, update, view)
let assert Ok(_) = lustre.start(app, "#app", initial_items)
Nil
}
type Model {
Model(rooms: List(String), name: String)
}
fn init(items: List(String)) -> #(Model, Effect(Msg)) {
let model = Model(rooms: items, name: "")
#(model, effect.none())
}
type Msg {
UserTypedNewItem(String)
UserAddedItem
}
fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
case msg {
UserAddedItem -> {
case model.name {
"" -> #(model, effect.none())
name -> {
let updated_items = [name, ..model.rooms]
#(Model(rooms: updated_items, name: ""), effect.none())
}
}
}
UserTypedNewItem(text) -> #(Model(..model, name: text), effect.none())
}
}
fn view(model: Model) -> Element(Msg) {
let styles = [
#("max-width", "30ch"),
#("margin", "0 auto"),
#("display", "flex"),
#("flex-direction", "column"),
#("gap", "1em"),
]
html.div([attribute.styles(styles)], [
html.h1([], [html.text("Select your QuizRoom")]),
view_room_list(model.rooms),
])
}
fn view_room_list(items: List(String)) -> Element(Msg) {
case items {
[] -> html.p([], [html.text("No items in your list yet.")])
_ -> {
html.ul([], list.map(items, fn(item) { html.li([], [html.text(item)]) }))
}
}
}