module Page exposing (Page(..), view, viewErrors) import Avatar import Browser exposing (Document) import Html exposing (Html, a, button, div, footer, i, img, li, nav, p, span, text, ul) import Html.Attributes exposing (class, classList, href, style) import Html.Events exposing (onClick) import Profile import Route exposing (Route) import Session exposing (Session) import Username exposing (Username) import Viewer exposing (Viewer) import Viewer.Cred as Cred exposing (Cred) {-| Determines which navbar link (if any) will be rendered as active. Note that we don't enumerate every page here, because the navbar doesn't have links for every page. Anything that's not part of the navbar falls under Other. -} type Page = Other | Home | Login | Register | Settings | Profile Username | NewArticle {-| Take a page's Html and frames it with a header and footer. The caller provides the current user, so we can display in either "signed in" (rendering username) or "signed out" mode. isLoading is for determining whether we should show a loading spinner in the header. (This comes up during slow page transitions.) -} view : Maybe Viewer -> Page -> { title : String, content : Html msg } -> Document msg view maybeViewer page { title, content } = { title = title ++ " - Conduit" , body = viewHeader page maybeViewer :: content :: [ viewFooter ] } viewHeader : Page -> Maybe Viewer -> Html msg viewHeader page maybeViewer = nav [ class "navbar navbar-light" ] [ div [ class "container" ] [ a [ class "navbar-brand", Route.href Route.Home ] [ text "conduit" ] , ul [ class "nav navbar-nav pull-xs-right" ] <| navbarLink page Route.Home [ text "Home" ] :: viewMenu page maybeViewer ] ] viewMenu : Page -> Maybe Viewer -> List (Html msg) viewMenu page maybeViewer = let linkTo = navbarLink page in case maybeViewer of Just viewer -> let cred = Viewer.cred viewer { username } = cred avatar = Profile.avatar (Viewer.profile viewer) in [ linkTo Route.NewArticle [ i [ class "ion-compose" ] [], text " New Post" ] , linkTo Route.Settings [ i [ class "ion-gear-a" ] [], text " Settings" ] , linkTo (Route.Profile username) [ img [ class "user-pic", Avatar.src avatar ] [] , Username.toHtml username ] , linkTo Route.Logout [ text "Sign out" ] ] Nothing -> [ linkTo Route.Login [ text "Sign in" ] , linkTo Route.Register [ text "Sign up" ] ] viewFooter : Html msg viewFooter = footer [] [ div [ class "container" ] [ a [ class "logo-font", href "/" ] [ text "conduit" ] , span [ class "attribution" ] [ text "An interactive learning project from " , a [ href "https://thinkster.io" ] [ text "Thinkster" ] , text ". Code & design licensed under MIT." ] ] ] navbarLink : Page -> Route -> List (Html msg) -> Html msg navbarLink page route linkContent = li [ classList [ ( "nav-item", True ), ( "active", isActive page route ) ] ] [ a [ class "nav-link", Route.href route ] linkContent ] isActive : Page -> Route -> Bool isActive page route = case ( page, route ) of ( Home, Route.Home ) -> True ( Login, Route.Login ) -> True ( Register, Route.Register ) -> True ( Settings, Route.Settings ) -> True ( Profile pageUsername, Route.Profile routeUsername ) -> pageUsername == routeUsername ( NewArticle, Route.NewArticle ) -> True _ -> False {-| Render dismissable errors. We use this all over the place! -} viewErrors : msg -> List String -> Html msg viewErrors dismissErrors errors = if List.isEmpty errors then Html.text "" else div [ class "error-messages" , style "position" "fixed" , style "top" "0" , style "background" "rgb(250, 250, 250)" , style "padding" "20px" , style "border" "1px solid" ] <| List.map (\error -> p [] [ text error ]) errors ++ [ button [ onClick dismissErrors ] [ text "Ok" ] ]