aboutsummaryrefslogtreecommitdiff
path: root/examples/07-routing/src/app.gleam
diff options
context:
space:
mode:
Diffstat (limited to 'examples/07-routing/src/app.gleam')
-rw-r--r--examples/07-routing/src/app.gleam134
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)],
+ )
}