From a6fc81e48182d931928a9d5d553d4689f431086f Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Sun, 6 Mar 2016 08:58:11 -0800 Subject: [PATCH] Use Elm Architecture in stages/8 --- stages/8/src/{ => Component}/ElmHub.elm | 69 +++++++++++-------------- stages/8/src/Component/SearchResult.elm | 57 ++++++++++++++++++++ stages/8/src/Main.elm | 2 +- 3 files changed, 89 insertions(+), 39 deletions(-) rename stages/8/src/{ => Component}/ElmHub.elm (65%) create mode 100644 stages/8/src/Component/SearchResult.elm diff --git a/stages/8/src/ElmHub.elm b/stages/8/src/Component/ElmHub.elm similarity index 65% rename from stages/8/src/ElmHub.elm rename to stages/8/src/Component/ElmHub.elm index 377ae38..edc0207 100644 --- a/stages/8/src/ElmHub.elm +++ b/stages/8/src/Component/ElmHub.elm @@ -1,15 +1,15 @@ -module ElmHub (..) where +module Component.ElmHub (..) where import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) -import StartApp import Http import Task exposing (Task) import Effects exposing (Effects) import Json.Decode exposing (Decoder, (:=)) import Json.Encode import Signal exposing (Address) +import Component.SearchResult exposing (ResultId) searchFeed : String -> Task x Action @@ -28,37 +28,27 @@ searchFeed query = Task.onError task (\_ -> Task.succeed (SetResults [])) -responseDecoder : Decoder (List SearchResult) +responseDecoder : Decoder (List Component.SearchResult.Model) responseDecoder = "items" := Json.Decode.list searchResultDecoder -searchResultDecoder : Decoder SearchResult +searchResultDecoder : Decoder Component.SearchResult.Model searchResultDecoder = - Json.Decode.object3 - SearchResult + Json.Decode.object4 + Component.SearchResult.Model ("id" := Json.Decode.int) ("full_name" := Json.Decode.string) ("stargazers_count" := Json.Decode.int) + (Json.Decode.succeed True) type alias Model = { 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 = { query = "tutorial" @@ -91,28 +81,18 @@ defaultValue str = property "defaultValue" (Json.Encode.string str) -viewSearchResult : Address Action -> SearchResult -> Html +viewSearchResult : Address Action -> Component.SearchResult.Model -> Html viewSearchResult address result = - li - [] - [ span [ class "star-count" ] [ text (toString result.stars) ] - , 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" ] - ] + Component.SearchResult.view + (Signal.forwardTo address (UpdateSearchResult result.id)) + result type Action = Search | SetQuery String - | HideById ResultId - | SetResults (List SearchResult) + | SetResults (List Component.SearchResult.Model) + | UpdateSearchResult ResultId Component.SearchResult.Action update : Action -> Model -> ( Model, Effects Action ) @@ -131,13 +111,26 @@ update action model = in ( newModel, Effects.none ) - HideById idToHide -> + UpdateSearchResult id childAction -> 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 - |> List.filter (\{ id } -> id /= idToHide) + |> List.map updateResult + |> List.unzip newModel = { model | results = newResults } in - ( newModel, Effects.none ) + ( newModel, Effects.batch effects ) diff --git a/stages/8/src/Component/SearchResult.elm b/stages/8/src/Component/SearchResult.elm new file mode 100644 index 0000000..b87e634 --- /dev/null +++ b/stages/8/src/Component/SearchResult.elm @@ -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" ] + ] diff --git a/stages/8/src/Main.elm b/stages/8/src/Main.elm index fa4bada..5b8e88e 100644 --- a/stages/8/src/Main.elm +++ b/stages/8/src/Main.elm @@ -1,7 +1,7 @@ module Main (..) where import StartApp -import ElmHub exposing (..) +import Component.ElmHub exposing (..) import Effects exposing (Effects) import Task exposing (Task) import Html exposing (Html)