226 lines
5.5 KiB
Elm
226 lines
5.5 KiB
Elm
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
|
|
| 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
|
|
]
|
|
)
|
|
|
|
|
|
|
|
-- 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 ->
|
|
[ Loading.icon ]
|
|
|
|
Failed ->
|
|
[ Loading.error "feed" ]
|
|
, div [ class "col-md-3" ]
|
|
[ div [ class "sidebar" ] <|
|
|
case model.tags of
|
|
Loaded tags ->
|
|
[ p [] [ text "Popular Tags" ]
|
|
, viewTags tags
|
|
]
|
|
|
|
Loading ->
|
|
[ 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
|
|
|
|
|
|
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 )
|
|
|
|
Failed ->
|
|
( model, Log.error )
|
|
|
|
GotTimeZone tz ->
|
|
( { model | timeZone = tz }, Cmd.none )
|
|
|
|
GotSession session ->
|
|
( { model | session = session }, Cmd.none )
|
|
|
|
|
|
|
|
-- SUBSCRIPTIONS
|
|
|
|
|
|
subscriptions : Model -> Sub Msg
|
|
subscriptions model =
|
|
Session.changes GotSession (Session.navKey model.session)
|
|
|
|
|
|
|
|
-- EXPORT
|
|
|
|
|
|
toSession : Model -> Session
|
|
toSession model =
|
|
model.session
|