frontend: render blog posts
This commit is contained in:
parent
4a52f5006b
commit
81206835d5
|
@ -0,0 +1,9 @@
|
||||||
|
// Module App.BlogEntry
|
||||||
|
|
||||||
|
exports.mdify = function(id) {
|
||||||
|
var converter = new showdown.Converter()
|
||||||
|
elem = document.getElementById(id);
|
||||||
|
md = elem.innerHTML;
|
||||||
|
elem.innerHTML = converter.makeHtml(md);
|
||||||
|
return "done :)";
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
module App.BlogEntry where
|
||||||
|
|
||||||
|
import Control.Monad.Aff (attempt)
|
||||||
|
import DOM (DOM)
|
||||||
|
import Data.Argonaut (class DecodeJson, decodeJson, (.?))
|
||||||
|
import Data.Either (Either(..), either)
|
||||||
|
import Data.Maybe (Maybe(..))
|
||||||
|
import Network.HTTP.Affjax (AJAX, get)
|
||||||
|
import Prelude (bind, pure, show, ($), (<>), (<<<))
|
||||||
|
import Pux (EffModel, noEffects)
|
||||||
|
import Pux.Html (Html, div, h1, h2, p, text)
|
||||||
|
import Pux.Html.Attributes (id_)
|
||||||
|
|
||||||
|
data Action = RequestPost
|
||||||
|
| ReceivePost (Either String Post)
|
||||||
|
| RenderPost
|
||||||
|
|
||||||
|
type State =
|
||||||
|
{ status :: String
|
||||||
|
, hack :: String
|
||||||
|
, id :: Maybe Int
|
||||||
|
, post :: Post
|
||||||
|
, name :: String }
|
||||||
|
|
||||||
|
data Post = Post
|
||||||
|
{ title :: String
|
||||||
|
, body :: String
|
||||||
|
, date :: String }
|
||||||
|
|
||||||
|
instance decodeJsonPost :: DecodeJson Post where
|
||||||
|
decodeJson json = do
|
||||||
|
obj <- decodeJson json
|
||||||
|
title <- obj .? "title"
|
||||||
|
body <- obj .? "body"
|
||||||
|
date <- obj .? "date"
|
||||||
|
pure $ Post { title: title, body: body, date: date }
|
||||||
|
|
||||||
|
init :: State
|
||||||
|
init =
|
||||||
|
{ status: "Loading..."
|
||||||
|
, hack: ""
|
||||||
|
, post: Post
|
||||||
|
{ title: ""
|
||||||
|
, body: ""
|
||||||
|
, date: "" }
|
||||||
|
, name: ""
|
||||||
|
, id: Nothing }
|
||||||
|
|
||||||
|
update :: Action -> State -> EffModel State Action (ajax :: AJAX, dom :: DOM)
|
||||||
|
update (ReceivePost (Left err)) state =
|
||||||
|
noEffects $ state { id = Nothing, status = err }
|
||||||
|
update (ReceivePost (Right post)) state =
|
||||||
|
{ state: state { status = "", id = Just 1, post = post }
|
||||||
|
, effects: [ pure $ RenderPost ]
|
||||||
|
}
|
||||||
|
update RequestPost state =
|
||||||
|
{ state: state
|
||||||
|
, effects: [ do
|
||||||
|
res <- attempt $ get ("/api/blog/post?name=" <> state.name)
|
||||||
|
let decode r = decodeJson r.response :: Either String Post
|
||||||
|
let post = either (Left <<< show) decode res
|
||||||
|
pure $ ReceivePost post
|
||||||
|
]
|
||||||
|
}
|
||||||
|
update RenderPost state =
|
||||||
|
noEffects $ state { hack = mdify "blogpost" }
|
||||||
|
|
||||||
|
view :: State -> Html Action
|
||||||
|
view { id: id, status: status, post: (Post post) } =
|
||||||
|
case id of
|
||||||
|
Nothing -> div [] []
|
||||||
|
(Just _) ->
|
||||||
|
div []
|
||||||
|
[ h1 [] [ text status ]
|
||||||
|
, div []
|
||||||
|
[ p [ id_ "blogpost" ] [ text post.body ] ]
|
||||||
|
]
|
||||||
|
|
||||||
|
foreign import mdify :: String -> String
|
|
@ -39,15 +39,15 @@ instance decodeJsonPost :: DecodeJson Post where
|
||||||
init :: State
|
init :: State
|
||||||
init =
|
init =
|
||||||
{ posts: []
|
{ posts: []
|
||||||
, status: "Loading..." }
|
, status: "" }
|
||||||
|
|
||||||
update :: Action -> State -> EffModel State Action (ajax :: AJAX, dom :: DOM)
|
update :: Action -> State -> EffModel State Action (ajax :: AJAX, dom :: DOM)
|
||||||
update (ReceivePosts (Left err)) state =
|
update (ReceivePosts (Left err)) state =
|
||||||
noEffects $ state { status = ("error: " <> err) }
|
noEffects $ state { status = ("error: " <> err) }
|
||||||
update (ReceivePosts (Right posts)) state =
|
update (ReceivePosts (Right posts)) state =
|
||||||
noEffects $ state { posts = posts, status = "Posts" }
|
noEffects $ state { posts = posts, status = "" }
|
||||||
update RequestPosts state =
|
update RequestPosts state =
|
||||||
{ state: state { status = "Fetching posts..." }
|
{ state: state { status = "Loading..." }
|
||||||
, effects: [ do
|
, effects: [ do
|
||||||
res <- attempt $ get "/api/blog/posts"
|
res <- attempt $ get "/api/blog/posts"
|
||||||
let decode r = decodeJson r.response :: Either String Posts
|
let decode r = decodeJson r.response :: Either String Posts
|
||||||
|
@ -79,5 +79,6 @@ view :: State -> Html Action
|
||||||
view state =
|
view state =
|
||||||
div
|
div
|
||||||
[]
|
[]
|
||||||
[ h1 [] [ text state.status ]
|
[ h1 [] [ text "Posts" ]
|
||||||
|
, p [] [ text state.status ]
|
||||||
, div [ className "row" ] $ map post state.posts ]
|
, div [ className "row" ] $ map post state.posts ]
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
module App.Layout where
|
module App.Layout where
|
||||||
|
|
||||||
|
import App.BlogEntry as BlogEntry
|
||||||
import App.BlogIndex as BlogIndex
|
import App.BlogIndex as BlogIndex
|
||||||
import App.Counter as Counter
|
import App.Counter as Counter
|
||||||
import App.Routes (Route(..))
|
import App.Routes (Route(..))
|
||||||
|
import Control.Monad.RWS (state)
|
||||||
import DOM (DOM)
|
import DOM (DOM)
|
||||||
import Network.HTTP.Affjax (AJAX)
|
import Network.HTTP.Affjax (AJAX)
|
||||||
import Prelude (($), (#), map, pure)
|
import Prelude (($), (#), map, pure)
|
||||||
|
@ -14,29 +16,37 @@ import Pux.Router (link)
|
||||||
data Action
|
data Action
|
||||||
= Child (Counter.Action)
|
= Child (Counter.Action)
|
||||||
| BIChild (BlogIndex.Action)
|
| BIChild (BlogIndex.Action)
|
||||||
|
| BEChild (BlogEntry.Action)
|
||||||
| PageView Route
|
| PageView Route
|
||||||
|
|
||||||
type State =
|
type State =
|
||||||
{ route :: Route
|
{ route :: Route
|
||||||
, count :: Counter.State
|
, count :: Counter.State
|
||||||
, bistate :: BlogIndex.State }
|
, bistate :: BlogIndex.State
|
||||||
|
, bestate :: BlogEntry.State }
|
||||||
|
|
||||||
init :: State
|
init :: State
|
||||||
init =
|
init =
|
||||||
{ route: NotFound
|
{ route: NotFound
|
||||||
, count: Counter.init
|
, count: Counter.init
|
||||||
, bistate: BlogIndex.init }
|
, bistate: BlogIndex.init
|
||||||
|
, bestate: BlogEntry.init }
|
||||||
|
|
||||||
update :: Action -> State -> EffModel State Action (ajax :: AJAX, dom :: DOM)
|
update :: Action -> State -> EffModel State Action (ajax :: AJAX, dom :: DOM)
|
||||||
update (PageView route) state = routeEffects route $ state { route = route }
|
update (PageView route) state = routeEffects route $ state { route = route }
|
||||||
update (BIChild action) state = BlogIndex.update action state.bistate
|
update (BIChild action) state = BlogIndex.update action state.bistate
|
||||||
# mapState (state { bistate = _ })
|
# mapState (state { bistate = _ })
|
||||||
# mapEffects BIChild
|
# mapEffects BIChild
|
||||||
|
update (BEChild action) state = BlogEntry.update action state.bestate
|
||||||
|
# mapState (state { bestate = _ })
|
||||||
|
# mapEffects BEChild
|
||||||
update (Child action) state = noEffects $ state { count = Counter.update action state.count }
|
update (Child action) state = noEffects $ state { count = Counter.update action state.count }
|
||||||
|
|
||||||
routeEffects :: Route -> State -> EffModel State Action (dom :: DOM, ajax :: AJAX)
|
routeEffects :: Route -> State -> EffModel State Action (dom :: DOM, ajax :: AJAX)
|
||||||
routeEffects BlogIndex state = { state: state
|
routeEffects BlogIndex state = { state: state
|
||||||
, effects: [ pure BlogIndex.RequestPosts ] } # mapEffects BIChild
|
, effects: [ pure BlogIndex.RequestPosts ] } # mapEffects BIChild
|
||||||
|
routeEffects (BlogPost page) state = { state: state { bestate = BlogEntry.init { name = page } }
|
||||||
|
, effects: [ pure BlogEntry.RequestPost ] } # mapEffects BEChild
|
||||||
routeEffects _ state = noEffects $ state
|
routeEffects _ state = noEffects $ state
|
||||||
|
|
||||||
view :: State -> Html Action
|
view :: State -> Html Action
|
||||||
|
@ -71,4 +81,5 @@ page NotFound _ = h1 [] [ text "not found" ]
|
||||||
page Home state = map Child $ Counter.view state.count
|
page Home state = map Child $ Counter.view state.count
|
||||||
page Resume state = h1 [] [ text "Christine Dodrill" ]
|
page Resume state = h1 [] [ text "Christine Dodrill" ]
|
||||||
page BlogIndex state = map BIChild $ BlogIndex.view state.bistate
|
page BlogIndex state = map BIChild $ BlogIndex.view state.bistate
|
||||||
|
page (BlogPost _) state = map BEChild $ BlogEntry.view state.bestate
|
||||||
page _ _ = h1 [] [ text "not implemented yet" ]
|
page _ _ = h1 [] [ text "not implemented yet" ]
|
||||||
|
|
|
@ -7,7 +7,7 @@ import Control.Monad.Eff (Eff)
|
||||||
import DOM (DOM)
|
import DOM (DOM)
|
||||||
import Network.HTTP.Affjax (AJAX)
|
import Network.HTTP.Affjax (AJAX)
|
||||||
import Prelude (bind, pure)
|
import Prelude (bind, pure)
|
||||||
import Pux (App, Config, CoreEffects, fromSimple, renderToDOM, start)
|
import Pux (App, Config, CoreEffects, renderToDOM, start)
|
||||||
import Pux.Devtool (Action, start) as Pux.Devtool
|
import Pux.Devtool (Action, start) as Pux.Devtool
|
||||||
import Pux.Router (sampleUrl)
|
import Pux.Router (sampleUrl)
|
||||||
import Signal ((~>))
|
import Signal ((~>))
|
||||||
|
|
|
@ -19,3 +19,5 @@ match url = fromMaybe NotFound $ router url $
|
||||||
Home <$ end
|
Home <$ end
|
||||||
<|>
|
<|>
|
||||||
BlogIndex <$ lit "blog" <* end
|
BlogIndex <$ lit "blog" <* end
|
||||||
|
<|>
|
||||||
|
BlogPost <$> (lit "blog" *> str) <* end
|
||||||
|
|
Loading…
Reference in New Issue