aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-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
-rw-r--r--examples/02-interactivity/README.md111
-rw-r--r--examples/02-interactivity/gleam.toml11
-rw-r--r--examples/02-interactivity/manifest.toml24
-rw-r--r--examples/02-interactivity/src/app.gleam66
-rw-r--r--examples/03-controlled-inputs/README.md1
-rw-r--r--examples/03-controlled-inputs/gleam.toml11
-rw-r--r--examples/03-controlled-inputs/manifest.toml24
-rw-r--r--examples/03-controlled-inputs/src/app.gleam74
-rw-r--r--examples/04-http-requests/README.md1
-rw-r--r--examples/04-http-requests/gleam.toml12
-rw-r--r--examples/04-http-requests/manifest.toml26
-rw-r--r--examples/04-http-requests/src/app.gleam91
-rw-r--r--examples/README.md26
-rw-r--r--examples/components/gleam.toml7
-rw-r--r--examples/components/manifest.toml15
-rw-r--r--examples/components/src/components.gleam91
-rw-r--r--examples/counter/gleam.toml7
-rw-r--r--examples/counter/manifest.toml15
-rw-r--r--examples/counter/src/counter.gleam53
-rw-r--r--examples/events/gleam.toml7
-rw-r--r--examples/events/manifest.toml15
-rw-r--r--examples/events/src/events.gleam70
-rw-r--r--examples/input/gleam.toml7
-rw-r--r--examples/input/manifest.toml15
-rw-r--r--examples/input/src/input.gleam120
-rw-r--r--examples/nested/gleam.toml7
-rw-r--r--examples/nested/manifest.toml15
-rw-r--r--examples/nested/src/nested.gleam57
-rw-r--r--examples/nested/src/nested/counter.gleam53
-rw-r--r--examples/server_demo/README.md22
-rw-r--r--examples/server_demo/gleam.toml13
-rw-r--r--examples/server_demo/manifest.toml32
-rw-r--r--examples/server_demo/src/demo.gleam22
-rw-r--r--examples/server_demo/src/demo/app.gleam88
-rw-r--r--examples/server_demo/src/demo/socket.gleam78
-rw-r--r--examples/server_demo/src/demo/web.gleam58
-rw-r--r--examples/svg/gleam.toml7
-rw-r--r--examples/svg/manifest.toml15
-rw-r--r--examples/svg/src/svg.gleam103
43 files changed, 616 insertions, 1018 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)
+}
diff --git a/examples/02-interactivity/README.md b/examples/02-interactivity/README.md
new file mode 100644
index 0000000..d97f618
--- /dev/null
+++ b/examples/02-interactivity/README.md
@@ -0,0 +1,111 @@
+# 02 Interactivity
+
+In this example we show the basic structure of all Lustre applications with a
+classic counter example.
+
+## The Model-View-Update architecture
+
+All Lustre applications are built around the Model-View-Update (MVU) architecture.
+This is a pattern that's been popularised by the Elm programming language and
+has since been adopted by many other frameworks and languages.
+
+MVU applications are built around three main concepts:
+
+- A `Model` and a function to initialise it.
+- A `Msg` type and a function to update the model based on messages.
+- A `View` function to render the model as a Lustre `Element`.
+
+These three pieces come together to form a self-contained update loop. You produce
+an initial model, render it as HTML, and convert any user interactions into
+messages to handle in the update function.
+
+ ```text
+ +--------+
+ | |
+ | update |
+ | |
+ +--------+
+ ^ |
+ | |
+ Msg | | Model
+ | |
+ | v
++------+ +------------------------+
+| | Model | |
+| init |------------------------>| Lustre Runtime |
+| | | |
++------+ +------------------------+
+ ^ |
+ | |
+ Msg | | Model
+ | |
+ | v
+ +--------+
+ | |
+ | view |
+ | |
+ +--------+
+```
+
+### Model
+
+The model represents the entire state of your application. For most Lustre
+applications this will be a record, but for this example we're aliasing `Int` to
+our `Model` type to keep things simple.
+
+We also need to write an `init` function that returns the initial state of our
+application. It takes one argument, known as "flags" which is provided when the
+application is first started.
+
+```gleam
+fn init(initial_count: Int) -> Model {
+ case initial_count < 0 {
+ True -> 0
+ False -> initial_count
+ }
+}
+```
+
+Our `init` function takes a starting count, but ensures it cannot be below `0`.
+
+### Update
+
+In many other frameworks, it's common to update state directly in an event handler.
+MVU applications take a different approach: instead of state updates being scattered
+around your codebase, they are handled in a single `update` function.
+
+To achieve this, we define a `Msg` type that represents all the different kinds of
+messages our application can receive. If you're familiar with Erlang this approach
+to state management will be familiar to you. If you're coming from a JavaScript
+background, this approach is most-similar to state management solutions like Redux
+or Vuex.
+
+```gleam
+pub opaque type Msg {
+ Incr
+ Decr
+}
+```
+
+This approach means it is easy to quickly get an idea of all the ways your app
+can change state, and makes it easy to add new state changes over time. By pattern
+matching on an incoming message in our `update` function, we can lean on Gleam's
+_exhaustiveness checking_ to ensure we handle all possible messages.
+
+### View
+
+
+
+```gleam
+fn view(model: Model) -> Element(Msg) {
+ ...
+}
+```
+
+
+## Creating a dynamic Lustre application
+
+In the previous example we used the `lustre.element` function to construct a
+static Lustre app. To construct a simple interactive app we can use `lustre.simple`
+instead. From now on we'll see that all the different ways to construct a Lustre
+application all take the same three `init`, `update`, and `view` functions.
diff --git a/examples/02-interactivity/gleam.toml b/examples/02-interactivity/gleam.toml
new file mode 100644
index 0000000..4368c0c
--- /dev/null
+++ b/examples/02-interactivity/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/02-interactivity/manifest.toml b/examples/02-interactivity/manifest.toml
new file mode 100644
index 0000000..4033048
--- /dev/null
+++ b/examples/02-interactivity/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/02-interactivity/src/app.gleam b/examples/02-interactivity/src/app.gleam
new file mode 100644
index 0000000..e47b7a4
--- /dev/null
+++ b/examples/02-interactivity/src/app.gleam
@@ -0,0 +1,66 @@
+import gleam/int
+import lustre
+import lustre/attribute
+import lustre/element.{type Element}
+import lustre/element/html
+import lustre/event
+// 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
+
+// MAIN ------------------------------------------------------------------------
+
+pub fn main() {
+ let app = lustre.simple(init, update, view)
+ let assert Ok(_) = lustre.start(app, "#app", 0)
+}
+
+// MODEL -----------------------------------------------------------------------
+
+type Model =
+ Int
+
+fn init(initial_count: Int) -> Model {
+ case initial_count < 0 {
+ True -> 0
+ False -> initial_count
+ }
+}
+
+// UPDATE ----------------------------------------------------------------------
+
+pub opaque type Msg {
+ Incr
+ Decr
+}
+
+fn update(model: Model, msg: Msg) -> Model {
+ case msg {
+ Incr -> model + 1
+ Decr -> model - 1
+ }
+}
+
+// VIEW ------------------------------------------------------------------------
+
+fn view(model: Model) -> Element(Msg) {
+ let count = int.to_string(model)
+ let styles = [#("width", "100vw"), #("height", "100vh")]
+
+ ui.centre(
+ [attribute.style(styles)],
+ ui.stack([], [
+ ui.button([event.on_click(Incr)], [element.text("+")]),
+ html.p([attribute.style([#("text-align", "center")])], [
+ element.text(count),
+ ]),
+ ui.button([event.on_click(Decr)], [element.text("-")]),
+ ]),
+ )
+}
diff --git a/examples/03-controlled-inputs/README.md b/examples/03-controlled-inputs/README.md
new file mode 100644
index 0000000..5326f25
--- /dev/null
+++ b/examples/03-controlled-inputs/README.md
@@ -0,0 +1 @@
+# 03 Controlled Inputs
diff --git a/examples/03-controlled-inputs/gleam.toml b/examples/03-controlled-inputs/gleam.toml
new file mode 100644
index 0000000..4368c0c
--- /dev/null
+++ b/examples/03-controlled-inputs/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/03-controlled-inputs/manifest.toml b/examples/03-controlled-inputs/manifest.toml
new file mode 100644
index 0000000..4033048
--- /dev/null
+++ b/examples/03-controlled-inputs/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/03-controlled-inputs/src/app.gleam b/examples/03-controlled-inputs/src/app.gleam
new file mode 100644
index 0000000..8e713ea
--- /dev/null
+++ b/examples/03-controlled-inputs/src/app.gleam
@@ -0,0 +1,74 @@
+import gleam/int
+import gleam/string
+import lustre
+import lustre/attribute
+import lustre/element.{type Element}
+import lustre/event
+// 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
+import lustre/ui/aside
+
+// MAIN ------------------------------------------------------------------------
+
+pub fn main() {
+ let app = lustre.simple(init, update, view)
+ let assert Ok(_) = lustre.start(app, "#app", Nil)
+}
+
+// MODEL -----------------------------------------------------------------------
+
+type Model {
+ Model(value: String, length: Int, max: Int)
+}
+
+fn init(_) -> Model {
+ Model(value: "", length: 0, max: 10)
+}
+
+// UPDATE ----------------------------------------------------------------------
+
+pub opaque type Msg {
+ GotInput(value: String)
+ Reset
+}
+
+fn update(model: Model, msg: Msg) -> Model {
+ case msg {
+ GotInput(value) -> {
+ let length = string.length(value)
+ case length <= model.max {
+ True -> Model(..model, value: value, length: length)
+ False -> model
+ }
+ }
+ Reset -> Model(..model, value: "", length: 0)
+ }
+}
+
+// VIEW ------------------------------------------------------------------------
+
+fn view(model: Model) -> Element(Msg) {
+ let styles = [#("width", "100vw"), #("height", "100vh")]
+ let length = int.to_string(model.length)
+
+ ui.centre(
+ [attribute.style(styles)],
+ ui.aside(
+ [aside.content_first(), aside.align_centre()],
+ ui.field(
+ [],
+ [element.text("Write a message:")],
+ ui.input([attribute.value(model.value), event.on_input(GotInput)]),
+ [element.text(length <> "/10")],
+ ),
+ ui.button([event.on_click(Reset)], [element.text("Reset")]),
+ ),
+ )
+}
diff --git a/examples/04-http-requests/README.md b/examples/04-http-requests/README.md
new file mode 100644
index 0000000..d6d82bd
--- /dev/null
+++ b/examples/04-http-requests/README.md
@@ -0,0 +1 @@
+# 04 HTTP Requests
diff --git a/examples/04-http-requests/gleam.toml b/examples/04-http-requests/gleam.toml
new file mode 100644
index 0000000..b84e394
--- /dev/null
+++ b/examples/04-http-requests/gleam.toml
@@ -0,0 +1,12 @@
+name = "app"
+version = "1.0.0"
+target = "javascript"
+
+[dependencies]
+gleam_stdlib = "~> 0.34 or ~> 1.0"
+lustre = { path = "../../" }
+lustre_ui = "~> 0.3"
+lustre_http = "~> 0.4"
+
+[dev-dependencies]
+gleeunit = "~> 1.0"
diff --git a/examples/04-http-requests/manifest.toml b/examples/04-http-requests/manifest.toml
new file mode 100644
index 0000000..fc33b28
--- /dev/null
+++ b/examples/04-http-requests/manifest.toml
@@ -0,0 +1,26 @@
+# 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_community_colour", "gleam_stdlib"], 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 = ["thoas", "gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "CB405BD93A8828BCD870463DE29375E7B2D252D9D124C109E5B618AAC00B86FC" },
+ { name = "gleam_otp", version = "0.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_erlang"], 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_stdlib", "gleam_community_colour", "gleam_community_ansi", "snag"], 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_http", version = "0.4.1", build_tools = ["gleam"], requirements = ["gleam_json", "lustre", "gleam_stdlib"], otp_app = "lustre_http", source = "hex", outer_checksum = "F2E575CA598D426DECD9F617500B4EDAF11BEEF4233B8D31D2D568219E5ACCED" },
+ { name = "lustre_ui", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_community_colour", "lustre"], 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_http = { version = "~> 0.4"}
+lustre_ui = { version = "~> 0.3" }
diff --git a/examples/04-http-requests/src/app.gleam b/examples/04-http-requests/src/app.gleam
new file mode 100644
index 0000000..ac75d42
--- /dev/null
+++ b/examples/04-http-requests/src/app.gleam
@@ -0,0 +1,91 @@
+import gleam/dynamic
+import gleam/option.{type Option, None, Some}
+import lustre
+import lustre/attribute
+import lustre/effect.{type Effect}
+import lustre/element.{type Element}
+import lustre/element/html
+import lustre/event
+// Lustre_http is a community package that provides a simple API for making
+// HTTP requests from your update function. You can find the docs for the package
+// here:
+//
+// https://hexdocs.pm/lustre_http/index.html
+import lustre_http.{type HttpOrJsonError}
+// 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
+import lustre/ui/aside
+
+// MAIN ------------------------------------------------------------------------
+
+pub fn main() {
+ let app = lustre.application(init, update, view)
+ let assert Ok(_) = lustre.start(app, "#app", Nil)
+}
+
+// MODEL -----------------------------------------------------------------------
+
+type Model {
+ Model(quote: Option(String))
+}
+
+fn init(_) -> #(Model, Effect(Msg)) {
+ #(Model(quote: None), effect.none())
+}
+
+// UPDATE ----------------------------------------------------------------------
+
+pub opaque type Msg {
+ Refresh
+ GotQuote(Result(String, HttpOrJsonError))
+}
+
+fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
+ case msg {
+ Refresh -> #(model, get_quote())
+ GotQuote(Ok(quote)) -> #(Model(quote: Some(quote)), effect.none())
+ GotQuote(Error(_)) -> #(model, effect.none())
+ }
+}
+
+fn get_quote() -> Effect(Msg) {
+ let url = "https://api.quotable.io/random"
+ let decoder = dynamic.field("content", dynamic.string)
+
+ lustre_http.get_as_json(url, GotQuote, decoder)
+}
+
+// VIEW ------------------------------------------------------------------------
+
+fn view(model: Model) -> Element(Msg) {
+ let styles = [#("width", "100vw"), #("height", "100vh")]
+
+ ui.centre(
+ [attribute.style(styles)],
+ ui.aside(
+ [aside.min_width(70), attribute.style([#("width", "60ch")])],
+ view_quote(model.quote),
+ ui.button([event.on_click(Refresh)], [element.text("New quote")]),
+ ),
+ )
+}
+
+fn view_quote(quote: Option(String)) -> Element(msg) {
+ case quote {
+ Some(quote) ->
+ ui.stack([], [
+ element.text("Someone once said..."),
+ html.p([attribute.style([#("font-style", "italic")])], [
+ element.text(quote),
+ ]),
+ ])
+ None -> html.p([], [element.text("Click the button to get a quote!")])
+ }
+}
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index 2c601ea..0000000
--- a/examples/README.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Lustre examples
-
-Each of these examples is a complete Gleam project that contains a Lustre app
-that demos or tests a particular feature of Lustre. To run any of them, navigate
-to the example's directory and first run:
-
-```sh
-$ gleam build
-```
-
-Then serve the app using `lustre/try`:
-
-```sh
-$ gleam run -m lustre/try
-```
-
-If you do not specify a target, this will attempt to serve the app using an Erlang
-HTTP server. If you'd prefer to serve using Node, you can specify the JavaScript
-target instead:
-
-```sh
-$ gleam run -m lustre/try --target javascript
-```
-
-Or you may additionally supply the `--runtime deno` flag to serve using Deno rather
-than Node.
diff --git a/examples/components/gleam.toml b/examples/components/gleam.toml
deleted file mode 100644
index 3cac691..0000000
--- a/examples/components/gleam.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-name = "components"
-version = "1.0.0"
-target = "javascript"
-
-[dependencies]
-gleam_stdlib = "~> 0.34"
-lustre = { path = "../../" }
diff --git a/examples/components/manifest.toml b/examples/components/manifest.toml
deleted file mode 100644
index 1c72364..0000000
--- a/examples/components/manifest.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file was generated by Gleam
-# You typically do not need to edit this file
-
-packages = [
- { 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 = ["thoas", "gleam_stdlib"], 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 = "lustre", version = "3.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], source = "local", path = "../.." },
- { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
-]
-
-[requirements]
-gleam_stdlib = { version = "~> 0.34" }
-lustre = { path = "../../" }
diff --git a/examples/components/src/components.gleam b/examples/components/src/components.gleam
deleted file mode 100644
index 03400bf..0000000
--- a/examples/components/src/components.gleam
+++ /dev/null
@@ -1,91 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import gleam/dynamic
-import gleam/function
-import gleam/int
-import gleam/list
-import gleam/dict
-import gleam/result
-import lustre
-import lustre/attribute
-import lustre/effect
-import lustre/element.{element, text}
-import lustre/element/html.{button, div, li, ol, p, slot}
-import lustre/event
-
-// MAIN ------------------------------------------------------------------------
-
-pub fn main() {
- let counter =
- lustre.component(
- counter_init,
- counter_update,
- counter_view,
- dict.from_list([
- #("count", fn(attr) {
- dynamic.int(attr)
- |> result.map(GotCount)
- }),
- ]),
- )
-
- let assert Ok(_) = lustre.register(counter, "custom-counter")
- // A `simple` lustre application doesn't produce `Effect`s. These are best to
- // start with if you're just getting started with lustre or you know you don't
- // need the runtime to manage any side effects.
- let app = lustre.simple(init, update, view)
- let assert Ok(_) = lustre.start(app, "[data-lustre-app]", Nil)
-
- Nil
-}
-
-fn init(_) {
- []
-}
-
-fn update(history, msg) {
- case msg {
- "reset" -> []
- _ -> [msg, ..history]
- }
-}
-
-fn view(history) {
- let on_custom_click = event.on("custom-click", function.constant(Ok("click")))
-
- div([], [
- button([event.on_click("reset")], [text("Reset")]),
- ol([], list.map(history, fn(msg) { li([], [text(msg)]) })),
- element(
- "custom-counter",
- [on_custom_click, attribute.property("count", list.length(history))],
- [ol([], list.map(history, fn(msg) { li([], [text(msg)]) }))],
- ),
- ])
-}
-
-// COUNTER ---------------------------------------------------------------------
-
-fn counter_init() {
- #(0, effect.none())
-}
-
-type CounterMsg {
- GotCount(Int)
- Clicked
-}
-
-fn counter_update(count, msg) {
- case msg {
- GotCount(count) -> #(count, effect.none())
- Clicked -> #(count, event.emit("custom-click", Nil))
- }
-}
-
-fn counter_view(count) {
- div([], [
- button([event.on_click(Clicked)], [text("Click me!")]),
- p([], [text("Count: "), text(int.to_string(count))]),
- slot([]),
- ])
-}
diff --git a/examples/counter/gleam.toml b/examples/counter/gleam.toml
deleted file mode 100644
index e6bddb8..0000000
--- a/examples/counter/gleam.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-name = "counter"
-version = "1.0.0"
-target = "javascript"
-
-[dependencies]
-gleam_stdlib = "~> 0.34"
-lustre = { path = "../../" }
diff --git a/examples/counter/manifest.toml b/examples/counter/manifest.toml
deleted file mode 100644
index 1c72364..0000000
--- a/examples/counter/manifest.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file was generated by Gleam
-# You typically do not need to edit this file
-
-packages = [
- { 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 = ["thoas", "gleam_stdlib"], 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 = "lustre", version = "3.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], source = "local", path = "../.." },
- { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
-]
-
-[requirements]
-gleam_stdlib = { version = "~> 0.34" }
-lustre = { path = "../../" }
diff --git a/examples/counter/src/counter.gleam b/examples/counter/src/counter.gleam
deleted file mode 100644
index 37af39a..0000000
--- a/examples/counter/src/counter.gleam
+++ /dev/null
@@ -1,53 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import gleam/int
-import lustre
-import lustre/element.{type Element, text}
-import lustre/element/html.{button, div, p}
-import lustre/event
-
-// MAIN ------------------------------------------------------------------------
-
-pub fn main() {
- // A `simple` lustre application doesn't produce `Effect`s. These are best to
- // start with if you're just getting started with lustre or you know you don't
- // need the runtime to manage any side effects.
- let app = lustre.simple(init, update, view)
- let assert Ok(_) = lustre.start(app, "[data-lustre-app]", Nil)
-}
-
-// MODEL -----------------------------------------------------------------------
-
-pub type Model =
- Int
-
-pub fn init(_) -> Model {
- 0
-}
-
-// UPDATE ----------------------------------------------------------------------
-
-pub opaque type Msg {
- Incr
- Decr
- Reset
-}
-
-pub fn update(model: Model, msg: Msg) -> Model {
- case msg {
- Incr -> model + 1
- Decr -> model - 1
- Reset -> 0
- }
-}
-
-// VIEW ------------------------------------------------------------------------
-
-pub fn view(model: Model) -> Element(Msg) {
- div([], [
- button([event.on_click(Incr)], [text("+")]),
- button([event.on_click(Decr)], [text("-")]),
- button([event.on_click(Reset)], [text("Reset")]),
- p([], [text(int.to_string(model))]),
- ])
-}
diff --git a/examples/events/gleam.toml b/examples/events/gleam.toml
deleted file mode 100644
index 46a962c..0000000
--- a/examples/events/gleam.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-name = "events"
-version = "1.0.0"
-target = "javascript"
-
-[dependencies]
-gleam_stdlib = "~> 0.34"
-lustre = { path = "../../" } \ No newline at end of file
diff --git a/examples/events/manifest.toml b/examples/events/manifest.toml
deleted file mode 100644
index 4116093..0000000
--- a/examples/events/manifest.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file was generated by Gleam
-# You typically do not need to edit this file
-
-packages = [
- { 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 = "lustre", version = "3.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], source = "local", path = "../.." },
- { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
-]
-
-[requirements]
-gleam_stdlib = { version = "~> 0.34" }
-lustre = { path = "../../" }
diff --git a/examples/events/src/events.gleam b/examples/events/src/events.gleam
deleted file mode 100644
index 7b4a4da..0000000
--- a/examples/events/src/events.gleam
+++ /dev/null
@@ -1,70 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import gleam/int
-import lustre
-import lustre/attribute
-import lustre/element.{type Element, text}
-import lustre/element/html.{button, div, p}
-import lustre/event
-
-// MAIN ------------------------------------------------------------------------
-
-pub fn main() {
- // A `simple` lustre application doesn't produce `Effect`s. These are best to
- // start with if you're just getting started with lustre or you know you don't
- // need the runtime to manage any side effects.
- let app = lustre.simple(init, update, view)
- let assert Ok(_) = lustre.start(app, "[data-lustre-app]", Nil)
-}
-
-// MODEL -----------------------------------------------------------------------
-
-pub type Model {
- Model(count: Int, active: Bool)
-}
-
-pub fn init(_) -> Model {
- Model(count: 0, active: True)
-}
-
-// UPDATE ----------------------------------------------------------------------
-
-pub opaque type Msg {
- Incr
- Decr
- Reset
- Toggle
-}
-
-pub fn update(model: Model, msg: Msg) -> Model {
- case msg {
- Incr -> Model(..model, count: model.count + 1)
- Decr -> Model(..model, count: model.count - 1)
- Reset -> Model(..model, count: 0)
- Toggle -> Model(..model, active: !model.active)
- }
-}
-
-// VIEW ------------------------------------------------------------------------
-
-pub fn view(model: Model) -> Element(Msg) {
- let on_click = fn(msg) {
- case model.active {
- True -> event.on_click(msg)
- False -> attribute.none()
- }
- }
-
- div([], [
- button([on_click(Incr)], [text("+")]),
- button([on_click(Decr)], [text("-")]),
- button([on_click(Reset)], [text("Reset")]),
- button([event.on_click(Toggle)], [
- case model.active {
- True -> text("Disable")
- False -> text("Enable")
- },
- ]),
- p([], [text(int.to_string(model.count))]),
- ])
-}
diff --git a/examples/input/gleam.toml b/examples/input/gleam.toml
deleted file mode 100644
index 5d891e8..0000000
--- a/examples/input/gleam.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-name = "input"
-version = "1.0.0"
-target = "javascript"
-
-[dependencies]
-gleam_stdlib = "~> 0.34"
-lustre = { path = "../../" } \ No newline at end of file
diff --git a/examples/input/manifest.toml b/examples/input/manifest.toml
deleted file mode 100644
index 16bdd27..0000000
--- a/examples/input/manifest.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file was generated by Gleam
-# You typically do not need to edit this file
-
-packages = [
- { 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_stdlib", "gleam_erlang"], 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 = "lustre", version = "3.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], source = "local", path = "../.." },
- { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
-]
-
-[requirements]
-gleam_stdlib = { version = "~> 0.34" }
-lustre = { path = "../../" }
diff --git a/examples/input/src/input.gleam b/examples/input/src/input.gleam
deleted file mode 100644
index 6425b0c..0000000
--- a/examples/input/src/input.gleam
+++ /dev/null
@@ -1,120 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import gleam/dynamic
-import gleam/string
-import lustre
-import lustre/attribute.{attribute}
-import lustre/element.{type Element, text}
-import lustre/element/html.{div, input, label, pre}
-import lustre/event
-
-// MAIN ------------------------------------------------------------------------
-
-pub fn main() {
- // A `simple` lustre application doesn't produce `Effect`s. These are best to
- // start with if you're just getting started with lustre or you know you don't
- // need the runtime to manage any side effects.
- let app = lustre.simple(init, update, view)
- let assert Ok(_) = lustre.start(app, "[data-lustre-app]", Nil)
-
- Nil
-}
-
-// MODEL -----------------------------------------------------------------------
-
-type Model {
- Model(email: String, password: String, remember_me: Bool)
-}
-
-fn init(_) -> Model {
- Model(email: "", password: "", remember_me: False)
-}
-
-// UPDATE ----------------------------------------------------------------------
-
-type Msg {
- Typed(Input, String)
- Toggled(Control, Bool)
-}
-
-type Input {
- Email
- Password
-}
-
-type Control {
- RememberMe
-}
-
-fn update(model: Model, msg: Msg) -> Model {
- case msg {
- Typed(Email, email) -> Model(..model, email: email)
- Typed(Password, password) -> Model(..model, password: password)
- Toggled(RememberMe, remember_me) -> Model(..model, remember_me: remember_me)
- }
-}
-
-// RENDER ----------------------------------------------------------------------
-
-fn view(model: Model) -> Element(Msg) {
- div([attribute.class("container")], [
- card([
- email_input(model.email),
- password_input(model.password),
- remember_checkbox(model.remember_me),
- pre([attribute.class("debug")], [
- string.inspect(model)
- |> string.replace("(", "(\n ")
- |> string.replace(", ", ",\n ")
- |> string.replace(")", "\n)")
- |> text,
- ]),
- ]),
- ])
-}
-
-fn card(content: List(Element(a))) -> Element(a) {
- div([attribute.class("card")], [div([], content)])
-}
-
-fn email_input(value: String) -> Element(Msg) {
- render_input(Email, "email", "email-input", value, "Email address")
-}
-
-fn password_input(value: String) -> Element(Msg) {
- render_input(Password, "password", "password-input", value, "Password")
-}
-
-fn render_input(
- field: Input,
- type_: String,
- id: String,
- value: String,
- label_: String,
-) -> Element(Msg) {
- div([attribute.class("input")], [
- label([attribute.for(id)], [text(label_)]),
- input([
- attribute.id(id),
- attribute.name(id),
- attribute.type_(type_),
- attribute.required(True),
- attribute.value(dynamic.from(value)),
- event.on_input(fn(value) { Typed(field, value) }),
- ]),
- ])
-}
-
-fn remember_checkbox(checked: Bool) -> Element(Msg) {
- div([attribute.class("flex items-center")], [
- input([
- attribute.id("remember-me"),
- attribute.name("remember-me"),
- attribute.type_("checkbox"),
- attribute.checked(checked),
- attribute.class("checkbox"),
- event.on_click(Toggled(RememberMe, !checked)),
- ]),
- label([attribute.for("remember-me")], [text("Remember me")]),
- ])
-}
diff --git a/examples/nested/gleam.toml b/examples/nested/gleam.toml
deleted file mode 100644
index dd00c99..0000000
--- a/examples/nested/gleam.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-name = "nested"
-version = "1.0.0"
-target = "javascript"
-
-[dependencies]
-gleam_stdlib = "~> 0.34"
-lustre = { path = "../../" } \ No newline at end of file
diff --git a/examples/nested/manifest.toml b/examples/nested/manifest.toml
deleted file mode 100644
index 6593d5e..0000000
--- a/examples/nested/manifest.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file was generated by Gleam
-# You typically do not need to edit this file
-
-packages = [
- { 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 = ["thoas", "gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "CB405BD93A8828BCD870463DE29375E7B2D252D9D124C109E5B618AAC00B86FC" },
- { name = "gleam_otp", version = "0.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_erlang"], 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 = "lustre", version = "3.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], source = "local", path = "../.." },
- { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
-]
-
-[requirements]
-gleam_stdlib = { version = "~> 0.34" }
-lustre = { path = "../../" }
diff --git a/examples/nested/src/nested.gleam b/examples/nested/src/nested.gleam
deleted file mode 100644
index 2e1b9ec..0000000
--- a/examples/nested/src/nested.gleam
+++ /dev/null
@@ -1,57 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import nested/counter
-import gleam/list
-import gleam/map.{type Map}
-import gleam/pair
-import lustre
-import lustre/element.{type Element}
-import lustre/element/html.{div}
-
-// MAIN ------------------------------------------------------------------------
-
-pub fn main() {
- // A `simple` lustre application doesn't produce `Effect`s. These are best to
- // start with if you're just getting started with lustre or you know you don't
- // need the runtime to manage any side effects.
- let app = lustre.simple(init, update, view)
- let assert Ok(_) = lustre.start(app, "[data-lustre-app]", Nil)
-
- Nil
-}
-
-// MODEL -----------------------------------------------------------------------
-
-type Model =
- Map(Int, counter.Model)
-
-fn init(_) -> Model {
- use counters, id <- list.fold(list.range(1, 10), map.new())
-
- map.insert(counters, id, counter.init(Nil))
-}
-
-// UPDATE ----------------------------------------------------------------------
-
-type Msg =
- #(Int, counter.Msg)
-
-fn update(model: Model, msg: Msg) -> Model {
- let #(id, counter_msg) = msg
- let assert Ok(counter) = map.get(model, id)
-
- map.insert(model, id, counter.update(counter, counter_msg))
-}
-
-// RENDER ----------------------------------------------------------------------
-
-fn view(model: Model) -> Element(Msg) {
- let counters = {
- use rest, id, counter <- map.fold(model, [])
- let el = element.map(counter.view(counter), pair.new(id, _))
-
- [el, ..rest]
- }
-
- div([], counters)
-}
diff --git a/examples/nested/src/nested/counter.gleam b/examples/nested/src/nested/counter.gleam
deleted file mode 100644
index 37af39a..0000000
--- a/examples/nested/src/nested/counter.gleam
+++ /dev/null
@@ -1,53 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import gleam/int
-import lustre
-import lustre/element.{type Element, text}
-import lustre/element/html.{button, div, p}
-import lustre/event
-
-// MAIN ------------------------------------------------------------------------
-
-pub fn main() {
- // A `simple` lustre application doesn't produce `Effect`s. These are best to
- // start with if you're just getting started with lustre or you know you don't
- // need the runtime to manage any side effects.
- let app = lustre.simple(init, update, view)
- let assert Ok(_) = lustre.start(app, "[data-lustre-app]", Nil)
-}
-
-// MODEL -----------------------------------------------------------------------
-
-pub type Model =
- Int
-
-pub fn init(_) -> Model {
- 0
-}
-
-// UPDATE ----------------------------------------------------------------------
-
-pub opaque type Msg {
- Incr
- Decr
- Reset
-}
-
-pub fn update(model: Model, msg: Msg) -> Model {
- case msg {
- Incr -> model + 1
- Decr -> model - 1
- Reset -> 0
- }
-}
-
-// VIEW ------------------------------------------------------------------------
-
-pub fn view(model: Model) -> Element(Msg) {
- div([], [
- button([event.on_click(Incr)], [text("+")]),
- button([event.on_click(Decr)], [text("-")]),
- button([event.on_click(Reset)], [text("Reset")]),
- p([], [text(int.to_string(model))]),
- ])
-}
diff --git a/examples/server_demo/README.md b/examples/server_demo/README.md
deleted file mode 100644
index c0d6a2a..0000000
--- a/examples/server_demo/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# server_demo
-
-[![Package Version](https://img.shields.io/hexpm/v/server_demo)](https://hex.pm/packages/server_demo)
-[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/server_demo/)
-
-## Quick start
-
-```sh
-gleam run # Run the project
-gleam test # Run the tests
-gleam shell # Run an Erlang shell
-```
-
-## Installation
-
-If available on Hex this package can be added to your Gleam project:
-
-```sh
-gleam add server_demo
-```
-
-and its documentation can be found at <https://hexdocs.pm/server_demo>.
diff --git a/examples/server_demo/gleam.toml b/examples/server_demo/gleam.toml
deleted file mode 100644
index 81a3557..0000000
--- a/examples/server_demo/gleam.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-name = "demo"
-version = "1.0.0"
-
-[dependencies]
-gleam_erlang = "~> 0.23"
-gleam_http = "~> 3.5"
-gleam_json = "~> 0.7"
-gleam_otp = "~> 0.8"
-gleam_stdlib = "~> 0.34"
-lustre = { path = "../../" }
-lustre_ui = "~> 0.2"
-mist = "~> 0.15"
-wisp = "~> 0.8"
diff --git a/examples/server_demo/manifest.toml b/examples/server_demo/manifest.toml
deleted file mode 100644
index d78134c..0000000
--- a/examples/server_demo/manifest.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-# This file was generated by Gleam
-# You typically do not need to edit this file
-
-packages = [
- { name = "exception", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "984401CFC95BCA87C391E36194D2B9E5B946467D44893FADB1CA4ACD4B7A29CE" },
- { 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_crypto", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "DE1FC4E631CA374AB29CCAEAC043EE171B86114D7DC66DD483F0A93BF0C4C6FF" },
- { name = "gleam_erlang", version = "0.24.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "26BDB52E61889F56A291CB34167315780EE4AA20961917314446542C90D1C1A0" },
- { name = "gleam_http", version = "3.5.3", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "C2FC3322203B16F897C1818D9810F5DEFCE347F0751F3B44421E1261277A7373" },
- { 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 = "glisten", version = "0.9.2", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_erlang", "gleam_otp"], otp_app = "glisten", source = "hex", outer_checksum = "C960B6CF25D4AABAB01211146E9B57E11827B9C49E4175217E0FB7EF5BCB0FF7" },
- { name = "lustre", version = "3.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], source = "local", path = "../.." },
- { name = "lustre_ui", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "F81BE5D20153CFFC717C2C4687A19375A8613528908AF7069DDA1B929C8398B1" },
- { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" },
- { name = "mist", version = "0.15.0", build_tools = ["gleam"], requirements = ["gleam_otp", "gleam_erlang", "gleam_stdlib", "gleam_http", "glisten"], otp_app = "mist", source = "hex", outer_checksum = "49F51DDB64D7B2832F72727CC9721C478D6B524C96EA444C601A19D01E023C03" },
- { name = "simplifile", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "359CD7006E2F69255025C858CCC6407C11A876EC179E6ED1E46809E8DC6B1AAD" },
- { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
- { name = "wisp", version = "0.10.0", build_tools = ["gleam"], requirements = ["marceau", "gleam_json", "simplifile", "gleam_http", "gleam_crypto", "mist", "gleam_stdlib", "exception", "gleam_erlang"], otp_app = "wisp", source = "hex", outer_checksum = "744FF91702078301BDF8FE76F26C14B658A7D151D867FA6995762318ED2536A0" },
-]
-
-[requirements]
-gleam_erlang = { version = "~> 0.23" }
-gleam_http = { version = "~> 3.5" }
-gleam_json = { version = "~> 0.7" }
-gleam_otp = { version = "~> 0.8" }
-gleam_stdlib = { version = "~> 0.34" }
-lustre = { path = "../../" }
-lustre_ui = { version = "~> 0.2" }
-mist = { version = "~> 0.15" }
-wisp = { version = "~> 0.8" }
diff --git a/examples/server_demo/src/demo.gleam b/examples/server_demo/src/demo.gleam
deleted file mode 100644
index ebe858a..0000000
--- a/examples/server_demo/src/demo.gleam
+++ /dev/null
@@ -1,22 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import demo/socket
-import demo/web
-import gleam/erlang/process
-import mist
-
-// MAIN ------------------------------------------------------------------------
-
-pub fn main() {
- let assert Ok(_) =
- mist.new(fn(req) {
- case req.path {
- "/ws" -> socket.handle(req)
- _ -> web.handle(req)
- }
- })
- |> mist.port(8000)
- |> mist.start_http
-
- process.sleep_forever()
-}
diff --git a/examples/server_demo/src/demo/app.gleam b/examples/server_demo/src/demo/app.gleam
deleted file mode 100644
index 13d09a8..0000000
--- a/examples/server_demo/src/demo/app.gleam
+++ /dev/null
@@ -1,88 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import gleam/dict.{type Dict}
-import gleam/dynamic.{type Decoder}
-import gleam/int
-import gleam/json
-import gleam/result
-import lustre/attribute
-import lustre/effect.{type Effect}
-import lustre/element.{type Element}
-import lustre/element/html
-import lustre/event
-import lustre/server
-import lustre/ui
-
-// MODEL -----------------------------------------------------------------------
-
-pub type Model =
- Int
-
-pub fn init(count: Int) -> #(Model, Effect(Msg)) {
- #(count, effect.none())
-}
-
-// UPDATE ----------------------------------------------------------------------
-
-pub opaque type Msg {
- Incr
- Decr
- Reset(Int)
-}
-
-pub fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
- case msg {
- Incr -> #(model + 1, effect.none())
- Decr -> #(model - 1, effect.none())
- Reset(count) -> #(
- count,
- effect.event(
- "changed",
- json.string("You reset the count to: " <> int.to_string(count)),
- ),
- )
- }
-}
-
-pub fn on_attribute_change() -> Dict(String, Decoder(Msg)) {
- dict.from_list([
- #("count", fn(dyn) {
- dyn
- |> dynamic.int
- |> result.map(Reset)
- }),
- ])
-}
-
-// VIEW ------------------------------------------------------------------------
-
-pub fn view(model: Model) -> Element(Msg) {
- let count = int.to_string(model)
-
- ui.centre(
- [attribute.style([#("width", "100vw"), #("height", "100vh")])],
- ui.sequence([], [
- ui.button([event.on_click(Decr)], [element.text("-")]),
- ui.centre([], html.span([], [element.text(count)])),
- ui.button([event.on_click(Incr)], [element.text("+")]),
- ]),
- )
- // ui.cluster([], [
- // ui.input([event.on_input(Change), attribute.value(model.input)]),
- // html.span([], [element.text(model.input)]),
- // ]),
- // ui.centre(
- // [
- // event.on("mousemove", on_mouse_move),
- // server.include(["offsetX", "offsetY"]),
- // attribute.style([
- // #("aspect-ratio", "1 / 1 "),
- // #("background-color", "var(--element-background)"),
- // ]),
- // ],
- // html.div([], [
- // html.p([], [element.text("x: " <> int.to_string(model.mouse.0))]),
- // html.p([], [element.text("y: " <> int.to_string(model.mouse.1))]),
- // ]),
- // ),
-}
diff --git a/examples/server_demo/src/demo/socket.gleam b/examples/server_demo/src/demo/socket.gleam
deleted file mode 100644
index bc43962..0000000
--- a/examples/server_demo/src/demo/socket.gleam
+++ /dev/null
@@ -1,78 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import demo/app
-import gleam/bit_array
-import gleam/erlang/process.{type Subject}
-import gleam/function.{identity}
-import gleam/http/request.{type Request as HttpRequest}
-import gleam/http/response.{type Response as HttpResponse}
-import gleam/json
-import gleam/option.{Some}
-import gleam/otp/actor
-import gleam/result
-import lustre.{type Action, type ServerComponent}
-import lustre/element.{type Patch}
-import lustre/server
-import mist.{
- type Connection, type ResponseData, type WebsocketConnection,
- type WebsocketMessage,
-}
-
-//
-
-pub fn handle(req: HttpRequest(Connection)) -> HttpResponse(ResponseData) {
- mist.websocket(req, update, init, function.constant(Nil))
-}
-
-type Model(flags, model, msg) {
- Model(self: Subject(Patch(msg)), app: Subject(Action(ServerComponent, msg)))
-}
-
-fn init(_) {
- let assert Ok(app) =
- lustre.component(app.init, app.update, app.view, app.on_attribute_change())
- |> lustre.start_actor(0)
- let self = process.new_subject()
- let model = Model(self, app)
- let selector = process.selecting(process.new_selector(), self, identity)
-
- actor.send(app, lustre.add_renderer(process.self(), process.send(self, _)))
- #(model, Some(selector))
-}
-
-fn update(
- model: Model(flags, model, msg),
- conn: WebsocketConnection,
- msg: WebsocketMessage(Patch(a)),
-) {
- case msg {
- mist.Text(bits) -> {
- let _ = {
- use dyn <- json.decode_bits(bits)
- use action <- result.try(server.decode_action(dyn))
-
- actor.send(model.app, action)
- Ok(Nil)
- }
-
- actor.continue(model)
- }
- mist.Binary(_) -> actor.continue(model)
- mist.Closed -> {
- actor.send(model.app, lustre.remove_renderer(process.self()))
- actor.continue(model)
- }
- mist.Shutdown -> {
- actor.send(model.app, lustre.shutdown())
- actor.Stop(process.Normal)
- }
- mist.Custom(patch) -> {
- element.encode_patch(patch)
- |> json.to_string
- |> bit_array.from_string
- |> mist.send_text_frame(conn, _)
-
- actor.continue(model)
- }
- }
-}
diff --git a/examples/server_demo/src/demo/web.gleam b/examples/server_demo/src/demo/web.gleam
deleted file mode 100644
index b8c17e2..0000000
--- a/examples/server_demo/src/demo/web.gleam
+++ /dev/null
@@ -1,58 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import gleam/http/request.{type Request as HttpRequest}
-import gleam/http/response.{type Response as HttpResponse}
-import gleam/result
-import gleam/string_builder
-import lustre/attribute.{attribute}
-import lustre/element
-import lustre/element/html.{html}
-import lustre/server
-import lustre/ui/styles
-import mist.{type Connection, type ResponseData}
-import wisp.{type Request, type Response}
-
-//
-
-pub fn handle(req: HttpRequest(Connection)) -> HttpResponse(ResponseData) {
- wisp.mist_handler(handler, "")(req)
-}
-
-fn handler(req: Request) -> Response {
- use req <- wisp.handle_head(req)
- use <- wisp.serve_static(req, under: "/static", from: static_directory())
-
- html([attribute("lang", "en")], [
- html.head([], [
- html.meta([attribute("charset", "utf-8")]),
- html.meta([
- attribute("name", "viewport"),
- attribute("content", "width=device-width, initial-scale=1"),
- ]),
- styles.elements(),
- html.script(
- [attribute("type", "module")],
- "
- import '/static/lustre-server-component.mjs'
-
- document.addEventListener('DOMContentLoaded', () => {
- document
- .querySelector('lustre-server-component')
- .addEventListener('alert', event => {
- console.log(`The server count says: ${event.detail}`)
- })
- })
- ",
- ),
- ]),
- html.body([], [server.component([server.route("/ws")])]),
- ])
- |> element.to_string_builder
- |> string_builder.prepend("<!DOCTYPE html>\n")
- |> wisp.html_response(200)
-}
-
-fn static_directory() -> String {
- wisp.priv_directory("lustre")
- |> result.unwrap("")
-}
diff --git a/examples/svg/gleam.toml b/examples/svg/gleam.toml
deleted file mode 100644
index b755f57..0000000
--- a/examples/svg/gleam.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-name = "svg"
-version = "1.0.0"
-target = "javascript"
-
-[dependencies]
-gleam_stdlib = "~> 0.34"
-lustre = { path = "../../" } \ No newline at end of file
diff --git a/examples/svg/manifest.toml b/examples/svg/manifest.toml
deleted file mode 100644
index 1c72364..0000000
--- a/examples/svg/manifest.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file was generated by Gleam
-# You typically do not need to edit this file
-
-packages = [
- { 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 = ["thoas", "gleam_stdlib"], 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 = "lustre", version = "3.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], source = "local", path = "../.." },
- { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
-]
-
-[requirements]
-gleam_stdlib = { version = "~> 0.34" }
-lustre = { path = "../../" }
diff --git a/examples/svg/src/svg.gleam b/examples/svg/src/svg.gleam
deleted file mode 100644
index 93be5e3..0000000
--- a/examples/svg/src/svg.gleam
+++ /dev/null
@@ -1,103 +0,0 @@
-// IMPORTS ---------------------------------------------------------------------
-
-import gleam/int
-import lustre
-import lustre/attribute.{attribute}
-import lustre/element.{type Element, text}
-import lustre/element/html.{button, div, p, svg}
-import lustre/element/svg.{path}
-import lustre/event
-
-// MAIN ------------------------------------------------------------------------
-
-pub fn main() {
- // A `simple` lustre application doesn't produce `Effect`s. These are best to
- // start with if you're just getting started with lustre or you know you don't
- // need the runtime to manage any side effects.
- let app = lustre.simple(init, update, view)
- let assert Ok(_) = lustre.start(app, "[data-lustre-app]", Nil)
-}
-
-// MODEL -----------------------------------------------------------------------
-
-pub type Model =
- Int
-
-pub fn init(_) -> Model {
- 0
-}
-
-// UPDATE ----------------------------------------------------------------------
-
-pub opaque type Msg {
- Incr
- Decr
- Reset
-}
-
-pub fn update(model: Model, msg: Msg) -> Model {
- case msg {
- Incr -> model + 1
- Decr -> model - 1
- Reset -> 0
- }
-}
-
-// VIEW ------------------------------------------------------------------------
-
-pub fn view(model: Model) -> Element(Msg) {
- div([], [
- button([event.on_click(Incr)], [
- plus([attribute.style([#("color", "red")])]),
- ]),
- button([event.on_click(Decr)], [minus([])]),
- button([event.on_click(Reset)], [text("Reset")]),
- p([], [text(int.to_string(model))]),
- ])
-}
-
-fn plus(attrs) {
- svg(
- [
- attribute("width", "15"),
- attribute("height", "15"),
- attribute("viewBox", "0 0 15 15"),
- attribute("fill", "none"),
- ..attrs
- ],
- [
- path([
- attribute(
- "d",
- "M8 2.75C8 2.47386 7.77614 2.25 7.5 2.25C7.22386 2.25 7 2.47386 7 2.75V7H2.75C2.47386 7 2.25 7.22386 2.25 7.5C2.25 7.77614 2.47386 8 2.75 8H7V12.25C7 12.5261 7.22386 12.75 7.5 12.75C7.77614 12.75 8 12.5261 8 12.25V8H12.25C12.5261 8 12.75 7.77614 12.75 7.5C12.75 7.22386 12.5261 7 12.25 7H8V2.75Z",
- ),
- attribute("fill", "currentColor"),
- attribute("fill-rule", "evenodd"),
- attribute("clip-rule", "evenodd"),
- ]),
- ],
- )
-}
-
-fn minus(attrs) {
- svg(
- [
- attribute("width", "15"),
- attribute("height", "15"),
- attribute("viewBox", "0 0 15 15"),
- attribute("fill", "none"),
- ..attrs
- ],
- [
- path([
- attribute(
- "d",
- "M2.25 7.5C2.25 7.22386 2.47386 7 2.75 7H12.25C12.5261 7 12.75 7.22386 12.75 7.5C12.75 7.77614 12.5261 8 12.25 8H2.75C2.47386 8 2.25 7.77614 2.25 7.5Z",
- ),
- attribute("fill", "currentColor"),
- attribute("fill-rule", "evenodd"),
- attribute("clip-rule", "evenodd"),
- ]),
- ],
- )
-}