import gleam/int import gleam/javascript/promise.{type Promise} import lustre import lustre/attribute as attr import lustre/element.{type Element} import lustre/element/html import lustre/event import lustre/effect.{type Effect} pub fn main() { let app = lustre.application(init, update, view) let assert Ok(dispatch) = lustre.start(app, "#app", Nil) dispatch } type Model { Model(count: Int, greeting: String, name: String, time: Int) } fn init(_) -> #(Model, Effect(Msg)) { #(Model(0, "", "", 0), bind_clock()) } pub type Msg { Increment Decrement Greet GotGreeting(String) UpdateName(String) Tick(Int) } fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) { case msg { Increment -> #(Model(..model, count: model.count + 1), effect.none()) Decrement -> #(Model(..model, count: model.count - 1), effect.none()) Greet -> #(model, get_greeting(model.name)) GotGreeting(greeting) -> #( Model(..model, greeting: greeting), effect.none(), ) UpdateName(name) -> #(Model(..model, name: name), effect.none()) Tick(time) -> #(Model(..model, time: time), effect.none()) } } fn get_greeting(name: String) -> Effect(Msg) { effect.from(do_get_greeting(name, _)) } fn do_get_greeting(name: String, dispatch: fn(Msg) -> Nil) -> Nil { greet(name) // |> promise.await() |> promise.map(fn(response) { case response { Ok(greeting) -> GotGreeting(greeting) Error(err) -> GotGreeting("Error: " <> err) } }) |> promise.tap(dispatch) Nil } fn bind_clock() -> Effect(Msg) { effect.from(fn(dispatch) { listen_for_tick(fn(time) { tick(time) |> dispatch }) Nil }) } @external(javascript, "./ffi/commands.js", "greet") pub fn greet(name: String) -> Promise(Result(String, String)) type UnlistenFn = fn() -> Nil @external(javascript, "./ffi/commands.js", "listenForTick") pub fn listen_for_tick(handler: fn(Int) -> Nil) -> Promise(UnlistenFn) pub type Date @external(javascript, "./ffi/js_extra.js", "from_unix") pub fn new_date(timestamp: Int) -> Date @external(javascript, "./ffi/js_extra.js", "date_to_string") pub fn date_to_string(date: Date) -> String fn update_name(text: String) -> Msg { UpdateName(text) } fn tick(time: Int) -> Msg { Tick(time) } // -- VIEW fn view(model: Model) -> Element(Msg) { let count = int.to_string(model.count) let time = model.time |> new_date |> date_to_string html.div([], [ html.h1([], [element.text("Gleam + Vite + Tauri")]), html.div([attr.class("field text-center")], [ html.label([attr.for("greet_name")], [element.text("Name")]), element.text(" "), html.input([ attr.type_("text"), attr.name("greet_name"), event.on_input(update_name), ]), ]), html.p([attr.class("text-center")], [ element.text(model.greeting <> " " <> count <> " ✨"), ]), html.div([attr.class("text-center")], [ html.button([event.on_click(Decrement)], [element.text("-")]), html.button([event.on_click(Increment)], [element.text("+")]), html.button([event.on_click(Greet)], [element.text("Greet")]), ]), html.div([attr.class("clock text-center")], [ element.text("Clock: " <> time), ]), ]) }