Add part3
This commit is contained in:
21
intro/part3/README.md
Normal file
21
intro/part3/README.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Part 3
|
||||||
|
|
||||||
|
This is just like last time, except first we'll install the `elm/browser` package so we can create an interactive app in the browser, instead of static HTML.
|
||||||
|
|
||||||
|
To install the package, `cd` into the `part3/` directory and run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
elm install elm/browser
|
||||||
|
```
|
||||||
|
|
||||||
|
Then build everything the same way as last time:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
elm make src/Main.elm --output elm.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, open `index.html` in your browser.
|
||||||
|
|
||||||
|
## Exercise
|
||||||
|
|
||||||
|
Open `src/Main.elm` in your editor and resolve the TODOs there.
|
||||||
24
intro/part3/elm.json
Normal file
24
intro/part3/elm.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"type": "application",
|
||||||
|
"source-directories": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"elm-version": "0.19.0",
|
||||||
|
"dependencies": {
|
||||||
|
"direct": {
|
||||||
|
"elm/browser": "1.0.0",
|
||||||
|
"elm/core": "1.0.0",
|
||||||
|
"elm/html": "1.0.0"
|
||||||
|
},
|
||||||
|
"indirect": {
|
||||||
|
"elm/json": "1.0.0",
|
||||||
|
"elm/time": "1.0.0",
|
||||||
|
"elm/url": "1.0.0",
|
||||||
|
"elm/virtual-dom": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test-dependencies": {
|
||||||
|
"direct": {},
|
||||||
|
"indirect": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
intro/part3/index.html
Normal file
15
intro/part3/index.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Elm Workshop</title>
|
||||||
|
<link rel="stylesheet" href="../server/public/main.css">
|
||||||
|
<script src="elm.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script>
|
||||||
|
Elm.Main.init({node: document.getElementById("app")});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
intro/part3/src/Article.elm
Normal file
21
intro/part3/src/Article.elm
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module Article exposing (feed, tags)
|
||||||
|
|
||||||
|
-- For now, this module only holds hardcoded data.
|
||||||
|
--
|
||||||
|
-- In future exercises, it will read data from the server!
|
||||||
|
|
||||||
|
|
||||||
|
tags =
|
||||||
|
[ "elm"
|
||||||
|
, "fun"
|
||||||
|
, "programming"
|
||||||
|
, "dragons"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
feed =
|
||||||
|
[ { title = "Elm is fun!", description = "Elm", body = "I've really been enjoying it!", tags = [ "elm", "fun" ], slug = "elm-is-fun--zb6nba" }
|
||||||
|
, { title = "Who says undefined isn't a function anyway?", description = "Functions", body = "Quite frankly I think undefined can be anything it wants to be,if it believes in itself.", slug = "who-says-undefined-isnt-a-function-anyway-t39ope", tags = [ "programming" ] }
|
||||||
|
, { title = "This compiler is pretty neat", description = "Elm", body = "It tells me about problems in my code. How neat is that?", tags = [ "compilers", "elm" ], slug = "this-compiler-is-pretty-neat-9ycui8" }
|
||||||
|
, { title = "Are dragons real?", description = "dragons", body = "Do Komodo Dragons count? I think they should. It's right there in the name!", tags = [ "dragons" ], slug = "are-dragons-real-467lsh" }
|
||||||
|
]
|
||||||
132
intro/part3/src/Main.elm
Normal file
132
intro/part3/src/Main.elm
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
module Main exposing (main)
|
||||||
|
|
||||||
|
-- 👇 You can see our new `Article` module in `src/Article.elm`
|
||||||
|
|
||||||
|
import Article
|
||||||
|
import Browser
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes exposing (..)
|
||||||
|
import Html.Events exposing (onClick)
|
||||||
|
|
||||||
|
|
||||||
|
-- MODEL
|
||||||
|
|
||||||
|
|
||||||
|
initialModel =
|
||||||
|
{ tags = Article.tags
|
||||||
|
, selectedTag = "elm"
|
||||||
|
, allArticles = Article.feed
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- UPDATE
|
||||||
|
|
||||||
|
|
||||||
|
update msg model =
|
||||||
|
{- 👉 TODO: If `msg.description` is "ClickedTag", then
|
||||||
|
set the model's `selectedTag` field to be `msg.data`
|
||||||
|
|
||||||
|
💡 HINT 1: record update syntax looks like this:
|
||||||
|
|
||||||
|
{ model | foo = bar }
|
||||||
|
|
||||||
|
💡 HINT 2: Don't forget, every `if` must have an `else`!
|
||||||
|
|
||||||
|
-}
|
||||||
|
model
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- VIEW
|
||||||
|
|
||||||
|
|
||||||
|
view model =
|
||||||
|
let
|
||||||
|
{- 👉 TODO: Filter the articles down to onl the ones
|
||||||
|
that include the currently selected tag.
|
||||||
|
|
||||||
|
💡 HINT: Replace `True` below with something involving
|
||||||
|
`List.member`, `article.tags`, and `model.selectedTag`
|
||||||
|
|
||||||
|
Docs for List.member: http://package.elm-lang.org/packages/elm-lang/core/latest/List#member
|
||||||
|
-}
|
||||||
|
articles =
|
||||||
|
List.filter (\article -> True)
|
||||||
|
model.allArticles
|
||||||
|
|
||||||
|
feed =
|
||||||
|
List.map viewArticle articles
|
||||||
|
in
|
||||||
|
div [ class "home-page" ]
|
||||||
|
[ viewBanner
|
||||||
|
, div [ class "container page" ]
|
||||||
|
[ div [ class "row" ]
|
||||||
|
[ div [ class "col-md-9" ] feed
|
||||||
|
, div [ class "col-md-3" ]
|
||||||
|
[ div [ class "sidebar" ]
|
||||||
|
[ p [] [ text "Popular Tags" ]
|
||||||
|
, viewTags model
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewArticle article =
|
||||||
|
div [ class "article-preview" ]
|
||||||
|
[ h1 [] [ text article.title ]
|
||||||
|
, p [] [ text article.description ]
|
||||||
|
, span [] [ text "Read more..." ]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewBanner =
|
||||||
|
div [ class "banner" ]
|
||||||
|
[ div [ class "container" ]
|
||||||
|
[ h1 [ class "logo-font" ] [ text "conduit" ]
|
||||||
|
, p [] [ text "A place to share your knowledge." ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewTag selectedTagName tagName =
|
||||||
|
let
|
||||||
|
otherClass =
|
||||||
|
if tagName == selectedTagName then
|
||||||
|
"tag-selected"
|
||||||
|
else
|
||||||
|
"tag-default"
|
||||||
|
in
|
||||||
|
button
|
||||||
|
[ class ("tag-pill " ++ otherClass)
|
||||||
|
|
||||||
|
{- 👉 TODO: Add an `onClick` handler which sends a msg
|
||||||
|
that our `update` function above will use
|
||||||
|
to set the currently selected tag to `tagName`.
|
||||||
|
|
||||||
|
💡 HINT: It should look something like this:
|
||||||
|
|
||||||
|
, onClick { description = … , data = … }
|
||||||
|
|
||||||
|
👆 Don't forget to add a comma before `onClick`!
|
||||||
|
-}
|
||||||
|
]
|
||||||
|
[ text tagName ]
|
||||||
|
|
||||||
|
|
||||||
|
viewTags model =
|
||||||
|
div [ class "tag-list" ] (List.map (viewTag model.selectedTag) model.tags)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- MAIN
|
||||||
|
|
||||||
|
|
||||||
|
main =
|
||||||
|
Browser.sandbox
|
||||||
|
{ init = initialModel
|
||||||
|
, view = view
|
||||||
|
, update = update
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user