diff options
author | Eileen Noonan <enoonan@arcstone.com> | 2024-04-01 20:08:22 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-02 01:08:22 +0100 |
commit | bbefb97ba3d8f117b8cbef769180a4d8425cf145 (patch) | |
tree | 2f65118ad743754da00fab86c36833b017ebc537 /examples/07-routing/src/app.gleam | |
parent | 44d1ae11bd0f77dffff19017e7878669af2f95f9 (diff) | |
download | lustre-bbefb97ba3d8f117b8cbef769180a4d8425cf145.tar.gz lustre-bbefb97ba3d8f117b8cbef769180a4d8425cf145.zip |
✨ Create a routing example using modem. (#96)
Diffstat (limited to 'examples/07-routing/src/app.gleam')
-rw-r--r-- | examples/07-routing/src/app.gleam | 134 |
1 files changed, 125 insertions, 9 deletions
diff --git a/examples/07-routing/src/app.gleam b/examples/07-routing/src/app.gleam index a9d14d0..382bd60 100644 --- a/examples/07-routing/src/app.gleam +++ b/examples/07-routing/src/app.gleam @@ -1,4 +1,8 @@ import gleam/uri.{type Uri} +import gleam/list +import gleam/string +import gleam/result +import gleam/dynamic import lustre import lustre/attribute import lustre/effect.{type Effect} @@ -15,7 +19,6 @@ import modem // In your own apps, make sure to add the `lustre/ui` dependency and include the // stylesheet somewhere. import lustre/ui -import lustre/ui/aside // MAIN ------------------------------------------------------------------------ @@ -27,31 +30,144 @@ pub fn main() { // MODEL ----------------------------------------------------------------------- type Model { - Model + Model(current: Route, guests: List(Guest), new_guest_name: String) +} + +type Route { + Home + WelcomeGuest(value: String) +} + +type Guest { + Guest(slug: String, name: String) } fn init(_) -> #(Model, Effect(Msg)) { - #(Model, modem.init(on_route_change)) + #( + Model( + current: Home, + guests: [ + Guest(slug: "chihiro", name: "Chihiro"), + Guest(slug: "totoro", name: "Totoro"), + ], + new_guest_name: "", + ), + modem.init(on_route_change), + ) } fn on_route_change(uri: Uri) -> Msg { - let path = uri.path_segments(uri.path) - - RouterPushedPath(path) + case uri.path_segments(uri.path) { + ["welcome", guest] -> OnRouteChange(WelcomeGuest(guest)) + _ -> OnRouteChange(Home) + } } // UPDATE ---------------------------------------------------------------------- pub opaque type Msg { - RouterPushedPath(List(String)) + OnRouteChange(Route) + UserUpdatedNewGuestName(String) + UserAddedNewGuest(Guest) } fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) { - todo + case msg { + OnRouteChange(route) -> #(Model(..model, current: route), effect.none()) + UserUpdatedNewGuestName(name) -> #( + Model(..model, new_guest_name: name), + effect.none(), + ) + UserAddedNewGuest(guest) -> #( + Model( + ..model, + guests: list.append(model.guests, [guest]), + new_guest_name: "", + ), + effect.none(), + ) + } } // VIEW ------------------------------------------------------------------------ fn view(model: Model) -> Element(Msg) { - todo + let styles = [#("margin", "15vh")] + + let page = case model.current { + WelcomeGuest(name) -> render_welcome(model, name) + Home -> render_home(model) + } + + ui.stack([attribute.style(styles)], [render_nav(model), page]) +} + +fn render_nav(model: Model) -> Element(a) { + let item_styles = [#("margin", "15px"), #("text-decoration", "underline")] + + let nav_item = fn(path, text) { + html.a([attribute.href("/" <> path), attribute.style(item_styles)], [ + element.text(text), + ]) + } + + let guests = + model.guests + |> list.map(fn(guest: Guest) { + nav_item("welcome/" <> guest.slug, guest.name) + }) + + html.nav([], [nav_item("", "Home"), ..guests]) +} + +fn render_home(model: Model) { + let new_guest_input = fn(event) { + use code <- result.try(dynamic.field("key", dynamic.string)(event)) + case code { + "Enter" -> { + let guest_slug = + model.new_guest_name + |> string.replace(" ", "-") + |> string.lowercase + Ok( + UserAddedNewGuest(Guest(name: model.new_guest_name, slug: guest_slug)), + ) + } + _ -> { + use value <- result.try(event.value(event)) + Ok(UserUpdatedNewGuestName(value)) + } + } + } + ui.centre( + [attribute.style([#("margin-top", "10vh")])], + ui.stack([], [ + to_title("Welcome to the Party 🏡"), + html.label([], [element.text("Please sign the guest book:")]), + ui.input([ + event.on("keyup", new_guest_input), + attribute.value(model.new_guest_name), + ]), + ]), + ) +} + +fn render_welcome(model: Model, slug) -> Element(a) { + let guest = + model.guests + |> list.find(fn(guest: Guest) { guest.slug == slug }) + + let title = case guest { + Ok(guest) -> to_title("Hello, " <> guest.name <> "! 🎉") + _ -> to_title("Sorry ... didn't quite catch that.") + } + + ui.centre([attribute.style([#("margin-top", "10vh")])], title) +} + +fn to_title(text) { + html.h1( + [attribute.style([#("font-size", "36px"), #("font-weight", "bold")])], + [element.text(text)], + ) } |