git.iko.soy/purestack-dev/todomvc
on c8f9b92 help sign in
flake.nix−2
since splitsnapshots
unifiedsplit
@@ -38,8 +38,6 @@
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 --logger.stdout";
43 };
41 };
44 });
42 });
45 in {
43 in {
src/Frontend.purs+13−19
@@ -7,36 +7,26 @@ import Prim
7
7
8import Data.Array ((:))
8import Data.Array ((:))
9import Data.Foldable (for_)
9import Data.Foldable (for_)
10+import Data.Maybe (Maybe(..))
10import Data.URL as URL
11import Data.URL as URL
11import Effect (Effect)
12import Effect (Effect)
12import Plum as Plum
13import Plum as Plum
13import PureStack.Client (client)
14import PureStack.Client (client)
15+import Unsafe.Coerce (unsafeCoerce)
14
16
15−type Model = { newTodo :: String, todos :: Array TodoItem }
17+type Model = { newTodo :: String, todos :: Array String }
16
18
17data Msg
19data Msg
18 = UpdateNewTodo String
20 = UpdateNewTodo String
19− | SetTodos (Array TodoItem)
20 | AddNewTodo
21 | AddNewTodo
21− | TodoAdded
22
22
23main :: Effect Unit
23main :: Effect Unit
24main = do
24main = do
25− origin <- Plum.currentOrigin
26− let api = getApi (origin `URL.addSegment` "api")
27 Plum.run @Model @Msg "plum"
25 Plum.run @Model @Msg "plum"
28− { init: \runMsg -> do
29− runMsg $ SetTodos <$> api.getTodos
30− pure { newTodo: "", todos: [] }
26+ { init: pure { newTodo: "", todos: [] }
31− , update: \runMsg msg model -> case msg of
27+ , update: \msg model -> case msg of
32 UpdateNewTodo newTodo -> pure model { newTodo = newTodo }
28 UpdateNewTodo newTodo -> pure model { newTodo = newTodo }
33− AddNewTodo -> do
29+ AddNewTodo -> pure model { newTodo = "", todos = model.newTodo : model.todos }
34− runMsg $ api.createTodo (TodoItem { text: model.newTodo, done: false }) $> TodoAdded
35− pure model
36− TodoAdded -> do
37− runMsg $ SetTodos <$> api.getTodos
38− pure model
39− SetTodos todos -> pure model { todos = todos }
40 , view: \model -> column do
30 , view: \model -> column do
41 font "sans-serif"
31 font "sans-serif"
42
32
@@ -52,9 +42,13 @@ main = do
52
42
53 onKey "Enter" AddNewTodo
43 onKey "Enter" AddNewTodo
54
44
55− for_ model.todos $ \(TodoItem todo) -> do
45+ for_ model.todos $ \todo -> do
56− text todo.text mempty
46+ text todo mempty
57 }
47 }
58
48
49+url = case URL.fromString "localhost" of
50+ Just x -> x
51+ Nothing -> unsafeCoerce unit
52+
59−getApi = client @API
53+x = client @API url
60
54
src/Plum.purs+15−50
@@ -1,33 +1,25 @@
1−module Plum (Plum, run, currentOrigin) where
1+module Plum (Plum, run) where
2
2
3import Prelude
3import Prelude
4
4
5import Data.Array as Array
5import Data.Array as Array
6import Data.Maybe (Maybe(..))
6import Data.Maybe (Maybe(..))
7−import Data.URL (URL)
8−import Data.URL as URL
9import Effect (Effect)
7import Effect (Effect)
10−import Effect.Aff (Aff, launchAff_)
11−import Effect.Class (liftEffect)
12import Effect.Console (log)
8import Effect.Console (log)
13−import Effect.Exception (throw)
14import Effect.Ref as Ref
9import Effect.Ref as Ref
15import Foreign.Object as Object
10import Foreign.Object as Object
16import Literals.Undefined (undefined)
11import Literals.Undefined (undefined)
17import Plum.View (GenericUI(..), UI, grow)
12import Plum.View (GenericUI(..), UI, grow)
18import Snabbdom as Snabbdom
13import Snabbdom as Snabbdom
19−import Unsafe.Coerce (unsafeCoerce)
20import Untagged.Union (asOneOf)
14import Untagged.Union (asOneOf)
21import Web.DOM.NonElementParentNode (getElementById) as Web
15import Web.DOM.NonElementParentNode (getElementById) as Web
22import Web.HTML (window) as Web
16import Web.HTML (window) as Web
23−import Web.HTML.Event.EventTypes (invalid)
24import Web.HTML.HTMLDocument (toNonElementParentNode) as Web
17import Web.HTML.HTMLDocument (toNonElementParentNode) as Web
25−import Web.HTML.Location as Location
26−import Web.HTML.Window (document, location) as Web
18+import Web.HTML.Window (document) as Web
27
19
28type Plum msg model =
20type Plum msg model =
29− { init :: (Aff msg -> Effect Unit) -> Effect model
21+ { init :: Effect model
30− , update :: (Aff msg -> Effect Unit) -> msg -> model -> Effect model
22+ , update :: msg -> model -> Effect model
31 , view :: model -> UI msg Unit
23 , view :: model -> UI msg Unit
32 }
24 }
33
25
@@ -36,36 +28,25 @@ run id plum = do
36 Web.window >>= Web.document >>= Web.getElementById id <<< Web.toNonElementParentNode >>= case _ of
28 Web.window >>= Web.document >>= Web.getElementById id <<< Web.toNonElementParentNode >>= case _ of
37 Just element -> do
29 Just element -> do
38 let node = Snabbdom.toVNode element
30 let node = Snabbdom.toVNode element
39− modelRef <- Ref.new { model: unsafeCoerce undefined, lastNode: node }
40 patch <- Snabbdom.init
31 patch <- Snabbdom.init
32+ initModel <- plum.init
33+ modelRef <- Ref.new { model: initModel, lastNode: node }
41 let
34 let
42− fire =
43− ( \msg -> do
44− log "in"
45− { model: m, lastNode } <- Ref.read modelRef
46− m_ <- plum.update
47− ( \aff ->
48− launchAff_
49− ( do
50− msg' <- aff
51− liftEffect $ fire msg'
52− pure unit
53− )
54− )
55− msg
56− m
57− node' <- view m_
58− newNode <- patch lastNode node'
59− Ref.write { model: m_, lastNode: newNode } modelRef
60− pure unit
61− )
62 view model = do
35 view model = do
63 let UI { children } _ = plum.view model
36 let UI { children } _ = plum.view model
64 case Array.uncons children of
37 case Array.uncons children of
65 Just { head: child } -> do
38 Just { head: child } -> do
66 let
39 let
67 { node, style } = grow
40 { node, style } = grow
68− fire
41+ ( \msg -> do
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+ )
69 child
50 child
70 pure $
51 pure $
71 Snabbdom.h "div"
52 Snabbdom.h "div"
@@ -94,15 +75,6 @@ run id plum = do
94 }
75 }
95 []
76 []
96 (asOneOf undefined)
77 (asOneOf undefined)
97− initModel <- plum.init
98− ( \aff ->
99− launchAff_
100− ( do
101− msg' <- aff
102− liftEffect $ fire msg'
103− pure unit
104− )
105− )
106 newNode <- view initModel
78 newNode <- view initModel
107 newNode_ <- patch node newNode
79 newNode_ <- patch node newNode
108 log "patched"
80 log "patched"
@@ -112,10 +84,3 @@ run id plum = do
112
84
113outerStyle :: String
85outerStyle :: String
114outerStyle = "html,body{height:100%;padding:0;margin:0;}"
86outerStyle = "html,body{height:100%;padding:0;margin:0;}"
115−
116−currentOrigin :: Effect URL
117−currentOrigin = do
118− s <- Web.window >>= Web.location >>= Location.origin
119− case URL.fromString s of
120− Nothing -> throw "window.location.origin returned an invalid url"
121− Just url -> pure url