-
-
Save rtfeldman/5b680c64be829c6dbd78c073c269d313 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Views.Page exposing (ActivePage(..), bodyId, frame) | |
{-| The frame around a typical page - that is, the header and footer. | |
-} | |
import Color | |
import Data.User as User exposing (User, Username) | |
import Data.UserPhoto as UserPhoto exposing (UserPhoto) | |
import Element exposing (Element, el) | |
import Element.Attributes exposing (alignBottom, alignLeft, justify, paddingXY, spacing, spacingXY, verticalCenter) | |
import Html | |
import Html.Attributes exposing (..) | |
import Html.Lazy exposing (lazy2) | |
import Route exposing (Route) | |
import Style exposing (..) | |
import Style.Border as Border | |
import Style.Color as Color | |
import Style.Font as Font | |
import Style.Transition as Transition | |
import Util exposing ((=>)) | |
import Views.Spinner exposing (spinner) | |
{-| 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 ActivePage | |
= Other | |
| Home | |
| Login | |
| Register | |
| Settings | |
| Profile Username | |
| NewArticle | |
{-| Take a page's Html and frame 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.) | |
-} | |
frame : Bool -> Maybe User -> ActivePage -> Html msg -> Html msg | |
frame isLoading user page content = | |
div [ class "page-frame" ] | |
[ viewHeader page user isLoading | |
, content | |
, viewFooter | |
] | |
viewHeader : ActivePage -> Maybe User -> Bool -> Html msg | |
viewHeader page user isLoading = | |
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" ] <| | |
lazy2 Util.viewIf isLoading spinner | |
:: navbarLink (page == Home) Route.Home [ text "Home" ] | |
:: viewSignIn page user | |
] | |
] | |
viewSignIn : ActivePage -> Maybe User -> List (Html msg) | |
viewSignIn page user = | |
case user of | |
Nothing -> | |
[ navbarLink (page == Login) Route.Login [ text "Sign in" ] | |
, navbarLink (page == Register) Route.Register [ text "Sign up" ] | |
] | |
Just user -> | |
[ navbarLink (page == NewArticle) Route.NewArticle [ i [ class "ion-compose" ] [], text " New Post" ] | |
, navbarLink (page == Settings) Route.Settings [ i [ class "ion-gear-a" ] [], text " Settings" ] | |
, navbarLink | |
(page == Profile user.username) | |
(Route.Profile user.username) | |
[ img [ class "user-pic", UserPhoto.src user.image ] [] | |
, User.usernameToHtml user.username | |
] | |
, navbarLink False Route.Logout [ text "Sign out" ] | |
] | |
type alias Elem msg = | |
Html msg | |
row = | |
Debug.crash "TODO" | |
link = | |
Debug.crash "TODO" | |
paragraph = | |
Debug.crash "TODO" | |
unstyled = | |
Debug.crash "TODO" | |
style = | |
Debug.crash "TODO" | |
text = | |
Debug.crash "TODO" | |
-- By default, name the styled *element* rather than the style itself. | |
-- If a style will be reused across different elements, name the reusable style. | |
logoLink : String -> Elem msg -> Elem msg | |
logoLink = | |
link <| | |
style | |
[ Color.text (Color.rgb 92 184 92) | |
, Font.typeface [ "Titillium Web", "sans-serif" ] | |
, Font.size 16 | |
] | |
attributionParagraph : List (Elem msg) -> Elem msg | |
attributionParagraph = | |
paragraph [] <| | |
style [ Color.text (Color.rgb 187 187 187) ] | |
footerRow : List (Elem msg) -> Elem msg | |
footerRow = | |
let | |
footerStyle = | |
Style.style | |
[ Color.background (Color.rgb 243 243 243) | |
, Font.typeface [ "Source Sans Pro", "sans-serif" ] | |
, Font.size 12 | |
] | |
in | |
Element.footer footerStyle [ verticalCenter, spacing 10, paddingXY 77.5 21 ] | |
<style>.acb234 { } </style> | |
button [ onClick Foo ] [ text "blah" ] | |
button Foo [] [ text "blah" ] | |
footerLink : String -> Elem msg -> Elem msg | |
footerLink = | |
link <| | |
style | |
[ Color.text (Color.rgb 92 184 92) | |
, Font.typeface [ "Titillium Web", "sans-serif" ] | |
] | |
plainLink : String -> Elem msg -> Elem msg | |
plainLink = | |
link unstyled | |
viewFooter : Elem msg | |
viewFooter = | |
footerRow <| | |
[ text "conduit" |> logoLink "/" | |
, attributionParagraph | |
[ text "An interactive learning project from " | |
, text "Thinkster" |> footerLink "https://thinkster.io" | |
, text ". Code & design licensed under MIT." | |
] | |
] | |
viewFooter2 = | |
row Footer | |
[ verticalCenter, spacing 10, paddingXY 77.5 21 ] | |
[ link "/" (el Logo [] (text "conduit")) | |
, paragraph Attribution | |
[] | |
[ text "An interactive learning project from " | |
, link "https://thinkster.io" <| | |
el Link [] (text "Thinkster") | |
, text ". Code & design licensed under MIT." | |
] | |
] | |
-- `variation` can work like `classList` - give it a list of ( Style, Bool ) | |
-- pairs. It will always generate the class for the Style, but it will either | |
-- include it (or not) in the element's `class` atrtibute based on the `Bool`. | |
-- | |
-- | |
-- | |
-- logoStyle : Element msg -> Element msg | |
-- logoStyle = | |
-- style | |
-- [ Color.text (Color.rgb 92 184 92) | |
-- , Font.typeface [ "Titillium Web", "sans-serif" ] | |
-- , Font.size 16 | |
-- ] | |
-- | |
-- | |
-- footerStyle : Element msg -> Element msg | |
-- footerStyle = | |
-- style | |
-- [ Color.background (Color.rgb 243 243 243) | |
-- , Font.typeface [ "Source Sans Pro", "sans-serif" ] | |
-- , Font.size 12 | |
-- ] | |
-- | |
-- Design note: each Element contains a Dict of styles, keyed on hash of css. | |
-- When using an element combinator, or applying children to a given element, | |
-- those dicts get unioned together (ignoring duplicates). In this way, | |
-- once we get to the root, we just have all the styles already and can go for it. | |
-- Can use a checksum to avoid regenerating <style>. | |
-- | |
-- NOTE: for semantic purposes, there'd be no reason ever to use <button> - | |
-- except that we know things about buttons! They always have onClick. Same way | |
-- <input> always has onInput and defaultValue [hope hope hope it's value later] | |
-- So why not have the button API be: button : msg -> Element msg -> Element msg | |
-- and do the onClick automatically? EXACTLY! Do that! Now it's more convenient | |
-- than using <el> or whatever. And it's more semantic! Wins all around. Also, | |
-- if we detect that a <button> is inside a <form>, we should not submit | |
-- that <form> automatically. | |
-- | |
-- OTHER questions: what about tabIndex? Is there some cool way we can do that | |
-- automatically? Seems unlikely, unfortunately. | |
-- TODO make it so on /settings the footer is glued to the bottom of the page, even if there's no content in between | |
type Styles | |
= None | |
| Footer | |
| Logo | |
| Attribution | |
| Link | |
| ActiveNavItem | |
| NavItem | |
stylesheet : StyleSheet Styles variation | |
stylesheet = | |
Style.stylesheet | |
[ Style.style None [] | |
, Style.style Logo | |
[ Color.text (Color.rgb 92 184 92) | |
, Font.typeface [ "Titillium Web", "sans-serif" ] | |
, Font.size 16 | |
] | |
, Style.style Footer | |
[ Color.background (Color.rgb 243 243 243) | |
, Font.typeface [ "Source Sans Pro", "sans-serif" ] | |
, Font.size 12 | |
] | |
, Style.style Attribution | |
[ Color.text (Color.rgb 187 187 187) ] | |
, Style.style Link | |
[ Color.text (Color.rgb 92 184 92) | |
, cursor "pointer" | |
, hover | |
[ Color.text (Color.rgb 61 139 61) | |
] | |
] | |
] | |
navbarLink : Bool -> Route -> Element Styles variation msg -> Element Styles variation msg | |
navbarLink isActive route linkContent = | |
let | |
activeStyle = | |
if isActive then | |
ActiveNavItem | |
else | |
NavItem | |
in | |
Element.link (Route.toUrl route) <| | |
el activeStyle [] linkContent | |
navbarLink2 : Bool -> Route -> List (Html msg) -> Html msg | |
navbarLink2 isActive route linkContent = | |
li [ classList [ ( "nav-item", True ), ( "active", isActive ) ] ] | |
[ a [ class "nav-link", Route.href route ] linkContent ] | |
{-| This id comes from index.html. | |
The Feed uses it to scroll to the top of the page (by ID) when switching pages | |
in the pagination sense. | |
-} | |
bodyId : String | |
bodyId = | |
"page-body" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment