Use Elm Architecture in stages/8

This commit is contained in:
Richard Feldman
2016-03-06 08:58:11 -08:00
parent 72e5d3ac44
commit a6fc81e481
3 changed files with 89 additions and 39 deletions

View File

@@ -1,15 +1,15 @@
module ElmHub (..) where module Component.ElmHub (..) where
import Html exposing (..) import Html exposing (..)
import Html.Attributes exposing (..) import Html.Attributes exposing (..)
import Html.Events exposing (..) import Html.Events exposing (..)
import StartApp
import Http import Http
import Task exposing (Task) import Task exposing (Task)
import Effects exposing (Effects) import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=)) import Json.Decode exposing (Decoder, (:=))
import Json.Encode import Json.Encode
import Signal exposing (Address) import Signal exposing (Address)
import Component.SearchResult exposing (ResultId)
searchFeed : String -> Task x Action searchFeed : String -> Task x Action
@@ -28,37 +28,27 @@ searchFeed query =
Task.onError task (\_ -> Task.succeed (SetResults [])) Task.onError task (\_ -> Task.succeed (SetResults []))
responseDecoder : Decoder (List SearchResult) responseDecoder : Decoder (List Component.SearchResult.Model)
responseDecoder = responseDecoder =
"items" := Json.Decode.list searchResultDecoder "items" := Json.Decode.list searchResultDecoder
searchResultDecoder : Decoder SearchResult searchResultDecoder : Decoder Component.SearchResult.Model
searchResultDecoder = searchResultDecoder =
Json.Decode.object3 Json.Decode.object4
SearchResult Component.SearchResult.Model
("id" := Json.Decode.int) ("id" := Json.Decode.int)
("full_name" := Json.Decode.string) ("full_name" := Json.Decode.string)
("stargazers_count" := Json.Decode.int) ("stargazers_count" := Json.Decode.int)
(Json.Decode.succeed True)
type alias Model = type alias Model =
{ query : String { query : String
, results : List SearchResult , results : List Component.SearchResult.Model
} }
type alias SearchResult =
{ id : ResultId
, name : String
, stars : Int
}
type alias ResultId =
Int
initialModel : Model initialModel : Model
initialModel = initialModel =
{ query = "tutorial" { query = "tutorial"
@@ -91,28 +81,18 @@ defaultValue str =
property "defaultValue" (Json.Encode.string str) property "defaultValue" (Json.Encode.string str)
viewSearchResult : Address Action -> SearchResult -> Html viewSearchResult : Address Action -> Component.SearchResult.Model -> Html
viewSearchResult address result = viewSearchResult address result =
li Component.SearchResult.view
[] (Signal.forwardTo address (UpdateSearchResult result.id))
[ span [ class "star-count" ] [ text (toString result.stars) ] result
, a
[ href ("https://github.com/" ++ result.name)
, class "result-name"
, target "_blank"
]
[ text result.name ]
, button
[ class "hide-result", onClick address (HideById result.id) ]
[ text "X" ]
]
type Action type Action
= Search = Search
| SetQuery String | SetQuery String
| HideById ResultId | SetResults (List Component.SearchResult.Model)
| SetResults (List SearchResult) | UpdateSearchResult ResultId Component.SearchResult.Action
update : Action -> Model -> ( Model, Effects Action ) update : Action -> Model -> ( Model, Effects Action )
@@ -131,13 +111,26 @@ update action model =
in in
( newModel, Effects.none ) ( newModel, Effects.none )
HideById idToHide -> UpdateSearchResult id childAction ->
let let
newResults = updateResult childModel =
if childModel.id == id then
let
( newChildModel, childEffects ) =
Component.SearchResult.update childAction childModel
in
( newChildModel
, Effects.map (UpdateSearchResult id) childEffects
)
else
( childModel, Effects.none )
( newResults, effects ) =
model.results model.results
|> List.filter (\{ id } -> id /= idToHide) |> List.map updateResult
|> List.unzip
newModel = newModel =
{ model | results = newResults } { model | results = newResults }
in in
( newModel, Effects.none ) ( newModel, Effects.batch effects )

View File

@@ -0,0 +1,57 @@
module Component.SearchResult (..) where
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Signal exposing (Address)
import Effects exposing (Effects)
type alias Model =
{ id : Int
, name : String
, stars : Int
, expanded : Bool
}
type alias ResultId =
Int
type Action
= Expand
| Collapse
update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
Expand ->
( { model | expanded = True }, Effects.none )
Collapse ->
( { model | expanded = False }, Effects.none )
view : Address Action -> Model -> Html
view address model =
li
[]
<| if model.expanded then
[ span [ class "star-count" ] [ text (toString model.stars) ]
, a
[ href ("https://github.com/" ++ model.name)
, class "result-name"
, target "_blank"
]
[ text model.name ]
, button
[ class "hide-result", onClick address Collapse ]
[ text "X" ]
]
else
[ button
[ class "expand-result", onClick address Expand ]
[ text "Show" ]
]

View File

@@ -1,7 +1,7 @@
module Main (..) where module Main (..) where
import StartApp import StartApp
import ElmHub exposing (..) import Component.ElmHub exposing (..)
import Effects exposing (Effects) import Effects exposing (Effects)
import Task exposing (Task) import Task exposing (Task)
import Html exposing (Html) import Html exposing (Html)