Skip to content

Commit

Permalink
docs: finish first throw of docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ghivert committed Apr 17, 2024
1 parent 8499910 commit 7a269fa
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 19 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ pub fn main() {
let assert Ok(main) = tardis.single("main")
lustre.application(init, update, view)
|> tardis.wrap(main)
|> tardis.wrap(with: main)
|> lustre.start("#app", Nil)
|> tardis.activate(main)
|> tardis.activate(with: main)
}
fn init(_) {
Expand Down Expand Up @@ -61,9 +61,9 @@ You're good to go!

## Multiple apps setup

While it's easy to setup a single application with tardis, it can also be used to debug multiple applications in the same page. Tardis exposes two additional functions: [`setup`](https://hexdocs.pm/tardis/tardis.html#setup) and [`application`](https://hexdocs.pm/tardis/tardis.html#application). The first one initialize the instance of the debugger, while the second one allows to setup an application on the debugger!
While it's easy to setup a single application with tardis, it can also be used to debug multiple applications in the same page. Tardis exposes two additional functions: [`setup`](https://hexdocs.pm/tardis/tardis.html#setup) and [`application`](https://hexdocs.pm/tardis/tardis.html#application). The first one initialize the debugger, while the second one allows to setup an application on the debugger!

In case you're developping a independant package, you can even send the debugger instance directly to your application, and it will nicely integrate in it!
In case you're developping a independant package, you can even send the tardis or the debugger instance directly to your application, and it will nicely integrate in it!

```gleam
import gleam/int
Expand All @@ -78,14 +78,14 @@ pub fn main() {
let mod = tardis.application(instance, "module")
lustre.application(init_1, update_1, view_1)
|> tardis.wrap(main)
|> tardis.wrap(with: main)
|> lustre.start("#app", Nil)
|> tardis.activate(main)
|> tardis.activate(with: main)
lustre.application(init_2, update_2, view_2)
|> tardis.wrap(mod)
|> tardis.wrap(with: mod)
|> lustre.start("#mod", Nil)
|> tardis.activate(mod)
|> tardis.activate(with: mod)
}
```

Expand Down
99 changes: 88 additions & 11 deletions src/tardis.gleam
Original file line number Diff line number Diff line change
@@ -1,3 +1,43 @@
//// Tardis is in charge of being your good debugger friend, able to navigate
//// accross time and space! Just instanciate it, and use it in your application.
////
//// ```gleam
//// import gleam/int
//// import lustre
//// import lustre/element/html
//// import lustre/event
//// import tardis
////
//// pub fn main() {
//// let assert Ok(main) = tardis.single("main")
////
//// lustre.application(init, update, view)
//// |> tardis.wrap(with: main)
//// |> lustre.start("#app", Nil)
//// |> tardis.activate(with: main)
//// }
////
//// fn init(_) {
//// 0
//// }
////
//// fn update(model, msg) {
//// case msg {
//// Incr -> model + 1
//// Decr -> model - 1
//// }
//// }
////
//// fn view(model) {
//// let count = int.to_string(model)
//// html.div([], [
//// html.button([event.on_click(Incr)], [html.text(" + ")]),
//// html.p([], [html.text(count)]),
//// html.button([event.on_click(Decr)], [html.text(" - ")])
//// ])
//// }
//// ```

import gleam/dynamic.{type Dynamic}
import gleam/function
import gleam/int
Expand All @@ -23,26 +63,57 @@ import tardis/internals/setup.{type Middleware}
import tardis/internals/styles as s
import tardis/internals/view as v

pub opaque type Instance {
Instance(dispatch: fn(Action(Msg, lustre.ClientSpa)) -> Nil)
/// Represents the running Tardis. Should be used with lustre applications
/// only. One tardis is enough for multiple lustre applications running on the
/// same page, with their own update loop.
pub opaque type Tardis {
Tardis(dispatch: fn(Action(Msg, lustre.ClientSpa)) -> Nil)
}

pub opaque type Tardis {
Tardis(#(fn(Dynamic) -> Nil, Middleware))
/// Represents the instance for an application. It should be used within one and
/// only one application. You can get the instance by using [`application`](#application)
/// or [`single`](#single).
pub opaque type Instance {
Instance(#(fn(Dynamic) -> Nil, Middleware))
}

pub fn wrap(application: App(a, b, c), tardis: Tardis) {
let Tardis(#(_, middleware)) = tardis
/// Wrap a lustre application with the debugger. The debugger will never interfere
/// with your application by itself. You can directly chain your application with
/// this function.
/// ```gleam
/// fn main() {
/// let assert Ok(instance) = tardis.single("main")
/// lustre.application(init, update, view)
/// |> tardis.wrap(with: instance)
/// }
/// ```
pub fn wrap(application: App(a, b, c), with instance: Instance) {
let Instance(#(_, middleware)) = instance
setup.update_lustre(
application,
setup.wrap_init(middleware),
setup.wrap_update(middleware),
)
}

pub fn activate(result: Result(fn(Action(a, b)) -> Nil, c), tardis: Tardis) {
/// Activate the debugger of the application. `activate` should be run to let
/// the debugger being able to rewind time. It should be executed on the exact
/// same instance that has been wrapped.
/// ```gleam
/// fn main() {
/// let assert Ok(instance) = tardis.single("main")
/// lustre.application(init, update, view)
/// |> tardis.wrap(with: instance)
/// |> lustre.start()
/// |> tardis.activate(with: instance)
/// }
/// ```
pub fn activate(
result: Result(fn(Action(a, b)) -> Nil, c),
with instance: Instance,
) {
use dispatch <- result.map(result)
let Tardis(#(dispatcher, _)) = tardis
let Instance(#(dispatcher, _)) = instance
dispatcher(dynamic.from(dispatch))
dispatch
}
Expand All @@ -62,25 +133,31 @@ fn start_sketch(root) {
error.SketchError(error)
}

/// Creates the tardis. Should be run once, at the start of the application.
/// It can be skipped when using [`single`](#single).
pub fn setup() {
let #(shadow_root, lustre_root) = setup.mount_shadow_node()
start_sketch(shadow_root)
|> result.map(sketch.compose(view, _))
|> result.map(lustre.application(init, update, _))
|> result.try(start_lustre(lustre_root, _))
|> result.map(fn(dispatch) { Instance(dispatch) })
|> result.map(fn(dispatch) { Tardis(dispatch) })
}

/// Directly creates a tardis instance for a single application.
/// Replaces `setup` and `application` in a single application context.
pub fn single(name: String) {
setup()
|> result.map(application(_, name))
}

pub fn application(instance: Instance, name: String) {
/// Creates the application debugger from the tardis. Should be run once,
/// at the start of the application. It can be skipped when using [`single`](#single).
pub fn application(instance: Tardis, name: String) -> Instance {
let dispatch = instance.dispatch
let updater = setup.create_model_updater(dispatch, name)
let adder = setup.step_adder(dispatch, name)
Tardis(#(updater, adder))
Instance(#(updater, adder))
}

fn init(_) {
Expand Down
3 changes: 3 additions & 0 deletions src/tardis/error.gleam
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//// Manages error for Tardis.
//// Used only during initialization, to identify what is failing.

import lustre
import sketch/error as sketch

Expand Down

0 comments on commit 7a269fa

Please sign in to comment.