noredink-ui/styleguide-app/Main.elm

256 lines
7.3 KiB
Elm
Raw Normal View History

2022-03-15 21:06:13 +03:00
module Main exposing (main)
2018-02-13 00:32:38 +03:00
2021-11-05 21:26:43 +03:00
import Accessibility.Styled as Html exposing (Html)
import Browser exposing (Document, UrlRequest(..))
2020-03-24 22:26:41 +03:00
import Browser.Dom
import Browser.Navigation exposing (Key)
2022-03-15 21:06:13 +03:00
import Category
import Css exposing (..)
import Css.Media exposing (withMedia)
import Dict exposing (Dict)
import Example exposing (Example)
import Examples
2022-03-15 21:06:13 +03:00
import Html.Styled.Attributes exposing (..)
2020-11-06 21:51:33 +03:00
import Nri.Ui.CssVendorPrefix.V1 as VendorPrefixed
import Nri.Ui.Heading.V2 as Heading
import Nri.Ui.MediaQuery.V1 exposing (mobile, notMobile)
import Nri.Ui.Page.V3 as Page
2022-03-07 23:26:56 +03:00
import Nri.Ui.SideNav.V2 as SideNav
import Nri.Ui.Sprite.V1 as Sprite
2022-03-15 21:06:13 +03:00
import Routes exposing (Route)
import Sort.Set as Set
2020-03-24 22:26:41 +03:00
import Task
import Url exposing (Url)
2018-02-13 00:32:38 +03:00
main : Program () Model Msg
2018-02-13 00:32:38 +03:00
main =
Browser.application
2018-02-13 00:32:38 +03:00
{ init = init
, update = update
, subscriptions = subscriptions
, view = view
, onUrlRequest = OnUrlRequest
, onUrlChange = OnUrlChange
2018-02-13 00:32:38 +03:00
}
type alias Model =
{ -- Global UI
route : Route
, previousRoute : Maybe Route
, moduleStates : Dict String (Example Examples.State Examples.Msg)
, navigationKey : Key
}
init : () -> Url -> Key -> ( Model, Cmd Msg )
2018-12-05 21:56:04 +03:00
init () url key =
( { route = Routes.fromLocation url
, previousRoute = Nothing
, moduleStates =
Dict.fromList
(List.map (\example -> ( example.name, example )) Examples.all)
2018-12-05 21:56:04 +03:00
, navigationKey = key
2018-02-13 00:32:38 +03:00
}
, Cmd.none
)
type Msg
= UpdateModuleStates String Examples.Msg
| OnUrlRequest Browser.UrlRequest
| OnUrlChange Url
| ChangeRoute Route
2020-03-24 22:26:41 +03:00
| SkipToMainContent
| NoOp
update : Msg -> Model -> ( Model, Cmd Msg )
update action model =
case action of
UpdateModuleStates key exampleMsg ->
case Dict.get key model.moduleStates of
Just example ->
example.update exampleMsg example.state
|> Tuple.mapFirst
(\newState ->
{ model
| moduleStates =
Dict.insert key
{ example | state = newState }
model.moduleStates
}
)
|> Tuple.mapSecond (Cmd.map (UpdateModuleStates key))
Nothing ->
( model, Cmd.none )
OnUrlRequest request ->
case request of
Internal loc ->
( model, Browser.Navigation.pushUrl model.navigationKey (Url.toString loc) )
External loc ->
( model, Browser.Navigation.load loc )
OnUrlChange route ->
( { model
| route = Routes.fromLocation route
, previousRoute = Just model.route
}
, Cmd.none
)
ChangeRoute route ->
( model
, Browser.Navigation.pushUrl model.navigationKey
(Routes.toString route)
)
2020-03-24 22:26:41 +03:00
SkipToMainContent ->
( model
, Task.attempt (\_ -> NoOp) (Browser.Dom.focus "maincontent")
)
NoOp ->
( model, Cmd.none )
subscriptions : Model -> Sub Msg
subscriptions model =
Dict.values model.moduleStates
|> List.map (\example -> Sub.map (UpdateModuleStates example.name) (example.subscriptions example.state))
|> Sub.batch
view : Model -> Document Msg
view model =
{ title = "Style Guide"
, body =
[ view_ model |> Html.toUnstyled
, Sprite.attach |> Html.map never |> Html.toUnstyled
]
}
view_ : Model -> Html Msg
view_ model =
2020-06-19 23:52:02 +03:00
let
examples filterBy =
2021-05-28 04:23:07 +03:00
List.filter (\m -> filterBy m) (Dict.values model.moduleStates)
in
case model.route of
Routes.Doodad doodad ->
case List.head (examples (\m -> m.name == doodad)) of
Just example ->
2021-12-03 22:40:57 +03:00
Html.main_
[ css
[ maxWidth (Css.px 1400)
, margin auto
]
]
[ 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 =
2020-06-20 00:12:53 +03:00
Html.div
[ css
[ displayFlex
, withMedia [ mobile ] [ flexDirection column, alignItems stretch ]
2020-06-20 00:12:53 +03:00
, alignItems flexStart
2021-12-03 22:40:57 +03:00
, maxWidth (Css.px 1400)
, margin auto
2020-06-20 00:12:53 +03:00
]
]
[ navigation currentRoute
2021-11-05 21:26:43 +03:00
, 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"
]
]
2021-05-28 04:23:07 +03:00
navigation : Route -> Html Msg
navigation currentRoute =
let
2021-12-04 00:34:32 +03:00
categoryNavLinks : List (SideNav.Entry Route Msg)
categoryNavLinks =
List.map
(\category ->
SideNav.entry (Category.forDisplay category)
[ SideNav.href (Routes.Category category) ]
)
Category.all
in
2021-12-03 19:45:06 +03:00
SideNav.view
2022-03-07 23:26:56 +03:00
{ isCurrentRoute = (==) currentRoute
, routeToString = Routes.toString
2021-12-03 19:45:06 +03:00
, onSkipNav = SkipToMainContent
, css =
[ withMedia [ notMobile ]
[ VendorPrefixed.value "position" "sticky"
, top (px 55)
]
]
2021-12-03 19:45:06 +03:00
}
2021-12-04 00:34:32 +03:00
(SideNav.entry "All" [ SideNav.href Routes.All ]
:: categoryNavLinks
)