Add part7
This commit is contained in:
259
advanced/part7/src/Page/Home.elm
Normal file
259
advanced/part7/src/Page/Home.elm
Normal file
@@ -0,0 +1,259 @@
|
||||
module Page.Home exposing (Model, Msg, init, subscriptions, toSession, update, view)
|
||||
|
||||
{-| The homepage. You can get here via either the / or /#/ routes.
|
||||
-}
|
||||
|
||||
import Article
|
||||
import Article.Feed as Feed
|
||||
import Article.FeedSources as FeedSources exposing (FeedSources, Source(..))
|
||||
import Article.Tag as Tag exposing (Tag)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (attribute, class, classList, href, id, placeholder)
|
||||
import Html.Events exposing (onClick)
|
||||
import Http
|
||||
import Loading
|
||||
import Log
|
||||
import Page
|
||||
import Session exposing (Session)
|
||||
import Task exposing (Task)
|
||||
import Time
|
||||
import Viewer.Cred as Cred exposing (Cred)
|
||||
|
||||
|
||||
|
||||
-- MODEL
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ session : Session
|
||||
, timeZone : Time.Zone
|
||||
|
||||
-- Loaded independently from server
|
||||
, tags : Status (List Tag)
|
||||
, feed : Status Feed.Model
|
||||
}
|
||||
|
||||
|
||||
type Status a
|
||||
= Loading
|
||||
| LoadingSlowly
|
||||
| Loaded a
|
||||
| Failed
|
||||
|
||||
|
||||
init : Session -> ( Model, Cmd Msg )
|
||||
init session =
|
||||
let
|
||||
feedSources =
|
||||
case Session.cred session of
|
||||
Just cred ->
|
||||
FeedSources.fromLists (YourFeed cred) [ GlobalFeed ]
|
||||
|
||||
Nothing ->
|
||||
FeedSources.fromLists GlobalFeed []
|
||||
|
||||
loadTags =
|
||||
Tag.list
|
||||
|> Http.toTask
|
||||
in
|
||||
( { session = session
|
||||
, timeZone = Time.utc
|
||||
, tags = Loading
|
||||
, feed = Loading
|
||||
}
|
||||
, Cmd.batch
|
||||
[ Feed.init session feedSources
|
||||
|> Task.attempt CompletedFeedLoad
|
||||
, Tag.list
|
||||
|> Http.send CompletedTagsLoad
|
||||
, Task.perform GotTimeZone Time.here
|
||||
, Task.perform (\_ -> PassedSlowLoadThreshold) Loading.slowThreshold
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
|
||||
view : Model -> { title : String, content : Html Msg }
|
||||
view model =
|
||||
{ title = "Conduit"
|
||||
, content =
|
||||
div [ class "home-page" ]
|
||||
[ viewBanner
|
||||
, div [ class "container page" ]
|
||||
[ div [ class "row" ]
|
||||
[ div [ class "col-md-9" ] <|
|
||||
case model.feed of
|
||||
Loaded feed ->
|
||||
viewFeed model.timeZone feed
|
||||
|
||||
Loading ->
|
||||
[]
|
||||
|
||||
LoadingSlowly ->
|
||||
[ Loading.icon ]
|
||||
|
||||
Failed ->
|
||||
[ Loading.error "feed" ]
|
||||
, div [ class "col-md-3" ] <|
|
||||
case model.tags of
|
||||
Loaded tags ->
|
||||
[ div [ class "sidebar" ] <|
|
||||
[ p [] [ text "Popular Tags" ]
|
||||
, viewTags tags
|
||||
]
|
||||
]
|
||||
|
||||
Loading ->
|
||||
[]
|
||||
|
||||
LoadingSlowly ->
|
||||
[ Loading.icon ]
|
||||
|
||||
Failed ->
|
||||
[ Loading.error "tags" ]
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
viewBanner : Html msg
|
||||
viewBanner =
|
||||
div [ class "banner" ]
|
||||
[ div [ class "container" ]
|
||||
[ h1 [ class "logo-font" ] [ text "conduit" ]
|
||||
, p [] [ text "A place to share your knowledge." ]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
viewFeed : Time.Zone -> Feed.Model -> List (Html Msg)
|
||||
viewFeed timeZone feed =
|
||||
div [ class "feed-toggle" ]
|
||||
[ Feed.viewFeedSources feed |> Html.map GotFeedMsg ]
|
||||
:: (Feed.viewArticles timeZone feed |> List.map (Html.map GotFeedMsg))
|
||||
|
||||
|
||||
viewTags : List Tag -> Html Msg
|
||||
viewTags tags =
|
||||
div [ class "tag-list" ] (List.map viewTag tags)
|
||||
|
||||
|
||||
viewTag : Tag -> Html Msg
|
||||
viewTag tagName =
|
||||
a
|
||||
[ class "tag-pill tag-default"
|
||||
, onClick (ClickedTag tagName)
|
||||
|
||||
-- The RealWorld CSS requires an href to work properly.
|
||||
, href ""
|
||||
]
|
||||
[ text (Tag.toString tagName) ]
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
type Msg
|
||||
= ClickedTag Tag
|
||||
| CompletedFeedLoad (Result Http.Error Feed.Model)
|
||||
| CompletedTagsLoad (Result Http.Error (List Tag))
|
||||
| GotTimeZone Time.Zone
|
||||
| GotFeedMsg Feed.Msg
|
||||
| GotSession Session
|
||||
| PassedSlowLoadThreshold
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
ClickedTag tagName ->
|
||||
let
|
||||
subCmd =
|
||||
Feed.selectTag (Session.cred model.session) tagName
|
||||
in
|
||||
( model, Cmd.map GotFeedMsg subCmd )
|
||||
|
||||
CompletedFeedLoad (Ok feed) ->
|
||||
( { model | feed = Loaded feed }, Cmd.none )
|
||||
|
||||
CompletedFeedLoad (Err error) ->
|
||||
( { model | feed = Failed }, Cmd.none )
|
||||
|
||||
CompletedTagsLoad (Ok tags) ->
|
||||
( { model | tags = Loaded tags }, Cmd.none )
|
||||
|
||||
CompletedTagsLoad (Err error) ->
|
||||
( { model | tags = Failed }
|
||||
, Log.error
|
||||
)
|
||||
|
||||
GotFeedMsg subMsg ->
|
||||
case model.feed of
|
||||
Loaded feed ->
|
||||
let
|
||||
( newFeed, subCmd ) =
|
||||
Feed.update (Session.cred model.session) subMsg feed
|
||||
in
|
||||
( { model | feed = Loaded newFeed }
|
||||
, Cmd.map GotFeedMsg subCmd
|
||||
)
|
||||
|
||||
Loading ->
|
||||
( model, Log.error )
|
||||
|
||||
LoadingSlowly ->
|
||||
( model, Log.error )
|
||||
|
||||
Failed ->
|
||||
( model, Log.error )
|
||||
|
||||
GotTimeZone tz ->
|
||||
( { model | timeZone = tz }, Cmd.none )
|
||||
|
||||
GotSession session ->
|
||||
( { model | session = session }, Cmd.none )
|
||||
|
||||
PassedSlowLoadThreshold ->
|
||||
let
|
||||
-- If any data is still Loading, change it to LoadingSlowly
|
||||
-- so `view` knows to render a spinner.
|
||||
feed =
|
||||
case model.feed of
|
||||
Loading ->
|
||||
LoadingSlowly
|
||||
|
||||
other ->
|
||||
other
|
||||
|
||||
tags =
|
||||
case model.tags of
|
||||
Loading ->
|
||||
LoadingSlowly
|
||||
|
||||
other ->
|
||||
other
|
||||
in
|
||||
( { model | feed = feed, tags = tags }, Cmd.none )
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
Session.changes GotSession (Session.navKey model.session)
|
||||
|
||||
|
||||
|
||||
-- EXPORT
|
||||
|
||||
|
||||
toSession : Model -> Session
|
||||
toSession model =
|
||||
model.session
|
||||
Reference in New Issue
Block a user