1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
// IMPORTS ---------------------------------------------------------------------
import gleam/int
import lustre
import lustre/attribute.{ style }
import lustre/cmd.{ Cmd }
import lustre/element.{ button, div, p, text }
import lustre/event.{ on_click }
// MAIN ------------------------------------------------------------------------
pub fn main () -> Nil {
let selector = "[data-lustre-container]"
let program = lustre.application(init(), update, render)
// `lustre.start` can return an `Error` if no DOM element is found that matches
// the selector. This is a fatal error for our examples, so we panic if that
// happens.
let assert Ok(_) = lustre.start(program, selector)
Nil
}
// STATE -----------------------------------------------------------------------
pub type State {
State(
count: Int,
clock: Bool,
timer_id: Int
)
}
pub fn init () -> #(State, Cmd(Action)) {
#(State(0, True, 0), tick())
}
// UPDATE ----------------------------------------------------------------------
pub type Action {
Incr
Decr
Tick
}
pub fn update (state, action) {
case action {
Incr ->
#(State(..state, count: state.count + 1), cmd.none())
Decr ->
#(State(..state, count: state.count - 1), cmd.none())
Tick ->
#(State(..state, count: state.count + 1),
case state.clock {
True ->
tick()
False ->
cmd.none()
}
)
}
}
external fn after (f: fn () -> any, delay: Int) -> Nil
= "" "window.setTimeout"
fn tick () -> Cmd(Action) {
cmd.from(fn (dispatch) {
after(fn () {
dispatch(Tick)
}, 1000)
})
}
// RENDER ----------------------------------------------------------------------
pub fn render (state: State) {
div([ style([ #("display", "flex") ]) ], [
button([ on_click(Decr) ], [ text("-") ]),
p([], [ int.to_string(state.count) |> text ]),
button([ on_click(Incr) ], [ text("+") ]),
])
}
|