Use Elm Architecture in stages/8
This commit is contained in:
@@ -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 )
|
||||||
57
stages/8/src/Component/SearchResult.elm
Normal file
57
stages/8/src/Component/SearchResult.elm
Normal 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" ]
|
||||||
|
]
|
||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user