git.iko.soy/purestack-dev/todomvc
on master help sign in
runMsg
a4c41d9iko
flake.nix+2
@@ -38,6 +38,8 @@
38 project-m36.command = "${
38 project-m36.command = "${
39 project-m36-rest.packages.${system}.default
39 project-m36-rest.packages.${system}.default
40 }/bin/project-m36-rest";
40 }/bin/project-m36-rest";
41+ proxy.command =
42+ "${pkgs.reproxy}/bin/reproxy -l=localhost:3001 --static.enabled --static.rule='*,^/api/(.*),http://localhost:3000/$1' --assets.location=. --assets.spa";
41 };
43 };
42 });
44 });
43 in {
45 in {
src/Frontend.purs+9−5
@@ -19,14 +19,18 @@ type Model = { newTodo :: String, todos :: Array String }
19data Msg
19data Msg
20 = UpdateNewTodo String
20 = UpdateNewTodo String
21 | AddNewTodo
21 | AddNewTodo
22+ | TodoAdded
22
23
23main :: Effect Unit
24main :: Effect Unit
24main = do
25main = do
25 Plum.run @Model @Msg "plum"
26 Plum.run @Model @Msg "plum"
26− { init: pure { newTodo: "", todos: [] }
27+ { init: \_runMsg -> pure { newTodo: "", todos: [] }
27− , update: \msg model -> case msg of
28+ , update: \runMsg msg model -> case msg of
28 UpdateNewTodo newTodo -> pure model { newTodo = newTodo }
29 UpdateNewTodo newTodo -> pure model { newTodo = newTodo }
30+ AddNewTodo -> do
31+ runMsg $ api.createTodo (TodoItem { text: model.newTodo, done: false }) $> TodoAdded
29− AddNewTodo -> pure model { newTodo = "", todos = model.newTodo : model.todos }
32+ pure model { newTodo = "", todos = model.newTodo : model.todos }
33+ TodoAdded -> pure model
30 , view: \model -> column do
34 , view: \model -> column do
31 font "sans-serif"
35 font "sans-serif"
32
36
@@ -46,9 +50,9 @@ main = do
46 text todo mempty
50 text todo mempty
47 }
51 }
48
52
49−url = case URL.fromString "localhost" of
53+url = case URL.fromString "http://localhost" of
50 Just x -> x
54 Just x -> x
51 Nothing -> unsafeCoerce unit
55 Nothing -> unsafeCoerce unit
52
56
53−x = client @API url
57+api = client @API url
54
58
src/Plum.purs+37−13
@@ -5,12 +5,15 @@ import Prelude
5import Data.Array as Array
5import Data.Array as Array
6import Data.Maybe (Maybe(..))
6import Data.Maybe (Maybe(..))
7import Effect (Effect)
7import Effect (Effect)
8+import Effect.Aff (Aff, launchAff_)
9+import Effect.Class (liftEffect)
8import Effect.Console (log)
10import Effect.Console (log)
9import Effect.Ref as Ref
11import Effect.Ref as Ref
10import Foreign.Object as Object
12import Foreign.Object as Object
11import Literals.Undefined (undefined)
13import Literals.Undefined (undefined)
12import Plum.View (GenericUI(..), UI, grow)
14import Plum.View (GenericUI(..), UI, grow)
13import Snabbdom as Snabbdom
15import Snabbdom as Snabbdom
16+import Unsafe.Coerce (unsafeCoerce)
14import Untagged.Union (asOneOf)
17import Untagged.Union (asOneOf)
15import Web.DOM.NonElementParentNode (getElementById) as Web
18import Web.DOM.NonElementParentNode (getElementById) as Web
16import Web.HTML (window) as Web
19import Web.HTML (window) as Web
@@ -18,8 +21,8 @@ import Web.HTML.HTMLDocument (toNonElementParentNode) as Web
18import Web.HTML.Window (document) as Web
21import Web.HTML.Window (document) as Web
19
22
20type Plum msg model =
23type Plum msg model =
21− { init :: Effect model
24+ { init :: (Aff msg -> Effect Unit) -> Effect model
22− , update :: msg -> model -> Effect model
25+ , update :: (Aff msg -> Effect Unit) -> msg -> model -> Effect model
23 , view :: model -> UI msg Unit
26 , view :: model -> UI msg Unit
24 }
27 }
25
28
@@ -28,25 +31,36 @@ run id plum = do
28 Web.window >>= Web.document >>= Web.getElementById id <<< Web.toNonElementParentNode >>= case _ of
31 Web.window >>= Web.document >>= Web.getElementById id <<< Web.toNonElementParentNode >>= case _ of
29 Just element -> do
32 Just element -> do
30 let node = Snabbdom.toVNode element
33 let node = Snabbdom.toVNode element
34+ modelRef <- Ref.new { model: unsafeCoerce undefined, lastNode: node }
31 patch <- Snabbdom.init
35 patch <- Snabbdom.init
32− initModel <- plum.init
33− modelRef <- Ref.new { model: initModel, lastNode: node }
34 let
36 let
37+ fire =
38+ ( \msg -> do
39+ log "in"
40+ { model: m, lastNode } <- Ref.read modelRef
41+ m_ <- plum.update
42+ ( \aff ->
43+ launchAff_
44+ ( do
45+ msg' <- aff
46+ liftEffect $ fire msg'
47+ pure unit
48+ )
49+ )
50+ msg
51+ m
52+ node' <- view m_
53+ newNode <- patch lastNode node'
54+ Ref.write { model: m_, lastNode: newNode } modelRef
55+ pure unit
56+ )
35 view model = do
57 view model = do
36 let UI { children } _ = plum.view model
58 let UI { children } _ = plum.view model
37 case Array.uncons children of
59 case Array.uncons children of
38 Just { head: child } -> do
60 Just { head: child } -> do
39 let
61 let
40 { node, style } = grow
62 { node, style } = grow
41− ( \msg -> do
63+ fire
42− log "in"
43− { model: m, lastNode } <- Ref.read modelRef
44− m_ <- plum.update msg m
45− node <- view m_
46− newNode <- patch lastNode node
47− Ref.write { model: m_, lastNode: newNode } modelRef
48− pure unit
49− )
50 child
64 child
51 pure $
65 pure $
52 Snabbdom.h "div"
66 Snabbdom.h "div"
@@ -75,6 +89,15 @@ run id plum = do
75 }
89 }
76 []
90 []
77 (asOneOf undefined)
91 (asOneOf undefined)
92+ initModel <- plum.init
93+ ( \aff ->
94+ launchAff_
95+ ( do
96+ msg' <- aff
97+ liftEffect $ fire msg'
98+ pure unit
99+ )
100+ )
78 newNode <- view initModel
101 newNode <- view initModel
79 newNode_ <- patch node newNode
102 newNode_ <- patch node newNode
80 log "patched"
103 log "patched"
@@ -84,3 +107,4 @@ run id plum = do
84
107
85outerStyle :: String
108outerStyle :: String
86outerStyle = "html,body{height:100%;padding:0;margin:0;}"
109outerStyle = "html,body{height:100%;padding:0;margin:0;}"
110+