Update a ton of things

This commit is contained in:
Richard Feldman
2016-06-24 17:40:54 -07:00
parent 908ca61c77
commit c8e9a117f5
56 changed files with 1023 additions and 1466 deletions

View File

@@ -10,7 +10,7 @@ import Html.App
import Auth
import Http
import Task exposing (Task)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
main : Program Never

View File

@@ -5,7 +5,7 @@ Getting Started
1. Install [Node.js](http://nodejs.org) 4.0.0 or higher
2. Add an [editor plugin](http://elm-lang.org/install#syntax-highlighting) for your editor of choice.
2. Add a plugin for your editor of choice: [Atom](https://atom.io/packages/language-elm), [Sublime Text](https://packagecontrol.io/packages/Elm%20Language%20Support), [VS Code](https://github.com/sbrink/vscode-elm), [Light Table](https://github.com/rundis/elm-light), [Vim](https://github.com/lambdatoast/elm.vim), [Emacs](https://github.com/jcollard/elm-mode), [Brackets](https://github.com/lepinay/elm-brackets)
3. Not required, but **highly** recommended: [install elm-format](https://github.com/avh4/elm-format#installation-) and integrate it into your editor so that it runs on save.

View File

@@ -16,7 +16,7 @@ model =
view model =
div [ class "content" ]
[ header []
[ -- TODO add the equivalent of <h1>ElmHub</h1> right before the tagline
[ -- TODO add the equivalent of <h1>ElmHub</h1> right before this <span>
span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
]
, ul [ class "results" ]

View File

@@ -4,19 +4,19 @@ Part 1
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```
## References
* [html-to-elm](http://mbylstra.github.io/html-to-elm/) - paste in HTML, get elm-html code
* [elm-html documentation](http://package.elm-lang.org/packages/evancz/elm-html/4.0.2/)
* [record syntax](http://elm-lang.org/docs/syntax#records) (e.g. `{ foo = 1, bar = 2`)
* [record syntax](http://elm-lang.org/docs/syntax#records) (e.g. `{ foo = 1, bar = 2 }`)

View File

@@ -1,36 +1,27 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Html.Lazy exposing (..)
import Http
import Auth
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Encode
import Signal exposing (Address)
import Json.Decode exposing (Decoder)
import Dict exposing (Dict)
import SearchResult
searchFeed : String -> Task x Action
searchFeed : String -> Cmd Msg
searchFeed query =
let
-- See https://developer.github.com/v3/search/#example for how to customize!
url =
"https://api.github.com/search/repositories?access_token="
++ Auth.token
++ "&q="
++ query
++ "+language:elm&sort=stars&order=desc"
task =
Http.get responseDecoder url
|> Task.map SetResults
in
Task.onError task (\_ -> Task.succeed (SetResults []))
Task.perform HandleSearchError HandleSearchResponse (Http.get responseDecoder url)
responseDecoder : Decoder (List SearchResult.Model)
@@ -52,54 +43,44 @@ initialModel =
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
view : Model -> Html Msg
view 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" ]
(viewSearchResults address model.results)
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, ul [ class "results" ] (viewSearchResults model.results)
]
viewSearchResults : Address Action -> Dict SearchResult.ResultId SearchResult.Model -> List Html
viewSearchResults address results =
viewSearchResults : Dict SearchResult.ResultId SearchResult.Model -> List (Html a)
viewSearchResults results =
results
|> Dict.values
|> List.sortBy (.stars >> negate)
|> List.map (\_ -> div [] [ text "TODO replace this line with view logic from SearchResult" ])
onInput address wrap =
on "input" targetValue (\val -> Signal.message address (wrap val))
defaultValue str =
property "defaultValue" (Json.Encode.string str)
type Action
type Msg
= Search
| SetQuery String
| DeleteById SearchResult.ResultId
| SetResults (List SearchResult.Model)
| HandleSearchResponse (List SearchResult.Model)
| HandleSearchError Http.Error
update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search ->
( model, Effects.task (searchFeed model.query) )
( model, searchFeed model.query )
SetQuery query ->
( { model | query = query }, Effects.none )
( { model | query = query }, Cmd.none )
SetResults results ->
let
@@ -109,11 +90,11 @@ update action model =
|> List.map (\result -> ( result.id, result ))
|> Dict.fromList
in
( { model | results = resultsById }, Effects.none )
( { model | results = resultsById }, Cmd.none )
DeleteById id ->
let
newModel =
{ model | results = Dict.remove id model.results }
in
( newModel, Effects.none )
( newModel, Cmd.none )

View File

@@ -1,27 +1,13 @@
module Main (..) where
module Main exposing (..)
import StartApp
import ElmHub exposing (..)
import Effects exposing (Effects)
import Task exposing (Task)
import Html exposing (Html)
main : Signal Html
main : Program Never
main =
app.html
app : StartApp.App Model
app =
StartApp.start
Html.App.program
{ view = view
, update = update
, init = ( initialModel, Effects.task (searchFeed initialModel.query) )
, init = ( initialModel, searchFeed initialModel.query )
, inputs = []
}
port tasks : Signal (Task Effects.Never ())
port tasks =
app.tasks

View File

@@ -4,14 +4,14 @@ Part 10
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```

View File

@@ -1,12 +1,9 @@
module SearchResult (..) where
module SearchResult exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Events exposing (..)
import Json.Decode exposing (Decoder, (:=))
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
import Signal exposing (Address)
import Dict exposing (Dict)
type alias ResultId =
@@ -28,10 +25,9 @@ decoder =
|> required "stargazers_count" Json.Decode.int
view : Address a -> Model -> Html
view address result =
li
[]
view : Model -> Html a
view result =
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a
[ href ("https://github.com/" ++ result.name)

View File

@@ -10,11 +10,9 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -9,13 +9,10 @@
],
"exposed-modules": [],
"dependencies": {
"deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0",
"laszlopandy/elm-console": "1.0.3 <= v < 2.0.0"
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -1,4 +1,4 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Html exposing (..)
import Html.Attributes exposing (..)
@@ -6,30 +6,23 @@ import Html.Events exposing (..)
import Http
import Auth
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Encode
import Signal exposing (Address)
import Dict exposing (Dict)
import SearchResult
searchFeed : String -> Task x Action
searchFeed : String -> Cmd Msg
searchFeed query =
let
-- See https://developer.github.com/v3/search/#example for how to customize!
url =
"https://api.github.com/search/repositories?access_token="
++ Auth.token
++ "&q="
++ query
++ "+language:elm&sort=stars&order=desc"
task =
Http.get responseDecoder url
|> Task.map SetResults
in
Task.onError task (\_ -> Task.succeed (SetResults []))
Task.perform HandleSearchError HandleSearchResponse (Http.get responseDecoder url)
responseDecoder : Decoder (List SearchResult.Model)
@@ -50,25 +43,21 @@ initialModel =
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
view : Model -> Html Msg
view 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" ]
(viewSearchResults address model.results)
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, ul [ class "results" ] (viewSearchResults model.results)
]
viewSearchResults : Address Action -> Dict SearchResult.ResultId SearchResult.Model -> List Html
viewSearchResults address results =
viewSearchResults : Dict SearchResult.ResultId SearchResult.Model -> List (Html a)
viewSearchResults results =
results
|> Dict.values
|> List.sortBy (.stars >> negate)
@@ -83,29 +72,21 @@ filterResults results =
results
onInput address wrap =
on "input" targetValue (\val -> Signal.message address (wrap val))
defaultValue str =
property "defaultValue" (Json.Encode.string str)
type Action
type Msg
= Search
| SetQuery String
| DeleteById SearchResult.ResultId
| SetResults (List SearchResult.Model)
update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search ->
( model, Effects.task (searchFeed model.query) )
( model, searchFeed model.query )
SetQuery query ->
( { model | query = query }, Effects.none )
( { model | query = query }, Cmd.none )
SetResults results ->
let
@@ -115,11 +96,11 @@ update action model =
|> List.map (\result -> ( result.id, result ))
|> Dict.fromList
in
( { model | results = resultsById }, Effects.none )
( { model | results = resultsById }, Cmd.none )
DeleteById id ->
let
newModel =
{ model | results = Dict.remove id model.results }
in
( newModel, Effects.none )
( newModel, Cmd.none )

View File

@@ -1,27 +1,13 @@
module Main (..) where
module Main exposing (..)
import StartApp
import ElmHub exposing (..)
import Effects exposing (Effects)
import Task exposing (Task)
import Html exposing (Html)
main : Signal Html
main : Program Never
main =
app.html
app : StartApp.App Model
app =
StartApp.start
Html.App.program
{ view = view
, update = update
, init = ( initialModel, Effects.task (searchFeed initialModel.query) )
, init = ( initialModel, searchFeed initialModel.query )
, inputs = []
}
port tasks : Signal (Task Effects.Never ())
port tasks =
app.tasks

View File

@@ -4,14 +4,14 @@ Part 11
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```

View File

@@ -1,10 +1,9 @@
module SearchResult (..) where
module SearchResult exposing (..)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Json.Decode exposing (Decoder, (:=))
import Signal exposing (Address)
import Json.Decode exposing (Decoder)
import Dict exposing (Dict)
@@ -21,8 +20,7 @@ type alias Model =
decoder : Decoder Model
decoder =
Json.Decode.object3
Model
Json.Decode.object3 Model
("id" := Json.Decode.int)
("full_name" := Json.Decode.string)
("stargazers_count" := Json.Decode.int)
@@ -30,21 +28,18 @@ decoder =
view : Address a -> (Int -> a) -> Model -> Html
view address delete result =
li
[]
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a
[ href
("https://github.com/"
++ (Debug.log
"TODO we should not see this when typing in the search box!"
++ (Debug.log "TODO we should not see this when typing in the search box!"
result.name
)
)
, target "_blank"
]
[ text result.name ]
, button
[ class "hide-result", onClick address (delete result.id) ]
, button [ class "hide-result", onClick (delete result.id) ]
[ text "X" ]
]

View File

@@ -10,11 +10,9 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -9,13 +9,10 @@
],
"exposed-modules": [],
"dependencies": {
"deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0",
"laszlopandy/elm-console": "1.0.3 <= v < 2.0.0"
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -1,4 +1,4 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Html exposing (..)
import Html.Attributes exposing (..)
@@ -7,15 +7,13 @@ import Html.Lazy exposing (..)
import Http
import Auth
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Encode
import Signal exposing (Address)
import Dict exposing (Dict)
import SearchResult exposing (ResultId)
searchFeed : String -> Task x Action
searchFeed : String -> Task x Msg
searchFeed query =
let
-- See https://developer.github.com/v3/search/#example for how to customize!
@@ -51,61 +49,48 @@ initialModel =
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
view : Model -> Html Msg
view 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" ]
(viewSearchResults address model.results)
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, ul [ class "results" ] (viewSearchResults model.results)
]
viewSearchResults : Address Action -> Dict ResultId SearchResult.Model -> List Html
viewSearchResults address results =
viewSearchResults : Dict ResultId SearchResult.Model -> List Html
viewSearchResults results =
results
|> Dict.values
|> List.sortBy (.stars >> negate)
|> List.map (viewSearchResult address)
viewSearchResult : Address Action -> SearchResult.Model -> Html
viewSearchResult address result =
SearchResult.view
(Signal.forwardTo address (UpdateSearchResult result.id))
viewSearchResult : SearchResult.Model -> Html Msg
viewSearchResult result =
SearchResult.view (Signal.forwardTo address (UpdateSearchResult result.id))
result
onInput address wrap =
on "input" targetValue (\val -> Signal.message address (wrap val))
defaultValue str =
property "defaultValue" (Json.Encode.string str)
type Action
type Msg
= Search
| SetQuery String
| SetResults (List SearchResult.Model)
| UpdateSearchResult ResultId SearchResult.Action
| UpdateSearchResult ResultId SearchResult.Msg
update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search ->
( model, Effects.task (searchFeed model.query) )
( model, searchFeed model.query )
SetQuery query ->
( { model | query = query }, Effects.none )
( { model | query = query }, Cmd.none )
SetResults results ->
let
@@ -115,18 +100,18 @@ update action model =
|> List.map (\result -> ( result.id, result ))
|> Dict.fromList
in
( { model | results = resultsById }, Effects.none )
( { model | results = resultsById }, Cmd.none )
UpdateSearchResult id childAction ->
UpdateSearchResult id childMsg ->
let
updated =
model.results
|> Dict.get id
|> Maybe.map (SearchResult.update childAction)
|> Maybe.map (SearchResult.update childMsg)
in
case updated of
Nothing ->
( model, Effects.none )
( model, Cmd.none )
Just ( newChildModel, childEffects ) ->
let

View File

@@ -1,27 +1,13 @@
module Main (..) where
module Main exposing (..)
import StartApp
import ElmHub exposing (..)
import Effects exposing (Effects)
import Task exposing (Task)
import Html exposing (Html)
main : Signal Html
main : Program Never
main =
app.html
app : StartApp.App Model
app =
StartApp.start
Html.App.program
{ view = view
, update = update
, init = ( initialModel, Effects.task (searchFeed initialModel.query) )
, init = ( initialModel, searchFeed initialModel.query )
, inputs = []
}
port tasks : Signal (Task Effects.Never ())
port tasks =
app.tasks

View File

@@ -4,16 +4,16 @@ Part 12
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```
## References

View File

@@ -1,11 +1,9 @@
module SearchResult (..) where
module SearchResult exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Signal exposing (Address)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
@@ -21,7 +19,7 @@ type alias ResultId =
Int
type Action
type Msg
= Expand
| Collapse
@@ -35,20 +33,18 @@ decoder =
|> hardcoded True
update : Action -> Model -> ( Model, Effects Action )
update action model =
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
-- TODO implement Expand and Collapse logic
( model, Effects.none )
( model, Cmd.none )
view : Address Action -> Model -> Html
view address model =
li
[]
<| if model.expanded then
view : Model -> Html Msg
view model =
li [] <|
if model.expanded then
[ span [ class "star-count" ] [ text (toString model.stars) ]
, a
[ href ("https://github.com/" ++ model.name), target "_blank" ]
, a [ href ("https://github.com/" ++ model.name), target "_blank" ]
[ text model.name ]
, button
-- TODO when the user clicks, send a Collapse action

View File

@@ -10,11 +10,9 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -9,13 +9,10 @@
],
"exposed-modules": [],
"dependencies": {
"deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0",
"laszlopandy/elm-console": "1.0.3 <= v < 2.0.0"
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -1,4 +1,4 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Html exposing (..)
import Html.Attributes exposing (..)
@@ -7,15 +7,13 @@ import Html.Lazy exposing (..)
import Http
import Auth
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Encode
import Signal exposing (Address)
import Dict exposing (Dict)
import SearchResult exposing (ResultId)
searchFeed : String -> Task x Action
searchFeed : String -> Task x Msg
searchFeed query =
let
-- See https://developer.github.com/v3/search/#example for how to customize!
@@ -51,25 +49,21 @@ initialModel =
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
view : Model -> Html Msg
view 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" ]
(viewSearchResults address model.results)
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, ul [ class "results" ] (viewSearchResults model.results)
]
viewSearchResults : Address Action -> Dict ResultId SearchResult.Model -> List Html
viewSearchResults address results =
viewSearchResults : Dict ResultId SearchResult.Model -> List Html
viewSearchResults results =
results
|> Dict.values
|> List.sortBy (.stars >> negate)
@@ -77,35 +71,26 @@ viewSearchResults address results =
viewSearchResult : Address Action -> SearchResult.Model -> Html
viewSearchResult address result =
SearchResult.view
(Signal.forwardTo address (UpdateSearchResult result.id))
viewSearchResult result =
SearchResult.view (Signal.forwardTo address (UpdateSearchResult result.id))
result
onInput address wrap =
on "input" targetValue (\val -> Signal.message address (wrap val))
defaultValue str =
property "defaultValue" (Json.Encode.string str)
type Action
type Msg
= Search
| SetQuery String
| SetResults (List SearchResult.Model)
| UpdateSearchResult ResultId SearchResult.Action
update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search ->
( model, Effects.task (searchFeed model.query) )
( model, searchFeed model.query )
SetQuery query ->
( { model | query = query }, Effects.none )
( { model | query = query }, Cmd.none )
SetResults results ->
let
@@ -115,7 +100,7 @@ update action model =
|> List.map (\result -> ( result.id, result ))
|> Dict.fromList
in
( { model | results = resultsById }, Effects.none )
( { model | results = resultsById }, Cmd.none )
UpdateSearchResult id childAction ->
let
@@ -126,7 +111,7 @@ update action model =
in
case updated of
Nothing ->
( model, Effects.none )
( model, Cmd.none )
Just ( newChildModel, childEffects ) ->
let

View File

@@ -1,27 +1,13 @@
module Main (..) where
module Main exposing (..)
import StartApp
import ElmHub exposing (..)
import Effects exposing (Effects)
import Task exposing (Task)
import Html exposing (Html)
main : Signal Html
main : Program Never
main =
app.html
app : StartApp.App Model
app =
StartApp.start
Html.App.program
{ view = view
, update = update
, init = ( initialModel, Effects.task (searchFeed initialModel.query) )
, init = ( initialModel, searchFeed initialModel.query )
, inputs = []
}
port tasks : Signal (Task Effects.Never ())
port tasks =
app.tasks

View File

@@ -4,16 +4,16 @@ Part 13
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```
## Compiling CSS

View File

@@ -1,11 +1,9 @@
module SearchResult (..) where
module SearchResult exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Signal exposing (Address)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
@@ -21,7 +19,7 @@ type alias ResultId =
Int
type Action
type Msg
= Expand
| Collapse
@@ -35,31 +33,27 @@ decoder =
|> hardcoded True
update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Expand ->
( { model | expanded = True }, Effects.none )
( { model | expanded = True }, Cmd.none )
Collapse ->
( { model | expanded = False }, Effects.none )
( { model | expanded = False }, Cmd.none )
view : Address Action -> Model -> Html
view address model =
li
[]
view : Model -> Html Msg
view model =
li []
<| if model.expanded then
[ span [ class "star-count" ] [ text (toString model.stars) ]
, a
[ href ("https://github.com/" ++ model.name), target "_blank" ]
, a [ href ("https://github.com/" ++ model.name), target "_blank" ]
[ text model.name ]
, button
[ class "hide-result", onClick address Collapse ]
, button [ class "hide-result", onClick Collapse ]
[ text "X" ]
]
else
[ button
[ class "expand-result", onClick address Expand ]
[ button [ class "expand-result", onClick Expand ]
[ text "Show" ]
]

View File

@@ -10,11 +10,10 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"rtfeldman/elm-css": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -10,12 +10,10 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"rtfeldman/elm-css": "1.0.0 <= v < 2.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -9,13 +9,11 @@
],
"exposed-modules": [],
"dependencies": {
"deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0",
"laszlopandy/elm-console": "1.0.3 <= v < 2.0.0"
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"rtfeldman/elm-css": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -50,14 +50,19 @@ model =
}
elmHubHeader : Html a
elmHubHeader =
header []
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
]
{-| TODO add a type annotation to this function
-}
view model =
div [ class "content" ]
[ header []
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
]
[ elmHubHeader
, ul [ class "results" ]
[{- TODO use model.results and viewSearchResults to display results -}]
]

View File

@@ -4,16 +4,16 @@ Part 2
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```
## References

View File

@@ -3,6 +3,7 @@ module Main exposing (..)
import Html exposing (..)
import Html.App
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
type alias Model =
@@ -50,19 +51,27 @@ initialModel =
}
view : Model -> Html Msg
view model =
div [ class "content" ]
[ header []
elmHubHeader : Html a
elmHubHeader =
header []
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
]
, ul [ class "results" ]
(List.map viewSearchResult model.results)
{-| TODO revise this type annotation once we add our onClick handler
-}
view : Model -> Html a
view model =
div [ class "content" ]
[ elmHubHeader
, ul [ class "results" ] (List.map viewSearchResult model.results)
]
viewSearchResult : SearchResult -> Html Msg
{-| TODO revise this type annotation once we add our onClick handler
-}
viewSearchResult : SearchResult -> Html a
viewSearchResult result =
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]

View File

@@ -4,16 +4,16 @@ Part 3
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```
## References

View File

@@ -3,6 +3,7 @@ module Main exposing (..)
import Html exposing (..)
import Html.App
import Html.Attributes exposing (..)
import Html.Events exposing (onClick, onInput)
type alias Model =
@@ -63,13 +64,12 @@ view model =
]
, input
[ class "search-query"
-- TODO when we receive onInput, set the query in the model
-- TODO onInput, set the query in the model
, defaultValue model.query
]
[]
, button [ class "search-button" ] [ text "Search" ]
, ul [ class "results" ]
(List.map viewSearchResult model.results)
, ul [ class "results" ] (List.map viewSearchResult model.results)
]

View File

@@ -4,16 +4,16 @@ Part 4
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```
## References

View File

@@ -69,7 +69,7 @@ responseDecoder =
searchResultDecoder : Decoder SearchResult
searchResultDecoder =
-- See https://developer.github.com/v3/search/#example
-- TODO replace these `hardcoded` with calls to `require`
-- TODO replace these calls to `hardcoded` with calls to `require`
decode SearchResult
|> hardcoded 0
|> hardcoded ""

View File

@@ -4,14 +4,14 @@ Part 5
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```

View File

@@ -1,19 +1,16 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Auth
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Http
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
import Json.Encode
import Signal exposing (Address)
searchFeed : String -> Effects Action
searchFeed : String -> Cmd Msg
searchFeed query =
let
url =
@@ -23,11 +20,7 @@ searchFeed query =
++ query
++ "+language:elm&sort=stars&order=desc"
-- TODO define task as:
--
-- task = performAction argument1 argument2 argument3
--
-- Use these "ingredients" to give `performAction` the arguments it needs:
-- TODO use these ingredients to give Task.perform the arguments it needs:
--
-- Http.get
-- url
@@ -37,41 +30,15 @@ searchFeed query =
--
-- Hint: http://package.elm-lang.org/packages/evancz/elm-http/3.0.0/Http#get
task =
"TODO performAction ..."
"TODO call Task.perform ..."
in
-- TODO replace this `Effects.none` with a call to:
--
-- Effects.task task
Effects.none
{-| Note: this will be a standard function in the next release of Elm.
Example:
type Action =
HandleResponse String | HandleError Http.Error
performAction
(\responseString -> HandleResponse responseString)
(\httpError -> HandleError httpError)
(Http.getString "https://google.com?q=something")
-}
performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b
performAction successToAction errorToAction task =
let
successTask =
Task.map successToAction task
in
Task.onError successTask (\err -> Task.succeed (errorToAction err))
-- TODO replace this Cmd.none with a call to Task.perform
Cmd.none
responseDecoder : Decoder (List SearchResult)
responseDecoder =
"items" := Json.Decode.list searchResultDecoder
Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder)
searchResultDecoder : Decoder SearchResult
@@ -108,25 +75,21 @@ initialModel =
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
view : Model -> Html Msg
view 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" ]
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, viewErrorMessage model.errorMessage
, ul
[ class "results" ]
(List.map (viewSearchResult address) model.results)
, ul [ class "results" ] (List.map viewSearchResult model.results)
]
viewErrorMessage : Maybe String -> Html
viewErrorMessage : Maybe String -> Html a a
viewErrorMessage errorMessage =
case errorMessage of
Just message ->
@@ -136,29 +99,18 @@ viewErrorMessage errorMessage =
text ""
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
[]
viewSearchResult : SearchResult -> Html Msg
viewSearchResult result =
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a
[ href ("https://github.com/" ++ result.name), target "_blank" ]
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
[ text result.name ]
, button
[ class "hide-result", onClick address (DeleteById result.id) ]
, button [ class "hide-result", onClick (DeleteById result.id) ]
[ text "X" ]
]
type Action
type Msg
= Search
| SetQuery String
| DeleteById ResultId
@@ -166,27 +118,27 @@ type Action
| HandleSearchError Http.Error
update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search ->
( model, searchFeed model.query )
HandleSearchResponse results ->
( { model | results = results }, Effects.none )
( { model | results = results }, Cmd.none )
HandleSearchError error ->
-- TODO if decoding failed, store the message in model.errorMessage
--
-- Hint 1: look for "decode" in the documentation for this union type:
-- http://package.elm-lang.org/packages/evancz/elm-http/3.0.0/Http#Error
-- http://package.elm-lang.org/packages/evancz/elm-http/3.0.1/Http#Error
--
-- Hint 2: to check if this is working, break responseDecoder
-- by changing "stargazers_count" to "description"
( model, Effects.none )
( model, Cmd.none )
SetQuery query ->
( { model | query = query }, Effects.none )
( { model | query = query }, Cmd.none )
DeleteById idToHide ->
let
@@ -197,4 +149,4 @@ update action model =
newModel =
{ model | results = newResults }
in
( newModel, Effects.none )
( newModel, Cmd.none )

View File

@@ -1,27 +1,13 @@
module Main (..) where
module Main exposing (..)
import StartApp
import ElmHub exposing (..)
import Effects exposing (Effects)
import Task exposing (Task)
import Html exposing (Html)
main : Signal Html
main : Program Never
main =
app.html
app : StartApp.App Model
app =
StartApp.start
Html.App.program
{ view = view
, update = update
, init = ( initialModel, searchFeed initialModel.query )
, inputs = []
}
port tasks : Signal (Task Effects.Never ())
port tasks =
app.tasks

View File

@@ -4,16 +4,16 @@ Part 6
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```
## References

View File

@@ -10,11 +10,9 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -1,19 +1,16 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Auth
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Http
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
import Json.Encode
import Signal exposing (Address)
searchFeed : String -> Effects Action
searchFeed : String -> Cmd Msg
searchFeed query =
let
url =
@@ -22,19 +19,13 @@ searchFeed query =
++ "&q="
++ query
++ "+language:elm&sort=stars&order=desc"
task =
performAction
(\response -> HandleSearchResponse response)
(\error -> HandleSearchError error)
(Http.get responseDecoder url)
in
Effects.task task
Task.perform HandleSearchError HandleSearchResponse (Http.get responseDecoder url)
responseDecoder : Decoder (List SearchResult)
responseDecoder =
"items" := Json.Decode.list searchResultDecoder
Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder)
searchResultDecoder : Decoder SearchResult
@@ -45,30 +36,6 @@ searchResultDecoder =
|> required "stargazers_count" Json.Decode.int
{-| Note: this will be a standard function in the next release of Elm.
Example:
type Action =
HandleResponse String | HandleError Http.Error
performAction
(\responseString -> HandleResponse responseString)
(\httpError -> HandleError httpError)
(Http.getString "https://google.com?q=something")
-}
performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b
performAction successToAction errorToAction task =
let
successTask =
Task.map successToAction task
in
Task.onError successTask (\err -> Task.succeed (errorToAction err))
type alias Model =
{ query : String
, results : List SearchResult
@@ -95,25 +62,21 @@ initialModel =
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
view : Model -> Html Msg
view 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" ]
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, viewErrorMessage model.errorMessage
, ul
[ class "results" ]
(List.map (viewSearchResult address) model.results)
, ul [ class "results" ] (List.map viewSearchResult model.results)
]
viewErrorMessage : Maybe String -> Html
viewErrorMessage : Maybe String -> Html a
viewErrorMessage errorMessage =
case errorMessage of
Just message ->
@@ -123,29 +86,18 @@ viewErrorMessage errorMessage =
text ""
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
[]
viewSearchResult : SearchResult -> Html Msg
viewSearchResult result =
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a
[ href ("https://github.com/" ++ result.name), target "_blank" ]
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
[ text result.name ]
, button
[ class "hide-result", onClick address (DeleteById result.id) ]
, button [ class "hide-result", onClick (DeleteById result.id) ]
[ text "X" ]
]
type Action
type Msg
= Search
| SetQuery String
| DeleteById ResultId
@@ -153,14 +105,14 @@ type Action
| HandleSearchError Http.Error
update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Search ->
( model, searchFeed model.query )
HandleSearchResponse results ->
( { model | results = results }, Effects.none )
( { model | results = results }, Cmd.none )
HandleSearchError error ->
let
@@ -172,10 +124,10 @@ update action model =
_ ->
Nothing
in
( { model | errorMessage = errorMessage }, Effects.none )
( { model | errorMessage = errorMessage }, Cmd.none )
SetQuery query ->
( { model | query = query }, Effects.none )
( { model | query = query }, Cmd.none )
DeleteById idToHide ->
let
@@ -186,4 +138,4 @@ update action model =
newModel =
{ model | results = newResults }
in
( newModel, Effects.none )
( newModel, Cmd.none )

View File

@@ -1,27 +1,13 @@
module Main (..) where
module Main exposing (..)
import StartApp
import ElmHub exposing (..)
import Effects exposing (Effects)
import Task exposing (Task)
import Html exposing (Html)
main : Signal Html
main : Program Never
main =
app.html
app : StartApp.App Model
app =
StartApp.start
Html.App.program
{ view = view
, update = update
, init = ( initialModel, searchFeed initialModel.query )
, inputs = []
}
port tasks : Signal (Task Effects.Never ())
port tasks =
app.tasks

View File

@@ -4,23 +4,23 @@ Part 7
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```
## Running Tests
```bash
cd test
elm package install
elm-package install
elm test TestRunner.elm
```

View File

@@ -10,11 +10,9 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -9,14 +9,10 @@
],
"exposed-modules": [],
"dependencies": {
"deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0",
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0",
"laszlopandy/elm-console": "1.0.3 <= v < 2.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -1,43 +1,28 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Http
import Auth
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
import Json.Encode
import Signal exposing (Address)
searchFeed : Address String -> String -> Effects Action
searchFeed address query =
let
getQueryUrl : String -> String
getQueryUrl query =
-- See https://developer.github.com/v3/search/#example for how to customize!
url =
"https://api.github.com/search/repositories?access_token="
++ Auth.token
++ "&q="
++ query
++ "+language:elm&sort=stars&order=desc"
-- These only talk to JavaScript ports now. They never result in Actions
-- actually do any actions themselves.
task =
performAction
(\_ -> DoNothing)
(\_ -> DoNothing)
(Signal.send address query)
in
Effects.task task
responseDecoder : Decoder (List SearchResult)
responseDecoder =
"items" := Json.Decode.list searchResultDecoder
Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder)
searchResultDecoder : Decoder SearchResult
@@ -48,30 +33,6 @@ searchResultDecoder =
|> required "stargazers_count" Json.Decode.int
{-| Note: this will be a standard function in the next release of Elm.
Example:
type Action =
HandleResponse String | HandleError Http.Error
performAction
(\responseString -> HandleResponse responseString)
(\httpError -> HandleError httpError)
(Http.getString "https://google.com?q=something")
-}
performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b
performAction successToAction errorToAction task =
let
successTask =
Task.map successToAction task
in
Task.onError successTask (\err -> Task.succeed (errorToAction err))
type alias Model =
{ query : String
, results : List SearchResult
@@ -98,25 +59,21 @@ initialModel =
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
view : Model -> Html Msg
view 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" ]
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, viewErrorMessage model.errorMessage
, ul
[ class "results" ]
(List.map (viewSearchResult address) model.results)
, ul [ class "results" ] (List.map viewSearchResult model.results)
]
viewErrorMessage : Maybe String -> Html
viewErrorMessage : Maybe String -> Html a
viewErrorMessage errorMessage =
case errorMessage of
Just message ->
@@ -126,29 +83,18 @@ viewErrorMessage errorMessage =
text ""
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
[]
viewSearchResult : SearchResult -> Html Msg
viewSearchResult result =
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a
[ href ("https://github.com/" ++ result.name), target "_blank" ]
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
[ text result.name ]
, button
[ class "hide-result", onClick address (DeleteById result.id) ]
, button [ class "hide-result", onClick (DeleteById result.id) ]
[ text "X" ]
]
type Action
type Msg
= Search
| SetQuery String
| DeleteById ResultId
@@ -157,20 +103,20 @@ type Action
| DoNothing
update : Address String -> Action -> Model -> ( Model, Effects Action )
update searchAddress action model =
case action of
update : (String -> Cmd Msg) -> Msg -> Model -> ( Model, Cmd Msg )
update searchFeed msg model =
case msg of
Search ->
( model, searchFeed searchAddress model.query )
( model, searchFeed (getQueryUrl model.query) )
SetQuery query ->
( { model | query = query }, Effects.none )
( { model | query = query }, Cmd.none )
SetResults results ->
( { model | results = results }, Effects.none )
( { model | results = results }, Cmd.none )
SetErrorMessage errorMessage ->
( { model | errorMessage = errorMessage }, Effects.none )
( { model | errorMessage = errorMessage }, Cmd.none )
DeleteById idToHide ->
let
@@ -181,7 +127,16 @@ update searchAddress action model =
newModel =
{ model | results = newResults }
in
( newModel, Effects.none )
( newModel, Cmd.none )
DoNothing ->
( model, Effects.none )
( model, Cmd.none )
decodeGithubResponse : Json.Encode.Value -> Msg
decodeGithubResponse value =
-- TODO use Json.Decode.DecodeValue to decode the response into an Action.
--
-- Hint: look at ElmHub.elm, specifically the definition of Action and
-- the deefinition of responseDecoder
SetErrorMessage (Just "TODO decode the response!")

View File

@@ -1,57 +1,31 @@
module Main (..) where
port module Main exposing (..)
import StartApp
import ElmHub exposing (..)
import Effects exposing (Effects)
import Task exposing (Task)
import Html exposing (Html)
import Signal
import Json.Encode
import Json.Decode
import Html.App
import Json.Decode exposing (Value)
main : Signal Html
main : Program Never
main =
app.html
app : StartApp.App Model
app =
StartApp.start
Html.App.program
{ view = view
, update = update search.address
, init = ( initialModel, searchFeed search.address initialModel.query )
, inputs = [ responseActions ]
, update = update githubSearch
, init = ( initialModel, githubSearch (getQueryUrl initialModel.query) )
, subscriptions = \_ -> githubResponse decodeResponse
}
port tasks : Signal (Task Effects.Never ())
port tasks =
app.tasks
decodeResponse : Json.Decode.Value -> Msg
decodeResponse json =
case Json.Decode.decodeValue responseDecoder json of
Err err ->
SetErrorMessage (Just err)
Ok results ->
SetResults results
search : Signal.Mailbox String
search =
Signal.mailbox ""
port githubSearch : String -> Cmd msg
port githubSearch : Signal String
port githubSearch =
search.signal
responseActions : Signal Action
responseActions =
Signal.map decodeGithubResponse githubResponse
decodeGithubResponse : Json.Encode.Value -> Action
decodeGithubResponse value =
-- TODO use Json.Decode.DecodeValue to decode the response into an Action.
--
-- Hint: look at ElmHub.elm, specifically the definition of Action and
-- the deefinition of responseDecoder
SetErrorMessage (Just "TODO decode the response!")
port githubResponse : Signal Json.Encode.Value
port githubResponse : (Json.Decode.Value -> msg) -> Sub msg

View File

@@ -4,22 +4,22 @@ Part 8
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```
## Running Tests
```bash
cd test
elm package install
elm-package install
elm test TestRunner.elm
```

View File

@@ -10,11 +10,9 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -9,14 +9,10 @@
],
"exposed-modules": [],
"dependencies": {
"deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0",
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0",
"laszlopandy/elm-console": "1.0.3 <= v < 2.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}

View File

@@ -1,44 +1,27 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Http
import Auth
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
import Json.Encode
import Signal exposing (Address)
import Dict exposing (Dict)
searchFeed : Address String -> String -> Effects Action
searchFeed address query =
let
getQueryUrl : String -> String
getQueryUrl query =
-- See https://developer.github.com/v3/search/#example for how to customize!
url =
"https://api.github.com/search/repositories?access_token="
++ Auth.token
++ "&q="
++ query
++ "+language:elm&sort=stars&order=desc"
-- These only talk to JavaScript ports now. They never result in Actions
-- actually do any actions themselves.
task =
performAction
(\_ -> DoNothing)
(\_ -> DoNothing)
(Signal.send address query)
in
Effects.task task
responseDecoder : Decoder (List SearchResult)
responseDecoder =
"items" := Json.Decode.list searchResultDecoder
Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder)
searchResultDecoder : Decoder SearchResult
@@ -49,30 +32,6 @@ searchResultDecoder =
|> required "stargazers_count" Json.Decode.int
{-| Note: this will be a standard function in the next release of Elm.
Example:
type Action =
HandleResponse String | HandleError Http.Error
performAction
(\responseString -> HandleResponse responseString)
(\httpError -> HandleError httpError)
(Http.getString "https://google.com?q=something")
-}
performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b
performAction successToAction errorToAction task =
let
successTask =
Task.map successToAction task
in
Task.onError successTask (\err -> Task.succeed (errorToAction err))
type alias Model =
{ query : String
, results : Dict ResultId SearchResult
@@ -99,52 +58,37 @@ initialModel =
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
view : Model -> Html Msg
view 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" ]
(viewSearchResults address model.results)
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, ul [ class "results" ] (viewSearchResults model.results)
]
viewSearchResults : Address Action -> Dict ResultId SearchResult -> List Html
viewSearchResults address results =
viewSearchResults : Dict ResultId SearchResult -> List (Html Msg)
viewSearchResults results =
-- TODO sort by star count and render
[]
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
[]
viewSearchResult : SearchResult -> Html Msg
viewSearchResult result =
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a
[ href ("https://github.com/" ++ result.name), target "_blank" ]
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
[ text result.name ]
, button
[ class "hide-result", onClick address (DeleteById result.id) ]
, button [ class "hide-result", onClick (DeleteById result.id) ]
[ text "X" ]
]
type Action
type Msg
= Search
| SetQuery String
| DeleteById ResultId
@@ -153,14 +97,14 @@ type Action
| DoNothing
update : Address String -> Action -> Model -> ( Model, Effects Action )
update searchAddress action model =
case action of
update : (String -> Cmd Msg) -> Msg -> Model -> ( Model, Cmd Msg )
update searchFeed msg model =
case msg of
Search ->
( model, searchFeed searchAddress model.query )
( model, searchFeed (getQueryUrl model.query) )
SetQuery query ->
( { model | query = query }, Effects.none )
( { model | query = query }, Cmd.none )
SetResults results ->
let
@@ -169,14 +113,14 @@ update searchAddress action model =
-- TODO convert results list into a Dict
Dict.empty
in
( { model | results = resultsById }, Effects.none )
( { model | results = resultsById }, Cmd.none )
DeleteById id ->
-- TODO delete the result with the given id
( model, Effects.none )
( model, Cmd.none )
SetErrorMessage errorMessage ->
( { model | errorMessage = errorMessage }, Effects.none )
( { model | errorMessage = errorMessage }, Cmd.none )
DoNothing ->
( model, Effects.none )
( model, Cmd.none )

View File

@@ -1,58 +1,31 @@
module Main (..) where
port module Main exposing (..)
import StartApp
import ElmHub exposing (..)
import Effects exposing (Effects)
import Task exposing (Task)
import Html exposing (Html)
import Signal
import Json.Encode
import Json.Decode
import Html.App
import Json.Decode exposing (Value)
main : Signal Html
main : Program Never
main =
app.html
app : StartApp.App Model
app =
StartApp.start
Html.App.program
{ view = view
, update = update search.address
, init = ( initialModel, searchFeed search.address initialModel.query )
, inputs = [ responseActions ]
, update = update githubSearch
, init = ( initialModel, githubSearch (getQueryUrl initialModel.query) )
, subscriptions = \_ -> githubResponse decodeResponse
}
port tasks : Signal (Task Effects.Never ())
port tasks =
app.tasks
decodeResponse : Json.Decode.Value -> Msg
decodeResponse json =
case Json.Decode.decodeValue responseDecoder json of
Err err ->
SetErrorMessage (Just err)
search : Signal.Mailbox String
search =
Signal.mailbox ""
port githubSearch : Signal String
port githubSearch =
search.signal
responseActions : Signal Action
responseActions =
Signal.map decodeGithubResponse githubResponse
decodeGithubResponse : Json.Encode.Value -> Action
decodeGithubResponse value =
case Json.Decode.decodeValue responseDecoder value of
Ok results ->
SetResults results
Err message ->
SetErrorMessage (Just message)
port githubSearch : String -> Cmd msg
port githubResponse : Signal Json.Encode.Value
port githubResponse : (Json.Decode.Value -> msg) -> Sub msg

View File

@@ -4,14 +4,14 @@ Part 9
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```

View File

@@ -10,11 +10,9 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
"elm-version": "0.17.0 <= v < 0.18.0"
}