diff --git a/forbidden-imports.toml b/forbidden-imports.toml index afc00bc5..a07f23e8 100644 --- a/forbidden-imports.toml +++ b/forbidden-imports.toml @@ -33,11 +33,7 @@ hint = 'Use Accessibility.Widgetd.Widget' [forbidden.Html] hint = 'Use Html.Styled' -usages = [ - 'styleguide-app/../src/Nri/Ui/Button/V8.elm', - 'styleguide-app/Examples/Modal.elm', - 'styleguide-app/Main.elm', -] +usages = ['styleguide-app/../src/Nri/Ui/Button/V8.elm'] [forbidden."Nri.Ui.Accordion.V1"] hint = 'upgrade to V3' diff --git a/src/Nri/Ui/Page/V3.elm b/src/Nri/Ui/Page/V3.elm index 444e1465..ef0c98ae 100644 --- a/src/Nri/Ui/Page/V3.elm +++ b/src/Nri/Ui/Page/V3.elm @@ -23,7 +23,7 @@ import Nri.Ui.Html.V3 exposing (viewIf) {-| The default page information is for the button which will direct the user back to the main page of -the SPA. Specify it's name and the message which will +the SPA. Specify its name and the message which will navigate to the page. -} type alias DefaultPage msg = diff --git a/src/Nri/Ui/Switch/V1.elm b/src/Nri/Ui/Switch/V1.elm index e18c763a..08f2f14c 100644 --- a/src/Nri/Ui/Switch/V1.elm +++ b/src/Nri/Ui/Switch/V1.elm @@ -1,8 +1,8 @@ -module Nri.Ui.Switch.V1 exposing (view, Attribute, onSwitch, disabled, id, label) +module Nri.Ui.Switch.V1 exposing (view, Attribute, onSwitch, disabled, id, label, custom) {-| -@docs view, Attribute, onSwitch, disabled, id, label +@docs view, Attribute, onSwitch, disabled, id, label, custom -} @@ -27,6 +27,7 @@ type Attribute msg | Id String | Label (Html msg) | Disabled + | Custom (List (Html.Attribute Never)) {-| Specify what happens when the switch is toggled. @@ -63,10 +64,18 @@ label = Label +{-| Pass custom attributes through to be attached to the underlying input. +-} +custom : List (Html.Attribute Never) -> Attribute msg +custom = + Custom + + type alias Config msg = { onSwitch : Maybe (Bool -> msg) , id : String , label : Maybe (Html msg) + , attributes : List (Html.Attribute Never) } @@ -75,6 +84,7 @@ defaultConfig = { onSwitch = Nothing , id = "nri-ui-switch-with-default-id" , label = Nothing + , attributes = [] } @@ -93,6 +103,9 @@ customize attr config = Label label_ -> { config | label = Just label_ } + Custom custom_ -> + { config | attributes = custom_ } + {-| Render a switch. The boolean here indicates whether the switch is on or not. @@ -133,6 +146,7 @@ view attrs isOn = { id = config.id , onCheck = config.onSwitch , checked = isOn + , attributes = config.attributes } , Nri.Ui.Svg.V1.toHtml (viewSwitch @@ -162,26 +176,29 @@ viewCheckbox : { id : String , onCheck : Maybe (Bool -> msg) , checked : Bool + , attributes : List (Html.Attribute Never) } -> Html msg viewCheckbox config = Html.checkbox config.id (Just config.checked) - [ Attributes.id config.id - , Attributes.css + ([ Attributes.id config.id + , Attributes.css [ Css.position Css.absolute , Css.top (Css.px 10) , Css.left (Css.px 10) , Css.zIndex (Css.int 0) , Css.opacity (Css.num 0) ] - , case config.onCheck of + , case config.onCheck of Just onCheck -> Events.onCheck onCheck Nothing -> Widget.disabled True - ] + ] + ++ List.map (Attributes.map never) config.attributes + ) viewSwitch : diff --git a/styleguide-app/Example.elm b/styleguide-app/Example.elm index f96e60b8..019fd789 100644 --- a/styleguide-app/Example.elm +++ b/styleguide-app/Example.elm @@ -1,15 +1,22 @@ -module Example exposing (Example, view, wrapMsg, wrapState) +module Example exposing (Example, preview, view, wrapMsg, wrapState) import Category exposing (Category) import Css exposing (..) import Css.Global exposing (a, descendants) import Html.Styled as Html exposing (Html) import Html.Styled.Attributes as Attributes +import Html.Styled.Events as Events import Html.Styled.Lazy as Lazy import KeyboardSupport exposing (KeyboardSupport) -import Nri.Ui.Colors.V1 exposing (..) +import Nri.Ui.ClickableSvg.V2 as ClickableSvg +import Nri.Ui.ClickableText.V3 as ClickableText +import Nri.Ui.Colors.V1 as Colors exposing (..) +import Nri.Ui.Container.V2 as Container import Nri.Ui.Fonts.V1 as Fonts +import Nri.Ui.Heading.V2 as Heading import Nri.Ui.Html.Attributes.V2 as AttributeExtras exposing (targetBlank) +import Nri.Ui.UiIcon.V1 as UiIcon +import Routes exposing (Route) type alias Example state msg = @@ -18,12 +25,18 @@ type alias Example state msg = , state : state , update : msg -> state -> ( state, Cmd msg ) , subscriptions : state -> Sub msg + , preview : List (Html Never) , view : state -> List (Html msg) , categories : List Category , keyboardSupport : List KeyboardSupport } +fullName : Example state msg -> String +fullName example = + "Nri.Ui." ++ example.name ++ ".V" ++ String.fromInt example.version + + wrapMsg : (msg -> msg2) -> (msg2 -> Maybe msg) @@ -43,6 +56,7 @@ wrapMsg wrapMsg_ unwrapMsg example = Nothing -> ( state, Cmd.none ) , subscriptions = \state -> Sub.map wrapMsg_ (example.subscriptions state) + , preview = example.preview , view = \state -> List.map (Html.map wrapMsg_) (example.view state) , categories = example.categories , keyboardSupport = example.keyboardSupport @@ -71,6 +85,7 @@ wrapState wrapState_ unwrapState example = unwrapState >> Maybe.map example.subscriptions >> Maybe.withDefault Sub.none + , preview = example.preview , view = unwrapState >> Maybe.map example.view @@ -80,22 +95,77 @@ wrapState wrapState_ unwrapState example = } -view : Example state msg -> Html msg -view = - Lazy.lazy view_ +preview : (Route -> msg2) -> Example state msg -> Html msg2 +preview navigate = + Lazy.lazy (preview_ navigate) + + +preview_ : (Route -> msg2) -> Example state msg -> Html msg2 +preview_ navigate example = + Container.view + [ Container.gray + , Container.css + [ Css.flexBasis (Css.px 150) + , Css.hover + [ Css.backgroundColor Colors.glacier + , Css.cursor Css.pointer + ] + ] + , Container.custom [ Events.onClick (navigate (Routes.Doodad example.name)) ] + , Container.html + (ClickableText.link example.name + [ ClickableText.href (exampleHref example) + , ClickableText.css [ Css.marginBottom (Css.px 10) ] + ] + :: [ Html.div + [ Attributes.css + [ Css.displayFlex + , Css.flexDirection Css.column + ] + ] + (List.map (Html.map never) example.preview) + ] + ) + ] + + +view : Maybe Route -> Example state msg -> Html msg +view previousRoute example = + Container.view + [ Container.pillow + , Container.css + [ Css.position Css.relative + , Css.margin (Css.px 10) + , Css.minHeight (Css.calc (Css.vh 100) Css.minus (Css.px 20)) + , Css.boxSizing Css.borderBox + ] + , Container.html + [ Lazy.lazy view_ example + , ClickableSvg.link ("Close " ++ example.name ++ " example") + UiIcon.x + [ ClickableSvg.href + (Maybe.withDefault Routes.All previousRoute + |> Routes.toString + ) + , ClickableSvg.small + , ClickableSvg.css + [ Css.position Css.absolute + , Css.top (Css.px 15) + , Css.right (Css.px 15) + ] + ] + ] + ] view_ : Example state msg -> Html msg view_ example = - let - fullName = - "Nri.Ui." ++ example.name ++ ".V" ++ String.fromInt example.version - in Html.div [ -- this class makes the axe accessibility checking output easier to parse String.replace "." "-" example.name |> (++) "module-example__" |> Attributes.class + , Attributes.id (String.replace "." "-" example.name) ] [ Html.div [ Attributes.css @@ -107,52 +177,57 @@ view_ example = , descendants [ Css.Global.a [ textDecoration none ] ] ] ] - [ Html.styled Html.h2 - [ color navy - , fontSize (px 20) - , marginTop zero - , marginBottom zero - , Fonts.baseFont - ] - [] - [ Html.a - [ Attributes.href ("#/doodad/" ++ example.name) - , Attributes.class "module-example__doodad-link" - , -- this data attribute is used to name the Percy screenshots - String.replace "." "-" example.name - |> Attributes.attribute "data-percy-name" - ] - [ Html.text fullName ] - ] - , String.replace "." "-" fullName - |> (++) "https://package.elm-lang.org/packages/NoRedInk/noredink-ui/latest/" - |> viewLink "Docs" - , String.replace "." "/" fullName - ++ ".elm" - |> (++) "https://github.com/NoRedInk/noredink-ui/blob/master/src/" - |> viewLink "Source" + [ exampleLink example + , docsLink example + , srcLink example ] , KeyboardSupport.view example.keyboardSupport - , Html.div - [ Attributes.css - [ padding (px 40) - , boxShadow5 zero (px 2) (px 4) zero (rgba 0 0 0 0.25) - , border3 (px 1) solid gray92 - , borderRadius (px 20) - , margin3 (px 10) zero (px 40) + , Html.div [] (example.view example.state) + ] + + +exampleHref : Example state msg -> String +exampleHref example = + Routes.toString (Routes.Doodad example.name) + + +exampleLink : Example state msg -> Html msg +exampleLink example = + Heading.h2 [] + [ ClickableText.link (fullName example) + [ ClickableText.href (exampleHref example) + , ClickableText.large + , ClickableText.custom + [ -- this data attribute is used to name the Percy screenshots + String.replace "." "-" example.name + |> Attributes.attribute "data-percy-name" ] ] - (example.view example.state) ] -viewLink : String -> String -> Html msg -viewLink text href = - Html.a - ([ Attributes.href href - , Attributes.css [ Css.display Css.block, marginLeft (px 20) ] - ] - ++ targetBlank - ) - [ Html.text text +docsLink : Example state msg -> Html msg +docsLink example = + let + link = + "https://package.elm-lang.org/packages/NoRedInk/noredink-ui/latest/" + ++ String.replace "." "-" (fullName example) + in + ClickableText.link "Docs" + [ ClickableText.linkExternal link + , ClickableText.css [ Css.marginLeft (Css.px 20) ] + ] + + +srcLink : Example state msg -> Html msg +srcLink example = + let + link = + String.replace "." "/" (fullName example) + ++ ".elm" + |> (++) "https://github.com/NoRedInk/noredink-ui/blob/master/src/" + in + ClickableText.link "Source" + [ ClickableText.linkExternal link + , ClickableText.css [ Css.marginLeft (Css.px 20) ] ] diff --git a/styleguide-app/Examples/Accordion.elm b/styleguide-app/Examples/Accordion.elm index b60db65e..088ce90a 100644 --- a/styleguide-app/Examples/Accordion.elm +++ b/styleguide-app/Examples/Accordion.elm @@ -25,6 +25,7 @@ import Nri.Ui.DisclosureIndicator.V2 as DisclosureIndicator import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Heading.V2 as Heading import Nri.Ui.Svg.V1 as Svg +import Nri.Ui.Text.V6 as Text import Nri.Ui.UiIcon.V1 as UiIcon import Set exposing (Set) import Task @@ -38,6 +39,21 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ -- faking a mini version of the Accordion component to give styleguide users a sense of what the + -- component might look like + Html.div [] + [ Html.div [ css [ Css.displayFlex, Css.alignItems Css.center ] ] + [ defaultCaret False + , Text.smallBody [ Text.plaintext "Closed" ] + ] + , Html.div [ css [ Css.displayFlex, Css.alignItems Css.center ] ] + [ defaultCaret True + , Text.smallBody [ Text.plaintext "Open" ] + ] + , Text.caption [ Text.plaintext "Accordion content." ] + ] + ] , view = view , categories = [ Layout ] , keyboardSupport = @@ -57,13 +73,14 @@ example = } +defaultCaret : Bool -> Html msg +defaultCaret = + DisclosureIndicator.large [ Css.marginRight (Css.px 8) ] + + {-| -} view : State -> List (Html Msg) view model = - let - defaultCaret = - DisclosureIndicator.large [ Css.marginRight (Css.px 8) ] - in [ Heading.h3 [] [ Html.text "Accordion.view" ] , Accordion.view { entries = diff --git a/styleguide-app/Examples/AssignmentIcon.elm b/styleguide-app/Examples/AssignmentIcon.elm index 3503bb10..e5b5b57c 100644 --- a/styleguide-app/Examples/AssignmentIcon.elm +++ b/styleguide-app/Examples/AssignmentIcon.elm @@ -33,6 +33,21 @@ example = , state = () , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = + IconExamples.preview + [ AssignmentIcon.planningDiagnosticCircled + , AssignmentIcon.unitDiagnosticCircled + , AssignmentIcon.practiceCircled + , AssignmentIcon.quizCircled + , AssignmentIcon.quickWriteCircled + , AssignmentIcon.guidedDraftCircled + , AssignmentIcon.peerReviewCircled + , AssignmentIcon.selfReviewCircled + , AssignmentIcon.startPrimary + , AssignmentIcon.assessment + , AssignmentIcon.standards + , AssignmentIcon.writing + ] , view = \_ -> [ IconExamples.view "Diagnostic" diff --git a/styleguide-app/Examples/Balloon.elm b/styleguide-app/Examples/Balloon.elm index e9838dcf..9ba1a24a 100644 --- a/styleguide-app/Examples/Balloon.elm +++ b/styleguide-app/Examples/Balloon.elm @@ -29,6 +29,14 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ Balloon.balloon + [ Balloon.onTop + , Balloon.navy + , Balloon.paddingPx 15 + ] + (text "This is a balloon.") + ] , view = view } diff --git a/styleguide-app/Examples/Button.elm b/styleguide-app/Examples/Button.elm index af5d809b..d3381441 100644 --- a/styleguide-app/Examples/Button.elm +++ b/styleguide-app/Examples/Button.elm @@ -6,6 +6,7 @@ module Examples.Button exposing (Msg, State, example) -} +import Accessibility.Styled.Key as Key import Category exposing (Category(..)) import Css exposing (middle, verticalAlign) import Debug.Control as Control exposing (Control) @@ -28,6 +29,27 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ Button.link "Primary" + [ Button.small + , Button.fillContainerWidth + , Button.custom [ Key.tabbable False ] + ] + , Button.link "Secondary" + [ Button.small + , Button.fillContainerWidth + , Button.secondary + , Button.css [ Css.marginTop (Css.px 8) ] + , Button.custom [ Key.tabbable False ] + ] + , Button.link "Premium" + [ Button.small + , Button.fillContainerWidth + , Button.premium + , Button.css [ Css.marginTop (Css.px 8) ] + , Button.custom [ Key.tabbable False ] + ] + ] , view = \state -> [ viewButtonExamples state ] , categories = [ Buttons ] , keyboardSupport = [] diff --git a/styleguide-app/Examples/Checkbox.elm b/styleguide-app/Examples/Checkbox.elm index f8f4b53b..39188ab2 100644 --- a/styleguide-app/Examples/Checkbox.elm +++ b/styleguide-app/Examples/Checkbox.elm @@ -38,6 +38,7 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = [] , view = \state -> [ viewInteractableCheckbox "styleguide-checkbox-interactable" state diff --git a/styleguide-app/Examples/ClickableSvg.elm b/styleguide-app/Examples/ClickableSvg.elm index e266609e..91bb3278 100644 --- a/styleguide-app/Examples/ClickableSvg.elm +++ b/styleguide-app/Examples/ClickableSvg.elm @@ -6,6 +6,7 @@ module Examples.ClickableSvg exposing (Msg, State, example) -} +import Accessibility.Styled.Key as Key import Category exposing (Category(..)) import Css import Debug.Control as Control exposing (Control) @@ -36,6 +37,23 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ ClickableSvg.link "ClickableSvg small" + UiIcon.link + [ ClickableSvg.small + , ClickableSvg.custom [ Key.tabbable False ] + ] + , ClickableSvg.link "ClickableSvg medium" + UiIcon.link + [ ClickableSvg.medium + , ClickableSvg.custom [ Key.tabbable False ] + ] + , ClickableSvg.link "ClickableSvg large" + UiIcon.link + [ ClickableSvg.large + , ClickableSvg.custom [ Key.tabbable False ] + ] + ] , view = \state -> let diff --git a/styleguide-app/Examples/ClickableText.elm b/styleguide-app/Examples/ClickableText.elm index ee96bf9f..8a288cef 100644 --- a/styleguide-app/Examples/ClickableText.elm +++ b/styleguide-app/Examples/ClickableText.elm @@ -6,6 +6,7 @@ module Examples.ClickableText exposing (Msg, State, example) -} +import Accessibility.Styled.Key as Key import Category exposing (Category(..)) import Css exposing (middle, verticalAlign) import Debug.Control as Control exposing (Control) @@ -32,6 +33,23 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ ClickableText.link "Small" + [ ClickableText.icon UiIcon.link + , ClickableText.small + , ClickableText.custom [ Key.tabbable False ] + ] + , ClickableText.link "Medium" + [ ClickableText.icon UiIcon.link + , ClickableText.medium + , ClickableText.custom [ Key.tabbable False ] + ] + , ClickableText.link "Large" + [ ClickableText.icon UiIcon.link + , ClickableText.large + , ClickableText.custom [ Key.tabbable False ] + ] + ] , view = \state -> [ viewExamples state ] , categories = [ Buttons ] , keyboardSupport = [] diff --git a/styleguide-app/Examples/Colors.elm b/styleguide-app/Examples/Colors.elm index 9a748709..869a01f1 100644 --- a/styleguide-app/Examples/Colors.elm +++ b/styleguide-app/Examples/Colors.elm @@ -14,6 +14,7 @@ import Html.Styled.Attributes as Attributes exposing (css) import KeyboardSupport exposing (Direction(..), Key(..)) import Nri.Ui.Colors.Extra import Nri.Ui.Colors.V1 as Colors +import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Heading.V2 as Heading import SolidColor exposing (highContrast) @@ -41,6 +42,12 @@ example = , state = () , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = + [ ( "green", Colors.green ) + , ( "purple", Colors.purple ) + , ( "mustard", Colors.mustard ) + ] + |> List.map viewPreviewSwatch , view = \_ -> [ [ ( "gray20", Colors.gray20, "Main text" ) @@ -117,6 +124,22 @@ example = } +viewPreviewSwatch : ( String, Css.Color ) -> Html.Html msg +viewPreviewSwatch ( name, color ) = + Html.div + [ Attributes.css + [ Css.textAlign Css.center + , Css.padding2 (Css.px 8) Css.zero + , Css.margin2 (Css.px 4) Css.zero + , Css.borderRadius (Css.px 4) + , Css.backgroundColor color + , Css.color color + , Css.fontSize (Css.px 14) + ] + ] + [ Html.text name ] + + viewColors : List ColorExample -> Html.Html msg viewColors colors = colors diff --git a/styleguide-app/Examples/Confetti.elm b/styleguide-app/Examples/Confetti.elm index a4ba340d..e3325631 100644 --- a/styleguide-app/Examples/Confetti.elm +++ b/styleguide-app/Examples/Confetti.elm @@ -33,6 +33,7 @@ example = [ Browser.Events.onResize WindowResized , Confetti.subscriptions ConfettiMsg state ] + , preview = [] , view = \state -> [ Button.button "Launch confetti!" diff --git a/styleguide-app/Examples/Container.elm b/styleguide-app/Examples/Container.elm index 128dc1cc..2c3134da 100644 --- a/styleguide-app/Examples/Container.elm +++ b/styleguide-app/Examples/Container.elm @@ -35,6 +35,17 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ Container.view [] + , Container.view + [ Container.invalid + , Container.css [ Css.marginTop (Css.px 8) ] + ] + , Container.view + [ Container.disabled + , Container.css [ Css.marginTop (Css.px 8) ] + ] + ] , view = \state -> let diff --git a/styleguide-app/Examples/DisclosureIndicator.elm b/styleguide-app/Examples/DisclosureIndicator.elm index 1e3bd7b4..272ad9f4 100644 --- a/styleguide-app/Examples/DisclosureIndicator.elm +++ b/styleguide-app/Examples/DisclosureIndicator.elm @@ -36,6 +36,12 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ DisclosureIndicator.medium [] False + , DisclosureIndicator.medium [] True + , DisclosureIndicator.large [] False + , DisclosureIndicator.large [] True + ] , view = \state -> [ Text.smallBodyGray [ Text.plaintext "The disclosure indicator is only the caret. It is NOT a button -- you must create a button or clickabletext yourself!" ] diff --git a/styleguide-app/Examples/Divider.elm b/styleguide-app/Examples/Divider.elm index 6f30b4b5..d81abccc 100644 --- a/styleguide-app/Examples/Divider.elm +++ b/styleguide-app/Examples/Divider.elm @@ -35,5 +35,6 @@ example = , state = {} , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = [ Divider.view "Dividing Line" ] , view = \state -> [ Divider.view "Dividing Line" ] } diff --git a/styleguide-app/Examples/Fonts.elm b/styleguide-app/Examples/Fonts.elm index 7aedc1d7..4d032355 100644 --- a/styleguide-app/Examples/Fonts.elm +++ b/styleguide-app/Examples/Fonts.elm @@ -7,8 +7,9 @@ module Examples.Fonts exposing (example, State, Msg) -} import Category exposing (Category(..)) +import Css exposing (Style) import Example exposing (Example) -import Html.Styled as Html +import Html.Styled as Html exposing (Html) import Html.Styled.Attributes exposing (css) import KeyboardSupport exposing (Direction(..), Key(..)) import Nri.Ui.Fonts.V1 as Fonts @@ -35,6 +36,12 @@ example = , state = () , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = + [ ( "baseFont", Fonts.baseFont ) + , ( "quizFont", Fonts.quizFont ) + , ( "ugFont", Fonts.ugFont ) + ] + |> List.map viewPreview , view = \_ -> [ Heading.h3 [] [ Html.text "baseFont" ] @@ -48,3 +55,20 @@ example = [ Html.text "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" ] ] } + + +viewPreview : ( String, Style ) -> Html msg +viewPreview ( name, font ) = + Html.div + [ css + [ Css.displayFlex + , Css.justifyContent Css.spaceBetween + , font + , Css.fontSize (Css.px 14) + ] + ] + [ Html.p [ css [ Css.margin2 (Css.px 8) Css.zero ] ] + [ Html.text name ] + , Html.p [ css [ Css.margin2 (Css.px 8) Css.zero ] ] + [ Html.text "AaBbCc" ] + ] diff --git a/styleguide-app/Examples/Heading.elm b/styleguide-app/Examples/Heading.elm index 886e9a94..057758db 100644 --- a/styleguide-app/Examples/Heading.elm +++ b/styleguide-app/Examples/Heading.elm @@ -35,6 +35,12 @@ example = , state = () , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = + [ Heading.h1 [] [ Html.text "h1" ] + , Heading.h2 [] [ Html.text "h2" ] + , Heading.h3 [] [ Html.text "h3" ] + , Heading.h4 [] [ Html.text "h4" ] + ] , view = \_ -> [ Heading.h1 [] [ Html.text "This is the main page heading." ] diff --git a/styleguide-app/Examples/IconExamples.elm b/styleguide-app/Examples/IconExamples.elm index def4eb27..fae857f2 100644 --- a/styleguide-app/Examples/IconExamples.elm +++ b/styleguide-app/Examples/IconExamples.elm @@ -1,4 +1,4 @@ -module Examples.IconExamples exposing (view, viewWithCustomStyles) +module Examples.IconExamples exposing (preview, view, viewWithCustomStyles) import Css import Html.Styled as Html exposing (Html) @@ -9,6 +9,23 @@ import Nri.Ui.Svg.V1 as Svg import Nri.Ui.Text.V6 as Text +preview : List Svg.Svg -> List (Html msg) +preview icons = + [ Html.div + [ css + [ Css.displayFlex + , Css.flexWrap Css.wrap + , Css.property "gap" "10px" + , Css.color Colors.gray45 + ] + ] + (List.map + (Svg.withWidth (Css.px 30) >> Svg.withHeight (Css.px 30) >> Svg.toHtml) + icons + ) + ] + + view : String -> List ( String, Svg.Svg ) -> Html msg view headerText icons = let diff --git a/styleguide-app/Examples/Loading.elm b/styleguide-app/Examples/Loading.elm index 0efadaf3..5e0e8f0b 100644 --- a/styleguide-app/Examples/Loading.elm +++ b/styleguide-app/Examples/Loading.elm @@ -94,6 +94,7 @@ example = , state = init , update = update , subscriptions = subscriptions + , preview = [] , view = \{ showLoadingFadeIn, showLoading, showSpinners } -> [ if showLoading then diff --git a/styleguide-app/Examples/Logo.elm b/styleguide-app/Examples/Logo.elm index 8644f19a..4dab3e7e 100644 --- a/styleguide-app/Examples/Logo.elm +++ b/styleguide-app/Examples/Logo.elm @@ -10,9 +10,12 @@ import Category exposing (Category(..)) import Css import Example exposing (Example) import Examples.IconExamples as IconExamples +import Html.Styled as Html exposing (Html) +import Html.Styled.Attributes exposing (css) import KeyboardSupport exposing (Direction(..), Key(..)) import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Logo.V1 as Logo +import Nri.Ui.Svg.V1 as Svg {-| -} @@ -35,6 +38,14 @@ example = , state = () , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = + Html.div [ css [ Css.marginBottom (Css.px 8) ] ] [ Svg.toHtml Logo.noredink ] + :: IconExamples.preview + [ Logo.facebook + , Logo.twitter + , Logo.cleverC + , Logo.googleG + ] , view = \_ -> [ IconExamples.viewWithCustomStyles "NRI" diff --git a/styleguide-app/Examples/MasteryIcon.elm b/styleguide-app/Examples/MasteryIcon.elm index 01ec1f90..b33206c0 100644 --- a/styleguide-app/Examples/MasteryIcon.elm +++ b/styleguide-app/Examples/MasteryIcon.elm @@ -34,6 +34,7 @@ example = , state = () , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = [] , view = \_ -> [ IconExamples.view "Levels" diff --git a/styleguide-app/Examples/Menu.elm b/styleguide-app/Examples/Menu.elm index 4f09a0e5..8a6a97cf 100644 --- a/styleguide-app/Examples/Menu.elm +++ b/styleguide-app/Examples/Menu.elm @@ -47,6 +47,7 @@ example = } , { keys = [ Esc ], result = "Closes the menu" } ] + , preview = [] , view = view } diff --git a/styleguide-app/Examples/Message.elm b/styleguide-app/Examples/Message.elm index 71db74ed..17708dd1 100644 --- a/styleguide-app/Examples/Message.elm +++ b/styleguide-app/Examples/Message.elm @@ -177,6 +177,11 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ Message.view [ Message.plaintext "Tiny tip" ] + , Message.view [ Message.success, Message.plaintext "Tiny success" ] + , Message.view [ Message.error, Message.plaintext "Tiny error" ] + ] , view = \state -> let diff --git a/styleguide-app/Examples/Modal.elm b/styleguide-app/Examples/Modal.elm index 4d78a9cc..1c3a53da 100644 --- a/styleguide-app/Examples/Modal.elm +++ b/styleguide-app/Examples/Modal.elm @@ -7,22 +7,26 @@ module Examples.Modal exposing (Msg, State, example) -} import Accessibility.Styled as Html exposing (Html, div, h3, h4, p, span, text) +import Accessibility.Styled.Key as Key import Browser.Dom as Dom import Category exposing (Category(..)) import Css exposing (..) import Debug.Control as Control exposing (Control) import Debug.Control.Extra as ControlExtra import Example exposing (Example) -import Html as Root import Html.Styled.Attributes as Attributes exposing (css) import KeyboardSupport exposing (Direction(..), Key(..)) import Nri.Ui.Button.V10 as Button import Nri.Ui.Checkbox.V5 as Checkbox +import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.ClickableText.V3 as ClickableText +import Nri.Ui.Colors.Extra import Nri.Ui.Colors.V1 as Colors import Nri.Ui.FocusTrap.V1 as FocusTrap +import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Modal.V11 as Modal import Nri.Ui.Text.V6 as Text +import Nri.Ui.UiIcon.V1 as UiIcon import Task @@ -125,6 +129,51 @@ example = , state = init , update = update , subscriptions = subscriptions + , preview = + [ -- faking a mini version of the Modal component to give styleguide users a sense of what the + -- component might look like + div + [ css + [ Css.backgroundColor (Nri.Ui.Colors.Extra.withAlpha 0.9 Colors.navy) + , Css.borderRadius (Css.px 4) + , Css.padding2 (Css.px 25) Css.zero + , Css.displayFlex + , Css.alignItems Css.center + , Css.justifyContent Css.center + ] + ] + [ div + [ css + [ Css.backgroundColor Colors.white + , Css.padding (Css.px 10) + , Css.borderRadius (Css.px 10) + , Css.boxShadow5 Css.zero (Css.px 1) (Css.px 10) Css.zero (Css.rgba 0 0 0 0.35) + , Css.textAlign Css.center + , Css.color Colors.navy + , Fonts.baseFont + , Css.margin Css.auto + , Css.width (Css.px 100) + , Css.height (Css.px 60) + , Css.fontSize (Css.px 10) + , Css.fontWeight Css.bold + , Css.position Css.relative + ] + ] + [ text "Modal" + , ClickableSvg.link "Close" + UiIcon.x + [ ClickableSvg.exactWidth 10 + , ClickableSvg.exactHeight 10 + , ClickableSvg.css + [ Css.position absolute + , Css.top (Css.px 10) + , Css.right (Css.px 10) + ] + , ClickableSvg.custom [ Key.tabbable False ] + ] + ] + ] + ] , view = \state -> let diff --git a/styleguide-app/Examples/Page.elm b/styleguide-app/Examples/Page.elm index 2f6f5ee7..7d0c0956 100644 --- a/styleguide-app/Examples/Page.elm +++ b/styleguide-app/Examples/Page.elm @@ -17,6 +17,7 @@ import Html.Styled.Attributes exposing (css) import Http import KeyboardSupport exposing (Direction(..), Key(..)) import Nri.Ui.Colors.V1 as Colors +import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Heading.V2 as Heading import Nri.Ui.Page.V3 as Page exposing (RecoveryText(..)) @@ -62,6 +63,32 @@ example = , state = { httpError = CommonControls.httpError, recoveryText = initRecoveryText } , update = update , subscriptions = \_ -> Sub.none + , preview = + [ -- faking a mini version of the Page component to give styleguide users a sense of what the + -- component might look like + Html.div + [ css + [ Css.displayFlex + , Css.alignItems Css.center + , Css.flexDirection Css.column + , Css.backgroundColor Colors.white + , Css.borderRadius (Css.px 4) + , Css.padding (Css.px 20) + ] + ] + [ Html.div [ css [ Css.fontSize (Css.px 40) ] ] [ Html.text "😵" ] + , Html.p + [ css + [ Css.color Colors.navy + , Fonts.baseFont + , Css.fontWeight Css.bold + , Css.textAlign Css.center + , Css.margin Css.zero + ] + ] + [ Html.text "There was a problem!" ] + ] + ] , view = \model -> let diff --git a/styleguide-app/Examples/Pennant.elm b/styleguide-app/Examples/Pennant.elm index 596bd96e..8cadebb2 100644 --- a/styleguide-app/Examples/Pennant.elm +++ b/styleguide-app/Examples/Pennant.elm @@ -38,6 +38,12 @@ example = , state = () , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = + IconExamples.preview + [ Pennant.premiumFlag + , Pennant.expiredPremiumFlag + , Pennant.disabledPremiumFlag + ] , view = \_ -> [ IconExamples.viewWithCustomStyles "Premium Pennants" diff --git a/styleguide-app/Examples/RadioButton.elm b/styleguide-app/Examples/RadioButton.elm index d6dd00ab..a7bd4207 100644 --- a/styleguide-app/Examples/RadioButton.elm +++ b/styleguide-app/Examples/RadioButton.elm @@ -34,6 +34,7 @@ example = , state = init , update = update , subscriptions = subscriptions + , preview = [] , view = view , categories = [ Inputs ] , keyboardSupport = diff --git a/styleguide-app/Examples/SegmentedControl.elm b/styleguide-app/Examples/SegmentedControl.elm index d079b77a..e2a40f0e 100644 --- a/styleguide-app/Examples/SegmentedControl.elm +++ b/styleguide-app/Examples/SegmentedControl.elm @@ -36,6 +36,7 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = [] , view = \state -> let diff --git a/styleguide-app/Examples/Select.elm b/styleguide-app/Examples/Select.elm index b89e01e8..4507c38d 100644 --- a/styleguide-app/Examples/Select.elm +++ b/styleguide-app/Examples/Select.elm @@ -26,6 +26,7 @@ example = , subscriptions = \_ -> Sub.none , categories = [ Inputs ] , keyboardSupport = [] + , preview = [] , view = \state -> [ Html.Styled.label diff --git a/styleguide-app/Examples/Slide.elm b/styleguide-app/Examples/Slide.elm index a9585b7e..03a6d6c2 100644 --- a/styleguide-app/Examples/Slide.elm +++ b/styleguide-app/Examples/Slide.elm @@ -42,6 +42,7 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = [] , view = \state -> [ Keyed.node "div" diff --git a/styleguide-app/Examples/SlideModal.elm b/styleguide-app/Examples/SlideModal.elm index 3c2d321d..e5a1a034 100644 --- a/styleguide-app/Examples/SlideModal.elm +++ b/styleguide-app/Examples/SlideModal.elm @@ -40,6 +40,7 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = [] , view = \state -> [ viewModal state.modal diff --git a/styleguide-app/Examples/SortableTable.elm b/styleguide-app/Examples/SortableTable.elm index 2e7792d3..187657ba 100644 --- a/styleguide-app/Examples/SortableTable.elm +++ b/styleguide-app/Examples/SortableTable.elm @@ -41,6 +41,7 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = [] , view = \{ sortState } -> let diff --git a/styleguide-app/Examples/Svg.elm b/styleguide-app/Examples/Svg.elm index 690b4e62..e7703121 100644 --- a/styleguide-app/Examples/Svg.elm +++ b/styleguide-app/Examples/Svg.elm @@ -33,6 +33,7 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = [] , view = \state -> [ viewSettings state diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index 161516ef..8167cbcc 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -6,12 +6,12 @@ module Examples.Switch exposing (Msg, State, example) -} +import Accessibility.Styled.Key as Key import Category import Example exposing (Example) import Html.Styled as Html import Nri.Ui.Heading.V2 as Heading import Nri.Ui.Switch.V1 as Switch -import Nri.Ui.Text.V6 as Text {-| -} @@ -31,46 +31,47 @@ example = , state = True , update = \(Switch new) _ -> ( new, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = + [ Switch.view + [ Switch.label (Html.text "Toggle On") + , Switch.custom [ Key.tabbable False ] + ] + False + , Switch.view + [ Switch.label (Html.text "Toggle Off") + , Switch.custom [ Key.tabbable False ] + ] + True + ] , view = \interactiveIsOn -> [ Heading.h3 [] [ Html.text "Interactive" ] - , Text.mediumBody - [ Text.html - [ Switch.view - [ Switch.onSwitch Switch - , Switch.id "switch-interactive" - , Switch.label - (if interactiveIsOn then - Html.text "On" + , Switch.view + [ Switch.onSwitch Switch + , Switch.id "switch-interactive" + , Switch.label + (if interactiveIsOn then + Html.text "On" - else - Html.text "Off" - ) - ] - interactiveIsOn - ] + else + Html.text "Off" + ) ] - , Heading.h3 [] [ Html.text "Disabled" ] - , Text.mediumBody - [ Text.html - [ Switch.view - [ Switch.disabled - , Switch.id "switch-disabled-on" - , Switch.label (Html.text "Permanently on") - ] - True - ] + interactiveIsOn + , Heading.h3 [] [ Html.text "Disabled (On)" ] + , Switch.view + [ Switch.disabled + , Switch.id "switch-disabled-on" + , Switch.label (Html.text "Permanently on") ] - , Text.mediumBody - [ Text.html - [ Switch.view - [ Switch.disabled - , Switch.id "switch-disabled-off" - , Switch.label (Html.text "Permanently off") - ] - False - ] + True + , Heading.h3 [] [ Html.text "Disabled (Off)" ] + , Switch.view + [ Switch.disabled + , Switch.id "switch-disabled-off" + , Switch.label (Html.text "Permanently off") ] + False ] , categories = [ Category.Inputs ] , keyboardSupport = [{- TODO -}] diff --git a/styleguide-app/Examples/Table.elm b/styleguide-app/Examples/Table.elm index bd946cb3..2379e553 100644 --- a/styleguide-app/Examples/Table.elm +++ b/styleguide-app/Examples/Table.elm @@ -37,6 +37,29 @@ example = , subscriptions = \_ -> Sub.none , categories = [ Tables, Layout ] , keyboardSupport = [] + , preview = + [ Table.view + [ Table.string + { header = "A" + , value = .a + , width = px 50 + , cellStyles = always [] + } + , Table.string + { header = "B" + , value = .b + , width = px 50 + , cellStyles = always [] + } + ] + [ { a = "Row 1 A" + , b = "Row 1 B" + } + , { a = "Row 2 A" + , b = "Row 2 B" + } + ] + ] , view = \() -> let diff --git a/styleguide-app/Examples/Tabs.elm b/styleguide-app/Examples/Tabs.elm index 9be4b46a..9e7a9b2a 100644 --- a/styleguide-app/Examples/Tabs.elm +++ b/styleguide-app/Examples/Tabs.elm @@ -19,10 +19,13 @@ import Html.Styled as Html exposing (Html, fromUnstyled) import Html.Styled.Attributes exposing (css) import KeyboardSupport exposing (Key(..)) import List.Zipper exposing (Zipper) +import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Svg.V1 as Svg import Nri.Ui.Tabs.V7 as Tabs exposing (Alignment(..), Tab) +import Nri.Ui.Text.V6 as Text import Nri.Ui.Tooltip.V2 as Tooltip import Nri.Ui.UiIcon.V1 as UiIcon +import Routes import Task @@ -117,9 +120,14 @@ update msg model = ) +exampleName : String +exampleName = + "Tabs" + + example : Example State Msg example = - { name = "Tabs" + { name = exampleName , version = 7 , categories = [ Layout ] , keyboardSupport = @@ -136,6 +144,49 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ -- faking a mini version of the Tabs component to give styleguide users a sense of what the + -- component might look like + Html.div [ css [ Css.displayFlex, Css.flexWrap Css.wrap ] ] + [ Html.div + [ css + [ Css.backgroundColor Colors.white + , Css.padding (Css.px 4) + , Css.borderRadius4 (Css.px 4) (Css.px 4) Css.zero Css.zero + , Css.border3 (Css.px 1) Css.solid Colors.navy + , Css.borderBottomWidth Css.zero + ] + ] + [ Text.smallBody [ Text.plaintext "Tab 1" ] ] + , Html.div + [ css [ Css.width (Css.px 4), Css.borderBottom3 (Css.px 1) Css.solid Colors.navy ] + ] + [] + , Html.div + [ css + [ Css.backgroundColor Colors.frost + , Css.padding (Css.px 4) + , Css.borderRadius4 (Css.px 4) (Css.px 4) Css.zero Css.zero + , Css.border3 (Css.px 1) Css.solid Colors.navy + ] + ] + [ Text.smallBody [ Text.plaintext "Tab 1" ] ] + , Html.div + [ css + [ Css.width (Css.px 30) + , Css.borderBottom3 (Css.px 1) Css.solid Colors.navy + ] + ] + [] + , Html.div + [ css + [ Css.paddingTop (Css.px 4) + , Css.minWidth (Css.px 100) + ] + ] + [ Text.caption [ Text.plaintext "Tab 1 content" ] ] + ] + ] , view = \model -> let @@ -167,7 +218,7 @@ allTabs openTooltipId labelledBy = |> Svg.toHtml in [ Tabs.build { id = First, idString = "tab-0" } - ([ Tabs.spaHref "/#/doodad/Tabs" + ([ Tabs.spaHref <| Routes.toString (Routes.Doodad exampleName) , Tabs.tabString "1" , Tabs.withTooltip [ Tooltip.plaintext "Link Example" diff --git a/styleguide-app/Examples/Text.elm b/styleguide-app/Examples/Text.elm index 5286c7e6..04be16bc 100644 --- a/styleguide-app/Examples/Text.elm +++ b/styleguide-app/Examples/Text.elm @@ -30,6 +30,13 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ ( "caption", Text.caption ) + , ( "smallBody", Text.smallBody ) + , ( "mediumBody", Text.mediumBody ) + , ( "ugMediumBody", Text.ugMediumBody ) + ] + |> List.map viewPreview , view = \state -> let @@ -57,6 +64,11 @@ example = } +viewPreview : ( String, List (Text.Attribute msg) -> Html msg ) -> Html msg +viewPreview ( name, view ) = + view [ Text.plaintext name ] + + viewExamples : List ( String, List (Text.Attribute msg) -> Html msg ) -> List (Text.Attribute msg) -> Html msg viewExamples examples attributes = let diff --git a/styleguide-app/Examples/Text/Writing.elm b/styleguide-app/Examples/Text/Writing.elm index f9a1f1d2..22299a47 100644 --- a/styleguide-app/Examples/Text/Writing.elm +++ b/styleguide-app/Examples/Text/Writing.elm @@ -32,6 +32,7 @@ example = , state = () , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = [ TextWriting.footnote [ text "This is a footnote. " ] ] , view = \_ -> let diff --git a/styleguide-app/Examples/TextArea.elm b/styleguide-app/Examples/TextArea.elm index f4a2a662..f39bf075 100644 --- a/styleguide-app/Examples/TextArea.elm +++ b/styleguide-app/Examples/TextArea.elm @@ -44,6 +44,7 @@ example = , subscriptions = \_ -> Sub.none , categories = [ Inputs ] , keyboardSupport = [] + , preview = [] , view = \state -> [ Heading.h1 [] [ Html.text "Textarea controls" ] diff --git a/styleguide-app/Examples/TextInput.elm b/styleguide-app/Examples/TextInput.elm index 2cd1d906..494e7582 100644 --- a/styleguide-app/Examples/TextInput.elm +++ b/styleguide-app/Examples/TextInput.elm @@ -7,6 +7,7 @@ module Examples.TextInput exposing (Msg, State, example) -} import Accessibility.Styled as Html exposing (..) +import Accessibility.Styled.Key as Key import Category exposing (Category(..)) import Css exposing (..) import Debug.Control as Control exposing (Control) @@ -32,6 +33,16 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ TextInput.view "Text Input" + [ TextInput.custom [ Key.tabbable False ] + ] + , TextInput.view "Errored" + [ TextInput.value "invalid content" + , TextInput.errorIf True + , TextInput.custom [ Key.tabbable False ] + ] + ] , view = \state -> let diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 2cfa05c0..2ad8a296 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -7,6 +7,7 @@ module Examples.Tooltip exposing (example, State, Msg) -} import Accessibility.Styled as Html exposing (Html) +import Accessibility.Styled.Key as Key import Category exposing (Category(..)) import Css import Debug.Control as Control exposing (Control) @@ -33,6 +34,32 @@ example = , state = init , update = update , subscriptions = \_ -> Sub.none + , preview = + [ Html.div + [ css + [ Css.marginTop (Css.px 60) + , Css.alignSelf Css.center + ] + ] + [ Tooltip.view + { id = "preview-tooltip" + , trigger = + \attributes -> + ClickableSvg.button "example-preview-tooltip-icon" + UiIcon.gear + [ ClickableSvg.custom attributes + , ClickableSvg.small + , ClickableSvg.custom [ Key.tabbable False ] + ] + } + [ Tooltip.plaintext "This is a tooltip." + , Tooltip.open True + , Tooltip.onTop + , Tooltip.smallPadding + , Tooltip.fitToContent + ] + ] + ] , view = view } diff --git a/styleguide-app/Examples/UiIcon.elm b/styleguide-app/Examples/UiIcon.elm index 0841dfb7..10eac21b 100644 --- a/styleguide-app/Examples/UiIcon.elm +++ b/styleguide-app/Examples/UiIcon.elm @@ -33,6 +33,21 @@ example = , state = () , update = \_ state -> ( state, Cmd.none ) , subscriptions = \_ -> Sub.none + , preview = + IconExamples.preview + [ UiIcon.seeMore + , UiIcon.archive + , UiIcon.share + , UiIcon.footsteps + , UiIcon.person + , UiIcon.calendar + , UiIcon.missingDocument + , UiIcon.speechBalloon + , UiIcon.edit + , UiIcon.arrowTop + , UiIcon.checkmark + , UiIcon.equals + ] , view = \_ -> [ IconExamples.view "Interface" diff --git a/styleguide-app/Main.elm b/styleguide-app/Main.elm index 06ef6ca0..17065f63 100644 --- a/styleguide-app/Main.elm +++ b/styleguide-app/Main.elm @@ -1,6 +1,6 @@ module Main exposing (init, main) -import Accessibility.Styled as Html exposing (Html, img, text) +import Accessibility.Styled as Html exposing (Html) import Browser exposing (Document, UrlRequest(..)) import Browser.Dom import Browser.Navigation exposing (Key) @@ -10,15 +10,16 @@ import Css.Media exposing (withMedia) import Dict exposing (Dict) import Example exposing (Example) import Examples -import Html as RootHtml import Html.Attributes import Html.Styled.Attributes as Attributes exposing (..) import Html.Styled.Events as Events +import Nri.Ui.ClickableText.V3 as ClickableText import Nri.Ui.Colors.V1 as Colors import Nri.Ui.CssVendorPrefix.V1 as VendorPrefixed import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Heading.V2 as Heading import Nri.Ui.MediaQuery.V1 exposing (mobile, notMobile) +import Nri.Ui.Page.V3 as Page import Routes as Routes exposing (Route(..)) import Sort.Set as Set exposing (Set) import Task @@ -40,6 +41,7 @@ main = type alias Model = { -- Global UI route : Route + , previousRoute : Maybe Route , moduleStates : Dict String (Example Examples.State Examples.Msg) , navigationKey : Key } @@ -48,6 +50,7 @@ type alias Model = init : () -> Url -> Key -> ( Model, Cmd Msg ) init () url key = ( { route = Routes.fromLocation url + , previousRoute = Nothing , moduleStates = Dict.fromList (List.map (\example -> ( example.name, example )) Examples.all) @@ -61,6 +64,7 @@ type Msg = UpdateModuleStates String Examples.Msg | OnUrlRequest Browser.UrlRequest | OnUrlChange Url + | ChangeRoute Route | SkipToMainContent | NoOp @@ -95,7 +99,18 @@ update action model = ( model, Browser.Navigation.load loc ) OnUrlChange route -> - ( { model | route = Routes.fromLocation route }, Cmd.none ) + ( { model + | route = Routes.fromLocation route + , previousRoute = Just model.route + } + , Cmd.none + ) + + ChangeRoute route -> + ( model + , Browser.Navigation.pushUrl model.navigationKey + (Routes.toString route) + ) SkipToMainContent -> ( model @@ -125,69 +140,86 @@ view_ model = let examples filterBy = List.filter (\m -> filterBy m) (Dict.values model.moduleStates) - - mainContentHeader heading = - Heading.h1 - [ Heading.customAttr (id "maincontent") - , Heading.customAttr (tabindex -1) - , Heading.css [ marginBottom (px 30) ] - ] - [ Html.text heading ] in + case model.route of + Routes.Doodad doodad -> + case List.head (examples (\m -> m.name == doodad)) of + Just example -> + Html.main_ [] + [ Example.view model.previousRoute example + |> Html.map (UpdateModuleStates example.name) + ] + + Nothing -> + Page.notFound + { link = ChangeRoute Routes.All + , recoveryText = Page.ReturnTo "Component Library" + } + + Routes.Category category -> + withSideNav model.route + [ mainContentHeader (Category.forDisplay category) + , examples + (\doodad -> + Set.memberOf + (Set.fromList Category.sorter doodad.categories) + category + ) + |> viewPreviews (Category.forId category) + ] + + Routes.All -> + withSideNav model.route + [ mainContentHeader "All" + , viewPreviews "all" (examples (\_ -> True)) + ] + + +withSideNav : Route -> List (Html Msg) -> Html Msg +withSideNav currentRoute content = Html.div [ css [ displayFlex , withMedia [ mobile ] [ flexDirection column, alignItems stretch ] , alignItems flexStart - , minHeight (vh 100) ] ] - [ navigation model.route - , Html.main_ [ css [ flexGrow (int 1), sectionStyles ] ] - (case model.route of - Routes.Doodad doodad -> - case List.head (examples (\m -> m.name == doodad)) of - Just example -> - [ mainContentHeader ("Viewing " ++ doodad ++ " doodad only") - , Html.div [ id (String.replace "." "-" example.name) ] - [ Example.view example - |> Html.map (UpdateModuleStates example.name) - ] - ] - - Nothing -> - [ Html.text <| "Oops! We couldn't find " ++ doodad ] - - Routes.Category category -> - [ mainContentHeader (Category.forDisplay category) - , examples - (\doodad -> - Set.memberOf - (Set.fromList Category.sorter doodad.categories) - category - ) - |> List.map - (\example -> - Example.view example - |> Html.map (UpdateModuleStates example.name) - ) - |> Html.div [ id (Category.forId category) ] - ] - - Routes.All -> - [ mainContentHeader "All" - , examples (\_ -> True) - |> List.map - (\example -> - Example.view example - |> Html.map (UpdateModuleStates example.name) - ) - |> Html.div [] - ] - ) + [ navigation currentRoute + , Html.main_ + [ css + [ flexGrow (int 1) + , margin2 (px 40) zero + , Css.minHeight (Css.vh 100) + ] + ] + content ] +mainContentHeader : String -> Html msg +mainContentHeader heading = + Heading.h1 + [ Heading.customAttr (id "maincontent") + , Heading.customAttr (tabindex -1) + , Heading.css [ marginBottom (px 30) ] + ] + [ Html.text heading ] + + +viewPreviews : String -> List (Example state msg) -> Html Msg +viewPreviews containerId examples = + examples + |> List.map (\example -> Example.preview ChangeRoute example) + |> Html.div + [ id containerId + , css + [ Css.displayFlex + , Css.flexWrap Css.wrap + , Css.property "gap" "10px" + ] + ] + + navigation : Route -> Html Msg navigation route = let @@ -200,31 +232,31 @@ navigation route = False link active hash displayName = - Html.a - [ css - [ backgroundColor transparent - , borderStyle none - , textDecoration none + ClickableText.link displayName + [ ClickableText.small + , ClickableText.css + [ Css.color Colors.navy + , Css.display Css.block + , Css.padding (Css.px 8) + , Css.borderRadius (Css.px 8) , if active then - color Colors.navy + Css.backgroundColor Colors.glacier else - color Colors.azure - , Fonts.baseFont + Css.batch [] ] - , Attributes.href hash + , ClickableText.href hash ] - [ Html.text displayName ] navLink category = link (isActive category) - ("#/category/" ++ Debug.toString category) + (Routes.toString (Routes.Category category)) (Category.forDisplay category) toNavLi element = Html.li [ css - [ margin2 (px 10) zero + [ margin zero , listStyle none , textDecoration none ] @@ -269,18 +301,12 @@ navigation route = , id "skip" ] [ Html.text "Skip to main content" ] - , Heading.h4 [] [ Html.text "Categories" ] , (link (route == Routes.All) "#/" "All" :: List.map navLink Category.all ) |> List.map toNavLi |> Html.ul - [ css [ margin4 zero zero (px 40) zero, padding zero ] + [ css [ margin zero, padding zero ] , id "categories" ] ] - - -sectionStyles : Css.Style -sectionStyles = - Css.batch [ margin2 (px 40) zero ] diff --git a/styleguide-app/Routes.elm b/styleguide-app/Routes.elm index c7ab0e48..6fc49ee4 100644 --- a/styleguide-app/Routes.elm +++ b/styleguide-app/Routes.elm @@ -1,4 +1,4 @@ -module Routes exposing (Route(..), fromLocation) +module Routes exposing (Route(..), fromLocation, toString) import Browser.Navigation as Navigation import Category @@ -12,6 +12,19 @@ type Route | All +toString : Route -> String +toString route_ = + case route_ of + Doodad exampleName -> + "#/doodad/" ++ exampleName + + Category c -> + "#/category/" ++ Debug.toString c + + All -> + "#/" + + route : Parser Route route = Parser.oneOf