mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-11-22 23:30:42 +03:00
Merge pull request #993 from NoRedInk/tessa/togglable-sidenav
Tessa/togglable sidenav
This commit is contained in:
commit
32350457db
@ -1,6 +1,7 @@
|
||||
Nri.Ui.Accordion.V1,upgrade to V3
|
||||
Nri.Ui.Heading.V2,upgrade to V3
|
||||
Nri.Ui.Menu.V1,upgrade to V3
|
||||
Nri.Ui.SideNav.V3,upgrade to V4
|
||||
Nri.Ui.SortableTable.V2,upgrade to V3
|
||||
Nri.Ui.Table.V5,upgrade to V6
|
||||
Nri.Ui.Tabs.V6,upgrade to V7
|
||||
|
|
1
elm.json
1
elm.json
@ -51,6 +51,7 @@
|
||||
"Nri.Ui.Select.V8",
|
||||
"Nri.Ui.Shadows.V1",
|
||||
"Nri.Ui.SideNav.V3",
|
||||
"Nri.Ui.SideNav.V4",
|
||||
"Nri.Ui.SortableTable.V2",
|
||||
"Nri.Ui.SortableTable.V3",
|
||||
"Nri.Ui.Sprite.V1",
|
||||
|
@ -117,6 +117,9 @@ hint = 'upgrade to V3'
|
||||
[forbidden."Nri.Ui.SideNav.V2"]
|
||||
hint = 'upgrade to V3'
|
||||
|
||||
[forbidden."Nri.Ui.SideNav.V3"]
|
||||
hint = 'upgrade to V4'
|
||||
|
||||
[forbidden."Nri.Ui.SortableTable.V2"]
|
||||
hint = 'upgrade to V3'
|
||||
|
||||
|
@ -6,9 +6,10 @@ module Nri.Ui.ClickableSvg.V2 exposing
|
||||
, exactSize, exactWidth, exactHeight
|
||||
, disabled
|
||||
, withBorder
|
||||
, primary, secondary, danger, dangerSecondary
|
||||
, primary, secondary, tertiary, danger, dangerSecondary
|
||||
, custom, nriDescription, testId, id
|
||||
, css, notMobileCss, mobileCss, quizEngineMobileCss
|
||||
, iconForMobile
|
||||
, small, medium, large
|
||||
)
|
||||
|
||||
@ -18,6 +19,7 @@ module Nri.Ui.ClickableSvg.V2 exposing
|
||||
# Patch changes:
|
||||
|
||||
- adds `nriDescription`, `testId`, and `id` helpers
|
||||
- adds `iconForMobile`
|
||||
|
||||
|
||||
# Create a button or link
|
||||
@ -45,7 +47,7 @@ module Nri.Ui.ClickableSvg.V2 exposing
|
||||
## Customization
|
||||
|
||||
@docs withBorder
|
||||
@docs primary, secondary, danger, dangerSecondary
|
||||
@docs primary, secondary, tertiary, danger, dangerSecondary
|
||||
|
||||
@docs custom, nriDescription, testId, id
|
||||
|
||||
@ -53,6 +55,7 @@ module Nri.Ui.ClickableSvg.V2 exposing
|
||||
### CSS
|
||||
|
||||
@docs css, notMobileCss, mobileCss, quizEngineMobileCss
|
||||
@docs iconForMobile
|
||||
|
||||
|
||||
### DEPRECATED
|
||||
@ -247,6 +250,7 @@ withBorder =
|
||||
type Theme
|
||||
= Primary
|
||||
| Secondary
|
||||
| Tertiary
|
||||
| Danger
|
||||
| DangerSecondary
|
||||
|
||||
@ -257,7 +261,9 @@ type alias AppliedTheme =
|
||||
, background : Color
|
||||
, backgroundHovered : Color
|
||||
, includeBorder : Bool
|
||||
, borderColor : Color
|
||||
, borderBottom : Color
|
||||
, borderHover : Color
|
||||
}
|
||||
|
||||
|
||||
@ -268,7 +274,9 @@ disabledTheme =
|
||||
, background = Colors.white
|
||||
, backgroundHovered = Colors.white
|
||||
, includeBorder = True
|
||||
, borderColor = Colors.gray75
|
||||
, borderBottom = Colors.gray75
|
||||
, borderHover = Colors.gray75
|
||||
}
|
||||
|
||||
|
||||
@ -281,7 +289,9 @@ applyTheme theme =
|
||||
, background = Colors.azure
|
||||
, backgroundHovered = Colors.azureDark
|
||||
, includeBorder = False
|
||||
, borderColor = Colors.white
|
||||
, borderBottom = Colors.azureDark
|
||||
, borderHover = Colors.azureDark
|
||||
}
|
||||
|
||||
Secondary ->
|
||||
@ -290,7 +300,20 @@ applyTheme theme =
|
||||
, background = Colors.white
|
||||
, backgroundHovered = Colors.glacier
|
||||
, includeBorder = True
|
||||
, borderColor = Colors.azure
|
||||
, borderBottom = Colors.azure
|
||||
, borderHover = Colors.azure
|
||||
}
|
||||
|
||||
Tertiary ->
|
||||
{ main_ = Colors.gray45
|
||||
, mainHovered = Colors.azure
|
||||
, background = Colors.gray96
|
||||
, backgroundHovered = Colors.glacier
|
||||
, includeBorder = True
|
||||
, borderColor = Colors.gray92
|
||||
, borderBottom = Colors.gray92
|
||||
, borderHover = Colors.azure
|
||||
}
|
||||
|
||||
Danger ->
|
||||
@ -299,7 +322,9 @@ applyTheme theme =
|
||||
, background = Colors.red
|
||||
, backgroundHovered = Colors.redDark
|
||||
, includeBorder = False
|
||||
, borderColor = Colors.white
|
||||
, borderBottom = Colors.redDark
|
||||
, borderHover = Colors.redDark
|
||||
}
|
||||
|
||||
DangerSecondary ->
|
||||
@ -308,7 +333,9 @@ applyTheme theme =
|
||||
, background = Colors.white
|
||||
, backgroundHovered = Colors.redLight
|
||||
, includeBorder = True
|
||||
, borderColor = Colors.red
|
||||
, borderBottom = Colors.red
|
||||
, borderHover = Colors.red
|
||||
}
|
||||
|
||||
|
||||
@ -327,6 +354,13 @@ secondary =
|
||||
set (\attributes -> { attributes | theme = Secondary })
|
||||
|
||||
|
||||
{-| Used to de-emphasize elements when not hovered.
|
||||
-}
|
||||
tertiary : Attribute msg
|
||||
tertiary =
|
||||
set (\attributes -> { attributes | theme = Tertiary })
|
||||
|
||||
|
||||
{-| White/transparent icon on a red background.
|
||||
-}
|
||||
danger : Attribute msg
|
||||
@ -420,6 +454,12 @@ quizEngineMobileCss styles =
|
||||
css [ Css.Media.withMedia [ MediaQuery.quizEngineMobile ] styles ]
|
||||
|
||||
|
||||
{-| -}
|
||||
iconForMobile : Svg -> Attribute msg
|
||||
iconForMobile icon =
|
||||
set (\config -> { config | iconForMobile = Just icon })
|
||||
|
||||
|
||||
|
||||
-- INTERNALS
|
||||
|
||||
@ -437,6 +477,7 @@ build label icon =
|
||||
{ clickableAttributes = ClickableAttributes.init
|
||||
, label = label
|
||||
, icon = icon
|
||||
, iconForMobile = Nothing
|
||||
, disabled = False
|
||||
, size = Small
|
||||
, width = Nothing
|
||||
@ -456,6 +497,7 @@ type alias ButtonOrLinkAttributes msg =
|
||||
{ clickableAttributes : ClickableAttributes String msg
|
||||
, label : String
|
||||
, icon : Svg
|
||||
, iconForMobile : Maybe Svg
|
||||
, disabled : Bool
|
||||
, size : Size
|
||||
, width : Maybe Float
|
||||
@ -487,8 +529,7 @@ renderButton ((ButtonOrLink config) as button_) =
|
||||
++ ClickableAttributes.toButtonAttributes config.clickableAttributes
|
||||
++ config.customAttributes
|
||||
)
|
||||
[ renderIcon config theme.includeBorder
|
||||
]
|
||||
(renderIcons config theme.includeBorder)
|
||||
|
||||
|
||||
renderLink : ButtonOrLink msg -> Html msg
|
||||
@ -522,12 +563,11 @@ renderLink ((ButtonOrLink config) as link_) =
|
||||
)
|
||||
++ config.customAttributes
|
||||
)
|
||||
[ renderIcon config theme.includeBorder
|
||||
]
|
||||
(renderIcons config theme.includeBorder)
|
||||
|
||||
|
||||
renderIcon : ButtonOrLinkAttributes msg -> Bool -> Html msg
|
||||
renderIcon config includeBorder =
|
||||
renderIcons : ButtonOrLinkAttributes msg -> Bool -> List (Html msg)
|
||||
renderIcons config includeBorder =
|
||||
let
|
||||
size =
|
||||
getSize config.size
|
||||
@ -556,20 +596,43 @@ renderIcon config includeBorder =
|
||||
|
||||
else
|
||||
Maybe.withDefault size config.height
|
||||
in
|
||||
config.icon
|
||||
|> Svg.withCss
|
||||
|
||||
iconStyles =
|
||||
[ Css.displayFlex
|
||||
, Css.maxWidth (Css.px iconWidth)
|
||||
, Css.maxHeight (Css.px iconHeight)
|
||||
, Css.height (Css.pct 100)
|
||||
, Css.margin Css.auto
|
||||
]
|
||||
|> Svg.toHtml
|
||||
|
||||
hideFor breakpoint =
|
||||
Svg.withCss
|
||||
[ Css.Media.withMedia [ breakpoint ]
|
||||
[ Css.display Css.none
|
||||
]
|
||||
]
|
||||
in
|
||||
case config.iconForMobile of
|
||||
Just iconForMobile_ ->
|
||||
[ config.icon
|
||||
|> Svg.withCss iconStyles
|
||||
|> hideFor MediaQuery.mobile
|
||||
|> Svg.toHtml
|
||||
, iconForMobile_
|
||||
|> Svg.withCss iconStyles
|
||||
|> hideFor MediaQuery.notMobile
|
||||
|> Svg.toHtml
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
[ config.icon
|
||||
|> Svg.withCss iconStyles
|
||||
|> Svg.toHtml
|
||||
]
|
||||
|
||||
|
||||
buttonOrLinkStyles : ButtonOrLinkAttributes msg -> AppliedTheme -> List Style
|
||||
buttonOrLinkStyles config { main_, mainHovered, background, backgroundHovered, borderBottom, includeBorder } =
|
||||
buttonOrLinkStyles config { main_, mainHovered, background, backgroundHovered, borderColor, borderBottom, borderHover, includeBorder } =
|
||||
let
|
||||
cursor =
|
||||
if config.disabled then
|
||||
@ -600,7 +663,7 @@ buttonOrLinkStyles config { main_, mainHovered, background, backgroundHovered, b
|
||||
, Css.batch <|
|
||||
if config.hasBorder then
|
||||
[ Css.borderRadius (Css.px 8)
|
||||
, Css.borderColor main_
|
||||
, Css.borderColor borderColor
|
||||
, Css.borderBottomColor borderBottom
|
||||
, Css.borderStyle Css.solid
|
||||
, if includeBorder then
|
||||
@ -615,7 +678,7 @@ buttonOrLinkStyles config { main_, mainHovered, background, backgroundHovered, b
|
||||
, Css.borderBottomWidth (Css.px bordersAndPadding.bottomBorder)
|
||||
, Css.backgroundColor background
|
||||
, Css.hover
|
||||
[ Css.borderColor borderBottom
|
||||
[ Css.borderColor borderHover
|
||||
, Css.backgroundColor backgroundHovered
|
||||
]
|
||||
, Css.padding4
|
||||
|
@ -17,10 +17,10 @@ Changes from V1:
|
||||
-}
|
||||
|
||||
import Css exposing (Color)
|
||||
import Css.Media exposing (withMediaQuery)
|
||||
import Html.Styled as Html
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.MediaQuery.V1 as MediaQuery
|
||||
import Particle exposing (Particle)
|
||||
import Particle.System as ParticleSystem
|
||||
import Random exposing (Generator)
|
||||
@ -68,8 +68,7 @@ view (System system _) =
|
||||
, Css.width (Css.pct 100)
|
||||
, Css.height (Css.vh 100)
|
||||
, Css.pointerEvents Css.none
|
||||
, withMediaQuery [ "(prefers-reduced-motion)" ]
|
||||
[ Css.display Css.none ]
|
||||
, MediaQuery.prefersReducedMotion [ Css.display Css.none ]
|
||||
]
|
||||
]
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
module Nri.Ui.MediaQuery.V1 exposing
|
||||
( mobile, notMobile
|
||||
( anyMotion, prefersReducedMotion
|
||||
, mobile, notMobile
|
||||
, mobileBreakpoint
|
||||
, quizEngineMobile
|
||||
, quizEngineBreakpoint
|
||||
@ -20,6 +21,8 @@ module Nri.Ui.MediaQuery.V1 exposing
|
||||
[ Css.padding (Css.px 2)
|
||||
]
|
||||
|
||||
@docs anyMotion, prefersReducedMotion
|
||||
|
||||
@docs mobile, notMobile
|
||||
@docs mobileBreakpoint
|
||||
|
||||
@ -31,8 +34,20 @@ module Nri.Ui.MediaQuery.V1 exposing
|
||||
|
||||
-}
|
||||
|
||||
import Css exposing (px)
|
||||
import Css.Media exposing (MediaQuery, maxWidth, minWidth, only, screen)
|
||||
import Css exposing (Style, px)
|
||||
import Css.Media exposing (MediaQuery, maxWidth, minWidth, only, screen, withMediaQuery)
|
||||
|
||||
|
||||
{-| -}
|
||||
anyMotion : List Style -> Style
|
||||
anyMotion =
|
||||
withMediaQuery [ "(prefers-reduced-motion: no-preference)" ]
|
||||
|
||||
|
||||
{-| -}
|
||||
prefersReducedMotion : List Style -> Style
|
||||
prefersReducedMotion =
|
||||
withMediaQuery [ "(prefers-reduced-motion)" ]
|
||||
|
||||
|
||||
{-| Styles using the `mobileBreakpoint` value as the maxWidth.
|
||||
|
674
src/Nri/Ui/SideNav/V4.elm
Normal file
674
src/Nri/Ui/SideNav/V4.elm
Normal file
@ -0,0 +1,674 @@
|
||||
module Nri.Ui.SideNav.V4 exposing
|
||||
( view, Config, NavAttribute
|
||||
, collapsible
|
||||
, navLabel, navId
|
||||
, navCss, navNotMobileCss, navMobileCss, navQuizEngineMobileCss
|
||||
, entry, entryWithChildren, html, Entry, Attribute
|
||||
, icon, custom, css, nriDescription, testId, id
|
||||
, onClick
|
||||
, href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
||||
, primary, secondary
|
||||
, premiumDisplay
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
|
||||
# Changes from V3
|
||||
|
||||
- make the nav configurably collapsible
|
||||
|
||||
@docs view, Config, NavAttribute
|
||||
@docs collapsible
|
||||
@docs navLabel, navId
|
||||
@docs navCss, navNotMobileCss, navMobileCss, navQuizEngineMobileCss
|
||||
|
||||
|
||||
## Entries
|
||||
|
||||
@docs entry, entryWithChildren, html, Entry, Attribute
|
||||
@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 premiumDisplay
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled exposing (..)
|
||||
import Accessibility.Styled.Aria as Aria
|
||||
import Accessibility.Styled.Style as Style
|
||||
import ClickableAttributes exposing (ClickableAttributes)
|
||||
import Css exposing (..)
|
||||
import Css.Media
|
||||
import Html.Styled
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Html.Styled.Events as Events
|
||||
import Nri.Ui
|
||||
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Data.PremiumDisplay as PremiumDisplay exposing (PremiumDisplay)
|
||||
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.MediaQuery.V1 as MediaQuery
|
||||
import Nri.Ui.Svg.V1 as Svg exposing (Svg)
|
||||
import Nri.Ui.Tooltip.V3 as Tooltip
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
|
||||
|
||||
{-| Use `entry` to create a sidebar entry.
|
||||
-}
|
||||
type Entry route msg
|
||||
= Entry (List (Entry route msg)) (EntryConfig route msg)
|
||||
| Html (List (Html msg))
|
||||
|
||||
|
||||
{-| -}
|
||||
entry : String -> List (Attribute route msg) -> Entry route msg
|
||||
entry title attributes =
|
||||
attributes
|
||||
|> List.foldl (\(Attribute attribute) b -> attribute b) (build title)
|
||||
|> Entry []
|
||||
|
||||
|
||||
{-| -}
|
||||
entryWithChildren : String -> List (Attribute route msg) -> List (Entry route msg) -> Entry route msg
|
||||
entryWithChildren title attributes children =
|
||||
attributes
|
||||
|> List.foldl (\(Attribute attribute) b -> attribute b) (build title)
|
||||
|> Entry children
|
||||
|
||||
|
||||
{-| -}
|
||||
html : List (Html msg) -> Entry route msg
|
||||
html =
|
||||
Html
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias Config route msg =
|
||||
{ isCurrentRoute : route -> Bool
|
||||
, routeToString : route -> String
|
||||
, onSkipNav : msg
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
type NavAttribute msg
|
||||
= NavAttribute (NavAttributeConfig msg -> NavAttributeConfig msg)
|
||||
|
||||
|
||||
type alias NavAttributeConfig msg =
|
||||
{ navLabel : Maybe String
|
||||
, navId : Maybe String
|
||||
, css : List Style
|
||||
, collapsible : Maybe (CollapsibleConfig msg)
|
||||
}
|
||||
|
||||
|
||||
defaultNavAttributeConfig : NavAttributeConfig msg
|
||||
defaultNavAttributeConfig =
|
||||
{ navLabel = Nothing
|
||||
, navId = Nothing
|
||||
, css = []
|
||||
, collapsible = Nothing
|
||||
}
|
||||
|
||||
|
||||
{-| Give screenreader users context on what this particular sidenav is for.
|
||||
|
||||
If the nav is collapsible, this value will also be used for the sidenav tooltips.
|
||||
|
||||
-}
|
||||
navLabel : String -> NavAttribute msg
|
||||
navLabel str =
|
||||
NavAttribute (\config -> { config | navLabel = Just str })
|
||||
|
||||
|
||||
{-| -}
|
||||
navId : String -> NavAttribute msg
|
||||
navId str =
|
||||
NavAttribute (\config -> { config | navId = Just str })
|
||||
|
||||
|
||||
{-| These styles are included automatically in the nav container:
|
||||
|
||||
[ flexBasis (px 250)
|
||||
, flexShrink (num 0)
|
||||
, borderRadius (px 8)
|
||||
, backgroundColor Colors.gray96
|
||||
, padding (px 20)
|
||||
, marginRight (px 20)
|
||||
]
|
||||
|
||||
-}
|
||||
navCss : List Style -> NavAttribute msg
|
||||
navCss styles =
|
||||
NavAttribute (\config -> { config | css = List.append config.css styles })
|
||||
|
||||
|
||||
{-| -}
|
||||
navNotMobileCss : List Style -> NavAttribute msg
|
||||
navNotMobileCss styles =
|
||||
navCss [ Css.Media.withMedia [ MediaQuery.notMobile ] styles ]
|
||||
|
||||
|
||||
{-| -}
|
||||
navMobileCss : List Style -> NavAttribute msg
|
||||
navMobileCss styles =
|
||||
navCss [ Css.Media.withMedia [ MediaQuery.mobile ] styles ]
|
||||
|
||||
|
||||
{-| -}
|
||||
navQuizEngineMobileCss : List Style -> NavAttribute msg
|
||||
navQuizEngineMobileCss styles =
|
||||
navCss [ Css.Media.withMedia [ MediaQuery.quizEngineMobile ] styles ]
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias CollapsibleConfig msg =
|
||||
{ isOpen : Bool
|
||||
, toggle : Bool -> msg
|
||||
, isTooltipOpen : Bool
|
||||
, toggleTooltip : Bool -> msg
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
collapsible : CollapsibleConfig msg -> NavAttribute msg
|
||||
collapsible collapsible_ =
|
||||
NavAttribute (\config -> { config | collapsible = Just collapsible_ })
|
||||
|
||||
|
||||
{-| -}
|
||||
view : Config route msg -> List (NavAttribute msg) -> List (Entry route msg) -> Html msg
|
||||
view config navAttributes entries =
|
||||
let
|
||||
appliedNavAttributes =
|
||||
List.foldl (\(NavAttribute f) b -> f b) defaultNavAttributeConfig navAttributes
|
||||
|
||||
showNav =
|
||||
Maybe.map .isOpen appliedNavAttributes.collapsible
|
||||
|> Maybe.withDefault True
|
||||
|
||||
sidenavId =
|
||||
Maybe.withDefault defaultSideNavId appliedNavAttributes.navId
|
||||
|
||||
defaultCss =
|
||||
[ if showNav then
|
||||
case appliedNavAttributes.collapsible of
|
||||
Just _ ->
|
||||
Css.batch
|
||||
[ Css.flexBasis (Css.px 245)
|
||||
, Css.padding4 (Css.px 25) (Css.px 25) (Css.px 20) (Css.px 20)
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
Css.batch
|
||||
[ Css.flexBasis (Css.px 250)
|
||||
, Css.padding (Css.px 20)
|
||||
]
|
||||
|
||||
else
|
||||
Css.flexBasis (Css.px 5)
|
||||
, flexShrink (num 0)
|
||||
, marginRight (px 20)
|
||||
, position relative
|
||||
, borderRadius (px 8)
|
||||
, backgroundColor Colors.gray96
|
||||
]
|
||||
in
|
||||
div [ Attributes.css (defaultCss ++ appliedNavAttributes.css) ]
|
||||
[ viewSkipLink config.onSkipNav
|
||||
, viewJust (viewOpenCloseButton sidenavId appliedNavAttributes.navLabel) appliedNavAttributes.collapsible
|
||||
, viewNav sidenavId config appliedNavAttributes entries showNav
|
||||
]
|
||||
|
||||
|
||||
defaultSideNavId : String
|
||||
defaultSideNavId =
|
||||
"sidenav"
|
||||
|
||||
|
||||
viewOpenCloseButton : String -> Maybe String -> CollapsibleConfig msg -> Html msg
|
||||
viewOpenCloseButton sidenavId navLabel_ { isOpen, toggle, isTooltipOpen, toggleTooltip } =
|
||||
let
|
||||
name =
|
||||
Maybe.withDefault "sidebar" navLabel_
|
||||
|
||||
( action, icon_, attributes ) =
|
||||
if isOpen then
|
||||
( "Close " ++ name
|
||||
, UiIcon.openClose
|
||||
, [ ClickableSvg.css [ Css.padding (Css.px 5) ]
|
||||
, ClickableSvg.iconForMobile UiIcon.x
|
||||
]
|
||||
)
|
||||
|
||||
else
|
||||
( "Open " ++ name
|
||||
, UiIcon.openClose
|
||||
|> Svg.withCss [ Css.transform (rotate (deg 180)) ]
|
||||
, [ ClickableSvg.withBorder
|
||||
, ClickableSvg.iconForMobile UiIcon.hamburger
|
||||
]
|
||||
)
|
||||
|
||||
trigger tooltipAttributes =
|
||||
ClickableSvg.button action
|
||||
icon_
|
||||
([ ClickableSvg.custom
|
||||
[ Aria.controls [ sidenavId ]
|
||||
, Aria.expanded isOpen
|
||||
]
|
||||
, ClickableSvg.custom tooltipAttributes
|
||||
, ClickableSvg.onClick (toggle (not isOpen))
|
||||
, ClickableSvg.tertiary
|
||||
]
|
||||
++ attributes
|
||||
)
|
||||
in
|
||||
Tooltip.view
|
||||
{ trigger = trigger
|
||||
, id = "open-close-sidebar-tooltip"
|
||||
}
|
||||
[ Tooltip.open isTooltipOpen
|
||||
, Tooltip.onToggle toggleTooltip
|
||||
, Tooltip.plaintext action
|
||||
, Tooltip.smallPadding
|
||||
, Tooltip.fitToContent
|
||||
, if isOpen then
|
||||
Tooltip.onLeft
|
||||
|
||||
else
|
||||
Tooltip.onRight
|
||||
, Tooltip.onRightForMobile
|
||||
, Tooltip.containerCss
|
||||
(if isOpen then
|
||||
[ Css.Media.withMedia [ MediaQuery.notMobile ]
|
||||
[ Css.position Css.absolute
|
||||
, Css.top Css.zero
|
||||
, Css.right Css.zero
|
||||
]
|
||||
]
|
||||
|
||||
else
|
||||
[]
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
viewNav : String -> Config route msg -> NavAttributeConfig msg -> List (Entry route msg) -> Bool -> Html msg
|
||||
viewNav sidenavId config appliedNavAttributes entries showNav =
|
||||
nav
|
||||
([ Maybe.map Aria.label appliedNavAttributes.navLabel
|
||||
, Just (Attributes.id sidenavId)
|
||||
, if showNav then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just (Attributes.css [ Css.display Css.none ])
|
||||
]
|
||||
|> List.filterMap identity
|
||||
)
|
||||
(List.map (viewSidebarEntry config []) entries)
|
||||
|
||||
|
||||
viewSkipLink : msg -> Html msg
|
||||
viewSkipLink onSkip =
|
||||
ClickableText.button "Skip to main content"
|
||||
[ ClickableText.icon UiIcon.arrowPointingRight
|
||||
, ClickableText.small
|
||||
, ClickableText.css
|
||||
[ Css.pseudoClass "not(:focus)"
|
||||
[ Style.invisibleStyle
|
||||
]
|
||||
]
|
||||
, ClickableText.onClick onSkip
|
||||
]
|
||||
|
||||
|
||||
viewSidebarEntry : Config route msg -> List Css.Style -> Entry route msg -> Html msg
|
||||
viewSidebarEntry config extraStyles entry_ =
|
||||
case entry_ of
|
||||
Entry children entryConfig ->
|
||||
if entryConfig.premiumDisplay == PremiumDisplay.PremiumLocked then
|
||||
viewLockedEntry extraStyles entryConfig
|
||||
|
||||
else if anyLinkDescendants (isCurrentRoute config) children then
|
||||
div [ Attributes.css extraStyles ]
|
||||
(styled span
|
||||
(sharedEntryStyles
|
||||
++ [ backgroundColor Colors.gray92
|
||||
, color Colors.navy
|
||||
, fontWeight bold
|
||||
, cursor default
|
||||
, marginBottom (px 10)
|
||||
]
|
||||
)
|
||||
[]
|
||||
[ text entryConfig.title ]
|
||||
:: List.map (viewSidebarEntry config [ marginLeft (px 20) ]) children
|
||||
)
|
||||
|
||||
else
|
||||
viewSidebarLeaf config extraStyles entryConfig
|
||||
|
||||
Html html_ ->
|
||||
div [ Attributes.css extraStyles ] html_
|
||||
|
||||
|
||||
isCurrentRoute : Config route msg -> EntryConfig route msg -> Bool
|
||||
isCurrentRoute config { route } =
|
||||
Maybe.map config.isCurrentRoute route
|
||||
|> Maybe.withDefault False
|
||||
|
||||
|
||||
anyLinkDescendants : (EntryConfig route msg -> Bool) -> List (Entry route msg) -> Bool
|
||||
anyLinkDescendants f children =
|
||||
List.any
|
||||
(\entry_ ->
|
||||
case entry_ of
|
||||
Entry children_ entryConfig ->
|
||||
f entryConfig || anyLinkDescendants f children_
|
||||
|
||||
Html _ ->
|
||||
False
|
||||
)
|
||||
children
|
||||
|
||||
|
||||
viewSidebarLeaf :
|
||||
Config route msg
|
||||
-> List Style
|
||||
-> EntryConfig route msg
|
||||
-> Html msg
|
||||
viewSidebarLeaf config extraStyles entryConfig =
|
||||
let
|
||||
( linkFunctionName, attributes ) =
|
||||
ClickableAttributes.toLinkAttributes
|
||||
{ routeToString = config.routeToString
|
||||
, isDisabled = False
|
||||
}
|
||||
entryConfig.clickableAttributes
|
||||
in
|
||||
Nri.Ui.styled Html.Styled.a
|
||||
("Nri-Ui-SideNav-" ++ linkFunctionName)
|
||||
(sharedEntryStyles
|
||||
++ extraStyles
|
||||
++ (if isCurrentRoute config entryConfig then
|
||||
[ backgroundColor Colors.glacier
|
||||
, color Colors.navy
|
||||
, fontWeight bold
|
||||
, visited [ color Colors.navy ]
|
||||
]
|
||||
|
||||
else
|
||||
[]
|
||||
)
|
||||
++ entryConfig.customStyles
|
||||
)
|
||||
(attributes ++ entryConfig.customAttributes)
|
||||
[ viewJust
|
||||
(\icon_ ->
|
||||
icon_
|
||||
|> Svg.withWidth (px 20)
|
||||
|> Svg.withHeight (px 20)
|
||||
|> Svg.withCss [ marginRight (px 5) ]
|
||||
|> Svg.toHtml
|
||||
)
|
||||
entryConfig.icon
|
||||
, text entryConfig.title
|
||||
]
|
||||
|
||||
|
||||
viewLockedEntry : List Style -> EntryConfig route msg -> Html msg
|
||||
viewLockedEntry extraStyles entryConfig =
|
||||
styled Html.Styled.button
|
||||
[ batch sharedEntryStyles
|
||||
, important (color Colors.gray45)
|
||||
, borderWidth zero
|
||||
, batch extraStyles
|
||||
]
|
||||
(case entryConfig.onLockedContent of
|
||||
Just event ->
|
||||
Events.onClick event :: entryConfig.customAttributes
|
||||
|
||||
Nothing ->
|
||||
entryConfig.customAttributes
|
||||
)
|
||||
[ UiIcon.premiumLock
|
||||
|> Svg.withWidth (px 17)
|
||||
|> Svg.withHeight (px 25)
|
||||
|> Svg.withCss [ marginRight (px 10), minWidth (px 17) ]
|
||||
|> Svg.toHtml
|
||||
, text entryConfig.title
|
||||
]
|
||||
|
||||
|
||||
sharedEntryStyles : List Style
|
||||
sharedEntryStyles =
|
||||
[ padding2 (px 13) (px 20)
|
||||
, Css.property "word-break" "normal"
|
||||
, Css.property "overflow-wrap" "anywhere"
|
||||
, displayFlex
|
||||
, borderRadius (px 8)
|
||||
, alignItems center
|
||||
, Fonts.baseFont
|
||||
, color Colors.navy
|
||||
, backgroundColor transparent
|
||||
, textDecoration none
|
||||
, fontSize (px 15)
|
||||
, fontWeight (int 600)
|
||||
, textAlign left
|
||||
, cursor pointer
|
||||
]
|
||||
|
||||
|
||||
|
||||
-- Entry Customization helpers
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias EntryConfig route msg =
|
||||
{ icon : Maybe Svg
|
||||
, title : String
|
||||
, route : Maybe route
|
||||
, clickableAttributes : ClickableAttributes route msg
|
||||
, customAttributes : List (Html.Styled.Attribute msg)
|
||||
, customStyles : List Style
|
||||
, premiumDisplay : PremiumDisplay
|
||||
, onLockedContent : Maybe msg
|
||||
}
|
||||
|
||||
|
||||
build : String -> EntryConfig route msg
|
||||
build title =
|
||||
{ icon = Nothing
|
||||
, title = title
|
||||
, route = Nothing
|
||||
, clickableAttributes = ClickableAttributes.init
|
||||
, customAttributes = []
|
||||
, customStyles = []
|
||||
, premiumDisplay = PremiumDisplay.Free
|
||||
, onLockedContent = Nothing
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
type Attribute route msg
|
||||
= Attribute (EntryConfig route msg -> EntryConfig route msg)
|
||||
|
||||
|
||||
{-| -}
|
||||
icon : Svg -> Attribute route msg
|
||||
icon icon_ =
|
||||
Attribute (\attributes -> { attributes | icon = Just icon_ })
|
||||
|
||||
|
||||
{-| -}
|
||||
premiumDisplay : PremiumDisplay -> msg -> Attribute route msg
|
||||
premiumDisplay display ifLocked =
|
||||
Attribute
|
||||
(\attributes ->
|
||||
{ attributes
|
||||
| premiumDisplay = display
|
||||
, onLockedContent = Just ifLocked
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| 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 :
|
||||
Maybe route
|
||||
-> (ClickableAttributes route msg -> ClickableAttributes route msg)
|
||||
-> Attribute route msg
|
||||
setClickableAttributes route apply =
|
||||
Attribute
|
||||
(\attributes ->
|
||||
{ attributes
|
||||
| route =
|
||||
case route of
|
||||
Just r ->
|
||||
Just r
|
||||
|
||||
Nothing ->
|
||||
attributes.route
|
||||
, clickableAttributes = apply attributes.clickableAttributes
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
onClick : msg -> Attribute route msg
|
||||
onClick msg =
|
||||
setClickableAttributes Nothing (ClickableAttributes.onClick msg)
|
||||
|
||||
|
||||
{-| -}
|
||||
href : route -> Attribute route msg
|
||||
href route =
|
||||
setClickableAttributes (Just route) (ClickableAttributes.href route)
|
||||
|
||||
|
||||
{-| 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 : route -> Attribute route msg
|
||||
linkSpa route =
|
||||
setClickableAttributes (Just route)
|
||||
(ClickableAttributes.linkSpa route)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkWithMethod : { method : String, url : route } -> Attribute route msg
|
||||
linkWithMethod config =
|
||||
setClickableAttributes (Just config.url)
|
||||
(ClickableAttributes.linkWithMethod config)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkWithTracking : { track : msg, url : route } -> Attribute route msg
|
||||
linkWithTracking config =
|
||||
setClickableAttributes (Just config.url)
|
||||
(ClickableAttributes.linkWithTracking config)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkExternal : String -> Attribute route msg
|
||||
linkExternal url =
|
||||
setClickableAttributes Nothing (ClickableAttributes.linkExternal url)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkExternalWithTracking : { track : msg, url : String } -> Attribute route msg
|
||||
linkExternalWithTracking config =
|
||||
setClickableAttributes Nothing (ClickableAttributes.linkExternalWithTracking config)
|
@ -36,13 +36,13 @@ import Accessibility.Styled as Html exposing (Html)
|
||||
import Accessibility.Styled.Aria as Aria
|
||||
import Css exposing (Color, Style)
|
||||
import Css.Global as Global
|
||||
import Css.Media
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Html.Styled.Events as Events
|
||||
import Nri.Ui.Colors.Extra exposing (toCssString)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Html.Attributes.V2 as Extra
|
||||
import Nri.Ui.MediaQuery.V1 as MediaQuery
|
||||
import Nri.Ui.Svg.V1 exposing (Svg)
|
||||
import Svg.Styled as Svg
|
||||
import Svg.Styled.Attributes as SvgAttributes
|
||||
@ -373,6 +373,4 @@ stroke color =
|
||||
|
||||
transition : String -> Css.Style
|
||||
transition transitionRules =
|
||||
Css.Media.withMediaQuery
|
||||
[ "(prefers-reduced-motion: no-preference)" ]
|
||||
[ Css.property "transition" transitionRules ]
|
||||
MediaQuery.anyMotion [ Css.property "transition" transitionRules ]
|
||||
|
@ -1,5 +1,5 @@
|
||||
module Nri.Ui.UiIcon.V1 exposing
|
||||
( seeMore, openClose, download, sort, gear, flipper
|
||||
( seeMore, openClose, download, sort, gear, flipper, hamburger
|
||||
, archive, unarchive
|
||||
, playInCircle, pauseInCircle, stopInCircle
|
||||
, play, skip
|
||||
@ -33,7 +33,7 @@ module Nri.Ui.UiIcon.V1 exposing
|
||||
|
||||
{-| How to add new icons: <https://paper.dropbox.com/doc/How-to-create-a-new-SVG-icon-for-use-in-Elm--Ay9uhSLfGUAix0ERIiJ0Dm8dAg-8WNqtARdr4EgjmYEHPeYD>
|
||||
|
||||
@docs seeMore, openClose, download, sort, gear, flipper
|
||||
@docs seeMore, openClose, download, sort, gear, flipper, hamburger
|
||||
@docs archive, unarchive
|
||||
@docs playInCircle, pauseInCircle, stopInCircle
|
||||
@docs play, skip
|
||||
@ -910,6 +910,37 @@ pauseInCircle =
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
hamburger : Nri.Ui.Svg.V1.Svg
|
||||
hamburger =
|
||||
Nri.Ui.Svg.V1.init "0 0 25 25"
|
||||
[ Svg.rect
|
||||
[ Attributes.x "0"
|
||||
, Attributes.y "0"
|
||||
, Attributes.width "25"
|
||||
, Attributes.height "5"
|
||||
, Attributes.rx "2.5"
|
||||
]
|
||||
[]
|
||||
, Svg.rect
|
||||
[ Attributes.x "0"
|
||||
, Attributes.y "10"
|
||||
, Attributes.width "25"
|
||||
, Attributes.height "5"
|
||||
, Attributes.rx "2.5"
|
||||
]
|
||||
[]
|
||||
, Svg.rect
|
||||
[ Attributes.x "0"
|
||||
, Attributes.y "20"
|
||||
, Attributes.width "25"
|
||||
, Attributes.height "5"
|
||||
, Attributes.rx "2.5"
|
||||
]
|
||||
[]
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
equals : Nri.Ui.Svg.V1.Svg
|
||||
equals =
|
||||
|
@ -18,7 +18,7 @@ import Nri.Ui.CssVendorPrefix.V1 as VendorPrefixed
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.MediaQuery.V1 exposing (mobile)
|
||||
import Nri.Ui.Page.V3 as Page
|
||||
import Nri.Ui.SideNav.V3 as SideNav
|
||||
import Nri.Ui.SideNav.V4 as SideNav
|
||||
import Nri.Ui.Sprite.V1 as Sprite
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import Routes
|
||||
@ -36,6 +36,8 @@ type alias Model key =
|
||||
route : Route
|
||||
, previousRoute : Maybe Route
|
||||
, moduleStates : Dict String (Example Examples.State Examples.Msg)
|
||||
, isSideNavOpen : Bool
|
||||
, openTooltip : Maybe TooltipId
|
||||
, navigationKey : key
|
||||
, elliePackageDependencies : Result Http.Error (Dict String String)
|
||||
}
|
||||
@ -51,6 +53,8 @@ init () url key =
|
||||
( { route = Routes.fromLocation moduleStates url
|
||||
, previousRoute = Nothing
|
||||
, moduleStates = moduleStates
|
||||
, isSideNavOpen = True
|
||||
, openTooltip = Nothing
|
||||
, navigationKey = key
|
||||
, elliePackageDependencies = Ok Dict.empty
|
||||
}
|
||||
@ -62,12 +66,18 @@ init () url key =
|
||||
)
|
||||
|
||||
|
||||
type TooltipId
|
||||
= SideNavOpenCloseTooltip
|
||||
|
||||
|
||||
type Msg
|
||||
= UpdateModuleStates String Examples.Msg
|
||||
| OnUrlRequest Browser.UrlRequest
|
||||
| OnUrlChange Url
|
||||
| ChangeRoute Route
|
||||
| SkipToMainContent
|
||||
| ToggleSideNav Bool
|
||||
| ToggleTooltip TooltipId Bool
|
||||
| LoadedPackages (Result Http.Error (Dict String String))
|
||||
| Focused (Result Browser.Dom.Error ())
|
||||
|
||||
@ -125,6 +135,15 @@ update action model =
|
||||
, FocusOn "maincontent"
|
||||
)
|
||||
|
||||
ToggleSideNav isOpen ->
|
||||
( { model | isSideNavOpen = isOpen }, None )
|
||||
|
||||
ToggleTooltip tooltipId True ->
|
||||
( { model | openTooltip = Just tooltipId }, None )
|
||||
|
||||
ToggleTooltip _ False ->
|
||||
( { model | openTooltip = Nothing }, None )
|
||||
|
||||
LoadedPackages newPackagesResult ->
|
||||
let
|
||||
-- Ellie gets really slow to compile if we include all the packages, unfortunately!
|
||||
@ -280,10 +299,7 @@ viewCategory model category =
|
||||
)
|
||||
|
||||
|
||||
withSideNav :
|
||||
{ model | route : Route, moduleStates : Dict String (Example Examples.State Examples.Msg) }
|
||||
-> Html Msg
|
||||
-> Html Msg
|
||||
withSideNav : Model key -> Html Msg -> Html Msg
|
||||
withSideNav model content =
|
||||
Html.div
|
||||
[ css
|
||||
@ -333,10 +349,8 @@ viewPreviews containerId navConfig examples =
|
||||
]
|
||||
|
||||
|
||||
navigation :
|
||||
{ model | route : Route, moduleStates : Dict String (Example Examples.State Examples.Msg) }
|
||||
-> Html Msg
|
||||
navigation { moduleStates, route } =
|
||||
navigation : Model key -> Html Msg
|
||||
navigation { moduleStates, route, isSideNavOpen, openTooltip } =
|
||||
let
|
||||
examples =
|
||||
Dict.values moduleStates
|
||||
@ -370,6 +384,14 @@ navigation { moduleStates, route } =
|
||||
[ VendorPrefixed.value "position" "sticky"
|
||||
, top (px 55)
|
||||
]
|
||||
, SideNav.collapsible
|
||||
{ isOpen = isSideNavOpen
|
||||
, toggle = ToggleSideNav
|
||||
, isTooltipOpen = openTooltip == Just SideNavOpenCloseTooltip
|
||||
, toggleTooltip = ToggleTooltip SideNavOpenCloseTooltip
|
||||
}
|
||||
, SideNav.navLabel "categories"
|
||||
, SideNav.navId "sidenav__categories"
|
||||
]
|
||||
(SideNav.entry "Usage Guidelines"
|
||||
[ SideNav.linkExternal "https://paper.dropbox.com/doc/UI-Style-Guide-and-Caveats--BhJHYronm1RGM1hRfnkvhrZMAg-PvOLxeX3oyujYEzdJx5pu"
|
||||
|
@ -187,6 +187,7 @@ viewExampleTable { label, icon, attributes } =
|
||||
[ ( "primary", ClickableSvg.primary )
|
||||
, ( "secondary", ClickableSvg.secondary )
|
||||
, ( "danger", ClickableSvg.danger )
|
||||
, ( "tertiary", ClickableSvg.tertiary )
|
||||
, ( "dangerSecondary", ClickableSvg.dangerSecondary )
|
||||
]
|
||||
, Html.tfoot []
|
||||
@ -295,4 +296,13 @@ initSettings =
|
||||
{ moduleName = "ClickableSvg"
|
||||
, use = ClickableSvg.notMobileCss
|
||||
}
|
||||
|> ControlExtra.optionalListItem "iconForMobile"
|
||||
(Control.map
|
||||
(\( name, icon ) ->
|
||||
( "ClickableSvg.iconForMobile " ++ name
|
||||
, ClickableSvg.iconForMobile icon
|
||||
)
|
||||
)
|
||||
CommonControls.uiIcon
|
||||
)
|
||||
)
|
||||
|
@ -17,12 +17,12 @@ import EllieLink
|
||||
import Example exposing (Example)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.SideNav.V3 as SideNav
|
||||
import Nri.Ui.SideNav.V4 as SideNav
|
||||
|
||||
|
||||
version : Int
|
||||
version =
|
||||
3
|
||||
4
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -124,7 +124,7 @@ type alias State =
|
||||
|
||||
type alias Settings =
|
||||
{ currentRoute : String
|
||||
, navAttributes : List ( String, SideNav.NavAttribute )
|
||||
, navAttributes : List ( String, SideNav.NavAttribute Msg )
|
||||
, entries : List ( String, SideNav.Entry String Msg )
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ init =
|
||||
}
|
||||
|
||||
|
||||
controlNavAttributes : Control (List ( String, SideNav.NavAttribute ))
|
||||
controlNavAttributes : Control (List ( String, SideNav.NavAttribute Msg ))
|
||||
controlNavAttributes =
|
||||
ControlExtra.list
|
||||
|> ControlExtra.optionalListItemDefaultChecked "navLabel"
|
||||
|
@ -58,6 +58,7 @@ all =
|
||||
, ( "download", UiIcon.download, [] )
|
||||
, ( "sort", UiIcon.sort, [] )
|
||||
, ( "gear", UiIcon.gear, [] )
|
||||
, ( "hamburger", UiIcon.hamburger, [] )
|
||||
]
|
||||
)
|
||||
, ( "Archive & Unarchive"
|
||||
|
@ -47,6 +47,7 @@
|
||||
"Nri.Ui.Select.V8",
|
||||
"Nri.Ui.Shadows.V1",
|
||||
"Nri.Ui.SideNav.V3",
|
||||
"Nri.Ui.SideNav.V4",
|
||||
"Nri.Ui.SortableTable.V2",
|
||||
"Nri.Ui.SortableTable.V3",
|
||||
"Nri.Ui.Sprite.V1",
|
||||
|
Loading…
Reference in New Issue
Block a user