aboutsummaryrefslogtreecommitdiff
path: root/test/example/application/counter.gleam
blob: 62d8599d3254bd63ba4d18b7a8b3e6fc607ea8ac (plain)
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("+") ]),
    ])
}