mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-12-19 19:51:37 +03:00
Use ClickableAttribute helpers
This commit is contained in:
parent
5d1dbdb367
commit
de8903eeee
@ -1,26 +1,50 @@
|
||||
module Nri.Ui.SideNav.V1 exposing
|
||||
( view, Config, Entry
|
||||
, entry, EntryConfig
|
||||
, withBorderStyles
|
||||
( view, Config
|
||||
, entry, Entry
|
||||
, icon, custom, css, nriDescription, testId, id
|
||||
, onClick
|
||||
, href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
||||
, primary, secondary
|
||||
, premiumLevel
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs view, Config, Entry
|
||||
@docs entry, EntryConfig
|
||||
@docs view, Config
|
||||
@docs entry, Entry
|
||||
@docs icon, custom, css, nriDescription, testId, id
|
||||
|
||||
|
||||
## Behavior
|
||||
|
||||
@docs onClick
|
||||
@docs href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
||||
|
||||
|
||||
## Change the color scheme
|
||||
|
||||
@docs primary, secondary
|
||||
|
||||
|
||||
## Change the state
|
||||
|
||||
@docs premiumLevel
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled exposing (..)
|
||||
import ClickableAttributes exposing (ClickableAttributes)
|
||||
import Css exposing (..)
|
||||
import Css.Media as Media
|
||||
import Html.Styled
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import Html.Styled.Events as Events
|
||||
import Nri.Ui
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Data.PremiumLevel as PremiumLevel exposing (PremiumLevel)
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Html.Attributes.V2 as ExtraAttributes
|
||||
import Nri.Ui.Html.V3 exposing (viewJust)
|
||||
import Nri.Ui.Svg.V1 as Svg exposing (Svg)
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
@ -35,20 +59,11 @@ type Entry route msg
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias EntryConfig route msg =
|
||||
{ icon : Maybe Svg
|
||||
, title : String
|
||||
, route : route
|
||||
, attributes : List (Html.Styled.Attribute msg)
|
||||
, children : List (Entry route msg)
|
||||
, premiumLevel : PremiumLevel
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
entry : EntryConfig route msg -> Entry route msg
|
||||
entry =
|
||||
Entry
|
||||
entry : String -> route -> List (Attribute route msg) -> Entry route msg
|
||||
entry title route attributes =
|
||||
attributes
|
||||
|> List.foldl (\(Attribute attribute) b -> attribute b) (build title route)
|
||||
|> Entry
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -106,7 +121,7 @@ viewSidebarEntry : Config route msg -> List Css.Style -> Entry route msg -> Html
|
||||
viewSidebarEntry config extraStyles (Entry entry_) =
|
||||
if PremiumLevel.allowedFor entry_.premiumLevel config.userPremiumLevel then
|
||||
if anyLinkDescendants (.route >> config.isCurrentRoute) entry_ then
|
||||
div [ css extraStyles ]
|
||||
div [ Attributes.css extraStyles ]
|
||||
(styled span
|
||||
(sharedEntryStyles
|
||||
++ [ backgroundColor Colors.gray92
|
||||
@ -139,11 +154,16 @@ viewSidebarLeaf :
|
||||
-> List Style
|
||||
-> EntryConfig route msg
|
||||
-> Html msg
|
||||
viewSidebarLeaf config extraStyles { icon, title, route, attributes } =
|
||||
styled Html.Styled.a
|
||||
viewSidebarLeaf config extraStyles entryConfig =
|
||||
let
|
||||
( linkFunctionName, attributes ) =
|
||||
ClickableAttributes.toLinkAttributes entryConfig.clickableAttributes
|
||||
in
|
||||
Nri.Ui.styled Html.Styled.a
|
||||
("Nri-Ui-SideNav-" ++ linkFunctionName)
|
||||
(sharedEntryStyles
|
||||
++ extraStyles
|
||||
++ (if config.isCurrentRoute route then
|
||||
++ (if config.isCurrentRoute entryConfig.route then
|
||||
[ backgroundColor Colors.glacier
|
||||
, color Colors.navy
|
||||
, fontWeight bold
|
||||
@ -153,8 +173,9 @@ viewSidebarLeaf config extraStyles { icon, title, route, attributes } =
|
||||
else
|
||||
[]
|
||||
)
|
||||
++ entryConfig.customStyles
|
||||
)
|
||||
attributes
|
||||
(attributes ++ entryConfig.customAttributes)
|
||||
[ viewJust
|
||||
(\icon_ ->
|
||||
icon_
|
||||
@ -163,8 +184,8 @@ viewSidebarLeaf config extraStyles { icon, title, route, attributes } =
|
||||
|> Svg.withCss [ marginRight (px 5) ]
|
||||
|> Svg.toHtml
|
||||
)
|
||||
icon
|
||||
, text title
|
||||
entryConfig.icon
|
||||
, text entryConfig.title
|
||||
]
|
||||
|
||||
|
||||
@ -212,10 +233,177 @@ sharedEntryStyles =
|
||||
]
|
||||
|
||||
|
||||
withBorderStyles : List Style
|
||||
withBorderStyles =
|
||||
-- TODO: add a convenient way to use these styels
|
||||
[ backgroundColor Colors.white
|
||||
, boxShadow3 zero (px 2) Colors.gray75
|
||||
, border3 (px 1) solid Colors.gray75
|
||||
]
|
||||
|
||||
-- Entry Customization helpers
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias EntryConfig route msg =
|
||||
{ icon : Maybe Svg
|
||||
, title : String
|
||||
, route : route
|
||||
, clickableAttributes : ClickableAttributes msg
|
||||
, customAttributes : List (Html.Styled.Attribute msg)
|
||||
, customStyles : List Style
|
||||
, children : List (Entry route msg)
|
||||
, premiumLevel : PremiumLevel
|
||||
}
|
||||
|
||||
|
||||
build : String -> route -> EntryConfig route msg
|
||||
build title route =
|
||||
{ icon = Nothing
|
||||
, title = title
|
||||
, route = route
|
||||
, clickableAttributes = ClickableAttributes.init
|
||||
, customAttributes = []
|
||||
, customStyles = []
|
||||
, children = []
|
||||
, premiumLevel = PremiumLevel.Free
|
||||
}
|
||||
|
||||
|
||||
type Attribute route msg
|
||||
= Attribute (EntryConfig route msg -> EntryConfig route msg)
|
||||
|
||||
|
||||
{-| -}
|
||||
icon : Svg -> Attribute route msg
|
||||
icon icon_ =
|
||||
Attribute (\attributes -> { attributes | icon = Just icon_ })
|
||||
|
||||
|
||||
{-| -}
|
||||
premiumLevel : PremiumLevel -> msg -> Attribute route msg
|
||||
premiumLevel level ifLocked =
|
||||
-- TODO: adds the lock click behavior
|
||||
Attribute (\attributes -> { attributes | premiumLevel = level })
|
||||
|
||||
|
||||
{-| Use this helper to add custom attributes.
|
||||
|
||||
Do NOT use this helper to add css styles, as they may not be applied the way
|
||||
you want/expect if underlying Button styles change.
|
||||
Instead, please use the `css` helper.
|
||||
|
||||
-}
|
||||
custom : List (Html.Styled.Attribute msg) -> Attribute route msg
|
||||
custom attributes =
|
||||
Attribute
|
||||
(\config ->
|
||||
{ config
|
||||
| customAttributes = List.append config.customAttributes attributes
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
nriDescription : String -> Attribute route msg
|
||||
nriDescription description =
|
||||
custom [ ExtraAttributes.nriDescription description ]
|
||||
|
||||
|
||||
{-| -}
|
||||
testId : String -> Attribute route msg
|
||||
testId id_ =
|
||||
custom [ ExtraAttributes.testId id_ ]
|
||||
|
||||
|
||||
{-| -}
|
||||
id : String -> Attribute route msg
|
||||
id id_ =
|
||||
custom [ Attributes.id id_ ]
|
||||
|
||||
|
||||
{-| -}
|
||||
css : List Style -> Attribute route msg
|
||||
css styles =
|
||||
Attribute
|
||||
(\config ->
|
||||
{ config
|
||||
| customStyles = List.append config.customStyles styles
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
primary : Attribute route msg
|
||||
primary =
|
||||
Attribute (\attributes -> { attributes | customStyles = [] })
|
||||
|
||||
|
||||
{-| -}
|
||||
secondary : Attribute route msg
|
||||
secondary =
|
||||
Attribute
|
||||
(\attributes ->
|
||||
{ attributes
|
||||
| customStyles =
|
||||
[ backgroundColor Colors.white
|
||||
, boxShadow3 zero (px 2) Colors.gray75
|
||||
, border3 (px 1) solid Colors.gray75
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- LINKING, CLICKING, and TRACKING BEHAVIOR
|
||||
|
||||
|
||||
setClickableAttributes :
|
||||
(ClickableAttributes msg -> ClickableAttributes msg)
|
||||
-> Attribute route msg
|
||||
setClickableAttributes apply =
|
||||
Attribute
|
||||
(\attributes ->
|
||||
{ attributes | clickableAttributes = apply attributes.clickableAttributes }
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
onClick : msg -> Attribute route msg
|
||||
onClick msg =
|
||||
setClickableAttributes (ClickableAttributes.onClick msg)
|
||||
|
||||
|
||||
{-| -}
|
||||
href : String -> Attribute route msg
|
||||
href url =
|
||||
setClickableAttributes (ClickableAttributes.href url)
|
||||
|
||||
|
||||
{-| Use this link for routing within a single page app.
|
||||
|
||||
This will make a normal <a> tag, but change the Events.onClick behavior to avoid reloading the page.
|
||||
|
||||
See <https://github.com/elm-lang/html/issues/110> for details on this implementation.
|
||||
|
||||
-}
|
||||
linkSpa : String -> Attribute route msg
|
||||
linkSpa url =
|
||||
setClickableAttributes (ClickableAttributes.linkSpa url)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkWithMethod : { method : String, url : String } -> Attribute route msg
|
||||
linkWithMethod config =
|
||||
setClickableAttributes (ClickableAttributes.linkWithMethod config)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkWithTracking : { track : msg, url : String } -> Attribute route msg
|
||||
linkWithTracking config =
|
||||
setClickableAttributes (ClickableAttributes.linkWithTracking config)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkExternal : String -> Attribute route msg
|
||||
linkExternal url =
|
||||
setClickableAttributes (ClickableAttributes.linkExternal url)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkExternalWithTracking : { track : msg, url : String } -> Attribute route msg
|
||||
linkExternalWithTracking config =
|
||||
setClickableAttributes (ClickableAttributes.linkExternalWithTracking config)
|
||||
|
@ -226,46 +226,34 @@ viewPreviews containerId examples =
|
||||
navigation : Route -> Html Msg
|
||||
navigation currentRoute =
|
||||
let
|
||||
toNavLinkConfig : Category -> SideNav.EntryConfig Route Msg
|
||||
toNavLinkConfig : Category -> SideNav.Entry Route Msg
|
||||
toNavLinkConfig category =
|
||||
{ icon = Nothing
|
||||
, title = Category.forDisplay category
|
||||
, route = Routes.Category category
|
||||
, attributes = [ href (Routes.toString (Routes.Category category)) ]
|
||||
, children = []
|
||||
, premiumLevel = PremiumLevel.Free
|
||||
}
|
||||
SideNav.entry
|
||||
(Category.forDisplay category)
|
||||
(Routes.Category category)
|
||||
[ -- TODO: we shouldn't require manually adding the href
|
||||
SideNav.href (Routes.toString (Routes.Category category))
|
||||
]
|
||||
|
||||
navLinks : List (SideNav.Entry Route Msg)
|
||||
navLinks =
|
||||
SideNav.entry
|
||||
{ icon = Nothing
|
||||
, title = "All"
|
||||
, route = Routes.All
|
||||
, attributes = [ href (Routes.toString Routes.All) ]
|
||||
, children = []
|
||||
, premiumLevel = PremiumLevel.Free
|
||||
}
|
||||
:: List.map (toNavLinkConfig >> SideNav.entry) Category.all
|
||||
++ [ SideNav.entry
|
||||
{ icon = Nothing
|
||||
, title = "Example of Locked Premium content"
|
||||
, route = Routes.All
|
||||
, attributes = [ href (Routes.toString Routes.All) ]
|
||||
, children = []
|
||||
, premiumLevel = PremiumLevel.PremiumWithWriting
|
||||
}
|
||||
, SideNav.entry
|
||||
{ icon = Just UiIcon.gear
|
||||
, title = "Create your own"
|
||||
, route = Routes.All
|
||||
, attributes =
|
||||
[ href (Routes.toString Routes.All)
|
||||
, css SideNav.withBorderStyles
|
||||
]
|
||||
, children = []
|
||||
, premiumLevel = PremiumLevel.Free
|
||||
}
|
||||
SideNav.entry "All"
|
||||
Routes.All
|
||||
[ SideNav.href (Routes.toString Routes.All)
|
||||
]
|
||||
:: List.map toNavLinkConfig Category.all
|
||||
++ [ SideNav.entry "Example of Locked Premium content"
|
||||
Routes.All
|
||||
[ SideNav.premiumLevel PremiumLevel.PremiumWithWriting
|
||||
NoOp
|
||||
]
|
||||
, SideNav.entry "Create your own"
|
||||
-- TODO: support _no_ route
|
||||
Routes.All
|
||||
[ SideNav.icon UiIcon.gear
|
||||
, SideNav.secondary
|
||||
, SideNav.linkExternal "external-link"
|
||||
]
|
||||
]
|
||||
in
|
||||
SideNav.view
|
||||
|
Loading…
Reference in New Issue
Block a user