module ElmHub (..) where import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) import Http import Task exposing (Task) import Effects exposing (Effects) import Json.Decode exposing (Decoder, (:=)) import Json.Encode import Signal exposing (Address) searchFeed : Address String -> String -> Task x Action searchFeed address query = let -- See https://developer.github.com/v3/search/#example for how to customize! url = "https://api.github.com/search/repositories?q=" ++ query ++ "+language:elm&sort=stars&order=desc" -- These only talk to JavaScript ports now. They don't -- actually do any actions themselves. task = Signal.send address query |> Task.map (\_ -> DoNothing) in Task.onError task (\_ -> Task.succeed DoNothing) responseDecoder : Decoder (List SearchResult) responseDecoder = "items" := Json.Decode.list searchResultDecoder searchResultDecoder : Decoder SearchResult searchResultDecoder = Json.Decode.object3 SearchResult ("id" := Json.Decode.int) ("full_name" := Json.Decode.string) ("stargazers_count" := Json.Decode.int) type alias Model = { query : String , results : List SearchResult } type alias SearchResult = { id : ResultId , name : String , stars : Int } type alias ResultId = Int initialModel : Model initialModel = { query = "tutorial" , results = [] } view : Address Action -> Model -> Html view address model = div [ class "content" ] [ header [] [ h1 [] [ text "ElmHub" ] , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] ] , input [ class "search-query", onInput address SetQuery, defaultValue model.query ] [] , button [ class "search-button", onClick address Search ] [ text "Search" ] , ul [ class "results" ] (List.map (viewSearchResult address) model.results) ] onInput address wrap = on "input" targetValue (\val -> Signal.message address (wrap val)) defaultValue str = property "defaultValue" (Json.Encode.string str) viewSearchResult : Address Action -> SearchResult -> Html viewSearchResult address result = li [] [ span [ class "star-count" ] [ text (toString result.stars) ] , a [ href ("https://github.com/" ++ result.name), target "_blank" ] [ text result.name ] , button [ class "hide-result", onClick address (DeleteById result.id) ] [ text "X" ] ] type Action = Search | SetQuery String | DeleteById ResultId | SetResults (List SearchResult) | DoNothing update : Address String -> Action -> Model -> ( Model, Effects Action ) update searchAddress action model = case action of Search -> ( model, Effects.task (searchFeed searchAddress model.query) ) SetQuery query -> ( { model | query = query }, Effects.none ) SetResults results -> let newModel = { model | results = results } in ( newModel, Effects.none ) DeleteById idToHide -> let newResults = model.results |> List.filter (\{ id } -> id /= idToHide) newModel = { model | results = newResults } in ( newModel, Effects.none ) DoNothing -> ( model, Effects.none )