From 24f6962aa457d32319756f6217aafde7b0a9c752 Mon Sep 17 00:00:00 2001 From: Hayleigh Thompson Date: Tue, 23 Jan 2024 00:09:45 +0000 Subject: =?UTF-8?q?=E2=9C=A8=20Add=20universal=20components=20that=20can?= =?UTF-8?q?=20run=20on=20the=20server=20(#39)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :heavy_plus_sign: Add gleam_erlang gleam_otp and gleam_json dependencies. * :sparkles: Add json encoders for elememnts and attributes. * :sparkles: Add the ability to perform an effect with a custom dispatch function. * :construction: Experiment with a server-side component runtime. * :construction: Expose special server click events. * :construction: Experiment with a server-side component runtime. * :construction: Experiment with a server-side component runtime. * :construction: Experiment with a server-side component runtime. * :construction: Create a basic server component client bundle. * :construction: Create a basic server component demo. * :bug: Fixed a bug where the runtime stopped performing patches. * :refactor: Roll back introduction of shadow dom. * :recycle: Refactor to Custom Element-based approach to encapsulating server components. * :truck: Move some things around. * :sparkles: Add a minified version of the server component runtime. * :wrench: Add lustre/server/* to internal modules. * :recycle: on_attribute_change and on_client_event handlers are now functions not dicts. * :recycle: Refactor server component event handling to no longer need explicit tags. * :fire: Remove unnecessary attempt to stringify events. * :memo: Start documeint lustre/server functions. * :construction: Experiment with a js implementation of the server component backend runtime. * :recycle: Experiment with an API that makes heavier use of conditional complilation. * :recycle: Big refactor to unify server components, client components, and client apps. * :bug: Fixed some bugs with client runtimes. * :recycle: Update examples to new lustre api/ * :truck: Move server demo into examples/ folder/ * :wrench: Add lustre/runtime to internal modules. * :construction: Experiment with a diffing implementation. * :wrench: Hide internal modules from docs. * :heavy_plus_sign: Update deps to latest versions. * :recycle: Move diffing and vdom code into separate internal modules. * :sparkles: Bring server components to feature parity with client components. * :recycle: Update server component demo. * :bug: Fix bug where attribute changes weren't properly broadcast. * :fire: Remove unused 'Patch' type. * :recycle: Stub out empty js implementations so we can build for js. * :memo: Docs for the docs gods. * :recycle: Rename lustre.server_component to lustre.component. --- examples/server_demo/src/demo/app.gleam | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 examples/server_demo/src/demo/app.gleam (limited to 'examples/server_demo/src/demo/app.gleam') diff --git a/examples/server_demo/src/demo/app.gleam b/examples/server_demo/src/demo/app.gleam new file mode 100644 index 0000000..13d09a8 --- /dev/null +++ b/examples/server_demo/src/demo/app.gleam @@ -0,0 +1,88 @@ +// 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))]), + // ]), + // ), +} -- cgit v1.2.3