Last active
May 14, 2016 20:42
-
-
Save turboMaCk/98d2e40231c4033deca29c148d4684cc to your computer and use it in GitHub Desktop.
Elm 0.17: Views + main + update
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Repos exposing (main) | |
import List | |
import Html exposing (..) | |
import Html.App | |
import Html.Attributes exposing (..) | |
import Html.Events as Events | |
import Http | |
import Json.Decode as Json exposing ((:=)) | |
import Task exposing (..) | |
-- Model | |
type alias Repo = | |
{ id : Int | |
, name : String | |
, htmlUrl : String | |
-- , description : String | |
, sshUrl : String | |
-- , language : String | |
, stargazersCount: Int | |
, avatarUrl: String } | |
type alias Model = | |
{ userName : String | |
, resultsFor : String | |
, repos : List Repo | |
, isLoading : Bool | |
, alert : String | |
, selected : Int | |
, sortBy : SortBy } | |
type SortBy = Name | |
| Stars | |
initialModel : Model | |
initialModel = | |
{ userName = "turbomack" | |
, resultsFor = "turbomack" | |
, repos = [] | |
, isLoading = True | |
, alert = "" | |
, selected = -1 | |
, sortBy = Name } | |
isSelected : Model -> Repo -> Bool | |
isSelected model repo = | |
if model.selected == repo.id then True else False | |
sort : SortBy -> List Repo -> List Repo | |
sort sortBy repos = | |
case sortBy of | |
Name -> | |
repos |> List.sortBy .name | |
Stars -> | |
repos |> List.sortBy .stargazersCount |> List.reverse | |
reposDecoder : Json.Decoder (List Repo) | |
reposDecoder = | |
Json.list repoDecoder | |
repoDecoder : Json.Decoder Repo | |
repoDecoder = | |
Json.object6 | |
Repo | |
("id" := Json.int) | |
("name" := Json.string) | |
("html_url" := Json.string) | |
-- ("description" := Json.string) | |
("ssh_url" := Json.string) | |
-- ("language" := Json.string) | |
("stargazers_count" := Json.int) | |
(Json.at ["owner", "avatar_url"] Json.string) | |
getUrl : String -> String | |
getUrl name = | |
"https://api.github.com/users/" ++ name ++ "/repos" | |
-- fetchData : String -> Task.Task a (Result Http.Error (List Repo)) | |
-- fetchData name = | |
-- Http.get reposDecoder (getUrl name) | |
-- |> Task.toResult | |
httpErrorToString : String -> Http.Error -> String | |
httpErrorToString name err = | |
case err of | |
Http.Timeout -> "Timeout" | |
Http.NetworkError -> "Connection problem" | |
Http.UnexpectedPayload _ -> "That's weird. Something is broken!" | |
Http.BadResponse status msg -> | |
case status of | |
404 -> name ++ "not found:(" | |
_ -> msg | |
-- httpResultToAction : String -> Result Http.Error (List Repo) -> Action | |
-- httpResultToAction name result = | |
-- case result of | |
-- Ok repos -> | |
-- FetchDone repos | |
-- Err err -> | |
-- Error (httpErrorToString name err) | |
-- fetchDataAsEffects : String -> Effects Action | |
-- fetchDataAsEffects name = | |
-- fetchData name | |
-- |> Task.map (httpResultToAction name) | |
-- |> Effects.task | |
-- Init | |
init : ( Model, Cmd Msg ) | |
init = | |
( initialModel | |
, Cmd.none ) | |
-- , fetchDataAsEffects initialModel.userName ) | |
-- Actions | |
type Msg = NoOp | |
| FetchData String | |
| FetchDone (List Repo) | |
| Error String | |
| NameChanged String | |
| SelectRepo Repo | |
| ChangeSort SortBy | |
update : Msg -> Model -> (Model, Cmd Msg) | |
update action model = | |
case action of | |
NoOp -> | |
( model, Cmd.none ) | |
FetchData name -> | |
( { model | |
| isLoading = True | |
, resultsFor = model.userName } | |
, Cmd.none ) | |
-- , fetchDataAsEffects model.userName ) | |
FetchDone results -> | |
( { model | |
| repos = results | |
, isLoading = False | |
, alert = "" } | |
, Cmd.none ) | |
Error msg -> | |
( { model | |
| repos = [] | |
, isLoading = False | |
, alert = msg } | |
, Cmd.none ) | |
NameChanged name -> | |
( { model | |
| userName = name } | |
, Cmd.none ) | |
SelectRepo repo -> | |
let | |
value = | |
if repo.id == model.selected then -1 else repo.id | |
in | |
( { model | |
| selected = value } | |
, Cmd.none ) | |
ChangeSort attr -> | |
( { model | |
| sortBy = attr } | |
, Cmd.none ) | |
-- View | |
-- onInput : Signal.Address Action -> (String -> Action) -> Attribute | |
-- onInput address f = | |
-- Events.on "input" Events.targetValue (\v -> Signal.message address (f v)) | |
-- oSubmit address value = | |
-- Events.onWithOptions "submit" | |
-- { stopPropagation = True, preventDefault = True } | |
-- Json.value (\_ -> Signal.message address (FetchData value)) | |
headerView : Model -> Html Msg | |
headerView model = | |
header | |
[ class "header" ] | |
[ img | |
[ src "assets/octocat.png" | |
, class "octo-cat" ] [] | |
, h1 | |
[ class "headline" ] | |
[ text "Repos" ] | |
, Html.form | |
-- [ onSubmit address model.userName | |
[ class "search-form" ] | |
[ span | |
[ class "hint" ] | |
[ text "github.com/" ] | |
, input | |
[ value model.userName | |
-- , onInput address NameChanged | |
, class "search-field" ] [] | |
, button | |
[ type' "submit" | |
, class "submit-btn" ] | |
[ text "Go" ] ]] | |
sortView : Model -> Html Msg | |
sortView model = | |
let | |
isActive attr = | |
model.sortBy == attr | |
classNames attr = | |
if isActive attr then "active" else "inactive" | |
in | |
div | |
[ class "sort-filter" ] | |
[ button | |
[ class (classNames Name) | |
-- , Events.onClick address (ChangeSort Name) ] | |
] | |
[ text "name" ] | |
, button | |
[ class (classNames Stars) | |
-- , Events.onClick address (ChangeSort Stars) ] | |
] | |
[ text "stars" ]] | |
loadingView : Html Msg | |
loadingView = | |
div [] | |
[ text "loading..." ] | |
repoView : Model -> Repo -> Html Msg | |
repoView model repo = | |
let | |
classNames = | |
if isSelected model repo then "repo selected" else "repo" | |
cloneValue = | |
"git clone " ++ repo.sshUrl | |
in | |
li | |
[ class classNames ] | |
[ div | |
[ class "repo-main" | |
-- , Events.onClick address (SelectRepo repo)] | |
] | |
[ img | |
[ src repo.avatarUrl | |
, class "avatar" ] [] | |
, div | |
[ class "repo-info" ] | |
[ span | |
[ class "stars-count" ] | |
[ text ("stars: " ++ (toString repo.stargazersCount)) ] | |
, h2 | |
[ class "repo-name" ] | |
[ a | |
[ href repo.htmlUrl | |
, target "_blank" ] | |
[ text repo.name ]]]] | |
, div | |
[ class "repo-details" ] | |
[ div | |
[ class "clone" ] | |
[ label | |
[ class "clone-label"] | |
[ text "clone:" | |
, input | |
[ class "clone-input" | |
, disabled True | |
, value cloneValue ] []]]]] | |
reposListView : Model -> Html Msg | |
reposListView model = | |
ul | |
[ class "repos-list" ] | |
( model.repos |> sort model.sortBy |> List.map (repoView model) ) | |
alertView : String -> Html Msg | |
alertView msg = | |
div [ class "error alert" ] [ text msg ] | |
view : Model -> Html Msg | |
view model = | |
let | |
content = | |
if model.isLoading then loadingView else reposListView model | |
in | |
div [] | |
[ a | |
[ href "https://github.com/turboMaCk/elm-github-repos" | |
, class "fork-link" ] | |
[ text "Fork me on Github" ] | |
, div | |
[ class "app-container" ] | |
[ headerView model | |
, sortView model | |
, div | |
[ class "results-for" ] | |
[ text ("Results for `" ++ model.resultsFor ++ "`:")] | |
, alertView model.alert | |
, content ]] | |
main : Program Never | |
main = | |
Html.App.program | |
{ init = init | |
, update = update | |
, view = view | |
, subscriptions = \_ -> Sub.none } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment