aboutsummaryrefslogtreecommitdiff
path: root/examples/01-hello-world
diff options
context:
space:
mode:
Diffstat (limited to 'examples/01-hello-world')
-rw-r--r--examples/01-hello-world/README.md102
-rw-r--r--examples/01-hello-world/gleam.toml11
-rw-r--r--examples/01-hello-world/manifest.toml24
-rw-r--r--examples/01-hello-world/src/app.gleam27
4 files changed, 164 insertions, 0 deletions
diff --git a/examples/01-hello-world/README.md b/examples/01-hello-world/README.md
new file mode 100644
index 0000000..5302fe3
--- /dev/null
+++ b/examples/01-hello-world/README.md
@@ -0,0 +1,102 @@
+# 01 Hello World
+
+This hello world example is a tiny example of what you need to put together to
+get a Lustre application running. In later examples we'll touch on server-side
+rendering and Lustre Universal Components but for these first examples we'll
+be looking at rendering on the client _only_.
+
+## Configuring the Gleam project
+
+It's important to remember to add `target = "javascript"` to your `gleam.toml`!
+If you forget to do this you might end up confused when it looks like your project
+is successfully building but you have no JavaScript output!
+
+## Creating a `lustre.element` application
+
+The simplest kind of Lustre application is the `element`. This sets up a static
+application that does not have its own update loop and cannot dynamically render
+any content. Instead, we provide a static Lustre `Element` to render once.
+
+### HTML attributes and inline styles
+
+In Lustre, HTML attributes are modelled as a `List` of attributes. This is a bit
+different from many other frameworks that use an object or record for attributes.
+Lustre takes the list-of-attributes approach for a couple of reasons:
+
+- Gleam doesn't have a way to construct an anonymous record: we'd have to have
+ an infinite number of types to cover every possible varation!
+
+- Working with lists makes it convenient to merge different sets of attributes
+ together (like an element that defines some local attributes and merges them
+ with any passed in as an argument).
+
+In a similar fashion, inline styles are lists of property/value tuples. In this
+example we're setting inline styles for the `width` and `height` properties.
+
+### Why `element.text`?
+
+In frameworks like React, it's enough to just return a `String` if you want to
+render some text. Gleam's type system works a little differently though, a string
+literal isn't compatible with Lustre's `Element` type on its own, so we need to
+wrap any text to render in `element.text`.
+
+You won't see us do it in any of the examples we share, but it's common for folks
+to import `text` and any html elements they're using unqualified to cut down on
+some of the noise:
+
+```gleam
+import lustre/element.{text}
+import lustre/element/html.{div, p}
+...
+```
+
+## Starting a Lustre application
+
+Starting a Lustre application with `lustre.start` requires three things:
+
+- A configured `Application` (that's what we used `lustre.element` for).
+
+- A [CSS selector](https://developer.mozilla.org/en-US/docs/Web/API/Document_object_model/Locating_DOM_elements_using_selectors)
+ to locate the DOM node to mount the application on to. As in other frameworks,
+ it's common to use an element with the id "app": for that you'd write the
+ selector as `#app`.
+
+- Some initial data to pass to the application's `init` function. Because applications
+ constructed with `lustre.element` are not dynamic there's nothing meaningful
+ to pass in here, so we just use `Nil`.
+
+Starting an application could fail for a number of reasons, so this function
+returns a `Result`. The `Ok` value is a function you can use to send messages to
+your running application from the outside world: we'll see more of that in later
+examples!
+
+## Seeing the result
+
+Lustre ships with a very simple development server to help you look through these
+examples. You can run `gleam run -m lustre/try` in any of these examples to start
+this development server and head over to `localhost:1234` to see what it produces.
+
+If you're coming from a more mature Web development setup, you should know that
+this preview server is _not_ a replacement for a more robust development setup!
+While we work on building this into Lustre we recommend using [vite](https://vitejs.dev)
+with the [vite-gleam](https://www.npmjs.com/package/vite-gleam) plugin.
+
+### Enabling lustre_ui
+
+[Lustre_ui](https://hexdocs.pm/lustre_ui/) is a separate package published by us
+to provide a collection of robust styled elements for folks that want to get working
+with Lustre ASAP. Each of these examples have been written to use elements from
+that package.
+
+The lustre/try preview server can be configured to include the lustre_ui stylesheet
+by passing the `--include-styles` flag:
+
+```sh
+$ gleam run -m lustre/try -- --include-styles
+```
+
+Note that the first `--` is necessary so the Gleam binary knows this is a flag
+that should be passed to lustre/try!
+
+It's not necessary to use lustre_ui to use Lustre or to check out any of these
+examples, but the option is there if you want it.
diff --git a/examples/01-hello-world/gleam.toml b/examples/01-hello-world/gleam.toml
new file mode 100644
index 0000000..4368c0c
--- /dev/null
+++ b/examples/01-hello-world/gleam.toml
@@ -0,0 +1,11 @@
+name = "app"
+version = "1.0.0"
+target = "javascript"
+
+[dependencies]
+gleam_stdlib = "~> 0.34 or ~> 1.0"
+lustre = { path = "../../" }
+lustre_ui = "~> 0.3"
+
+[dev-dependencies]
+gleeunit = "~> 1.0"
diff --git a/examples/01-hello-world/manifest.toml b/examples/01-hello-world/manifest.toml
new file mode 100644
index 0000000..4033048
--- /dev/null
+++ b/examples/01-hello-world/manifest.toml
@@ -0,0 +1,24 @@
+# This file was generated by Gleam
+# You typically do not need to edit this file
+
+packages = [
+ { name = "argv", version = "1.0.1", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "A6E9009E50BBE863EB37D963E4315398D41A3D87D0075480FC244125808F964A" },
+ { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_community_colour"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" },
+ { name = "gleam_community_colour", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "A49A5E3AE8B637A5ACBA80ECB9B1AFE89FD3D5351FF6410A42B84F666D40D7D5" },
+ { name = "gleam_erlang", version = "0.24.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "26BDB52E61889F56A291CB34167315780EE4AA20961917314446542C90D1C1A0" },
+ { name = "gleam_json", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "CB405BD93A8828BCD870463DE29375E7B2D252D9D124C109E5B618AAC00B86FC" },
+ { name = "gleam_otp", version = "0.9.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "5FADBBEC5ECF3F8B6BE91101D432758503192AE2ADBAD5602158977341489F71" },
+ { name = "gleam_stdlib", version = "0.34.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016" },
+ { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" },
+ { name = "glint", version = "0.14.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib", "snag", "gleam_community_colour"], otp_app = "glint", source = "hex", outer_checksum = "21AB16D5A50D4EF34DF935915FDBEE06B2DAEDEE3FCC8584C6E635A866566B38" },
+ { name = "lustre", version = "3.1.3", build_tools = ["gleam"], requirements = ["argv", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "glint"], source = "local", path = "../.." },
+ { name = "lustre_ui", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "lustre", "gleam_stdlib"], otp_app = "lustre_ui", source = "hex", outer_checksum = "F81BE5D20153CFFC717C2C4687A19375A8613528908AF7069DDA1B929C8398B1" },
+ { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" },
+ { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
+]
+
+[requirements]
+gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
+gleeunit = { version = "~> 1.0" }
+lustre = { path = "../../" }
+lustre_ui = { version = "~> 0.3"}
diff --git a/examples/01-hello-world/src/app.gleam b/examples/01-hello-world/src/app.gleam
new file mode 100644
index 0000000..dc42ad7
--- /dev/null
+++ b/examples/01-hello-world/src/app.gleam
@@ -0,0 +1,27 @@
+import lustre
+import lustre/attribute
+import lustre/element
+import lustre/element/html
+// These examples are written with lustre_ui in mind. They'll work regardless,
+// but to see what lustre_ui can do make sure to run each of these examples with
+// the `--include-styles` flag:
+//
+// $ gleam run -m lustre/try -- --include-styles
+//
+// In your own apps, make sure to add the `lustre_ui` dependency and include the
+// stylesheet somewhere.
+import lustre/ui
+
+pub fn main() {
+ let styles = [#("width", "100vw"), #("height", "100vh")]
+ let app =
+ lustre.element(ui.centre(
+ [attribute.style(styles)],
+ html.div([], [
+ html.h1([], [element.text("Hello, world.")]),
+ html.h2([], [element.text("Welcome to Lustre.")]),
+ ]),
+ ))
+
+ let assert Ok(_) = lustre.start(app, "#app", Nil)
+}