noredink-ui/styleguide-app/Main.elm

264 lines
7.6 KiB
Elm
Raw Normal View History

2018-09-26 17:02:10 +03:00
module Main exposing (init, 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)
import Category exposing (Category)
import Css exposing (..)
import Css.Media exposing (withMedia)
import Dict exposing (Dict)
import Example exposing (Example)
import Examples
import Html.Attributes
import Html.Styled.Attributes as Attributes exposing (..)
2020-03-24 22:26:41 +03:00
import Html.Styled.Events as Events
2021-11-05 21:26:43 +03:00
import Nri.Ui.ClickableText.V3 as ClickableText
import Nri.Ui.Colors.V1 as Colors
2020-11-06 21:51:33 +03:00
import Nri.Ui.CssVendorPrefix.V1 as VendorPrefixed
import Nri.Ui.Data.PremiumLevel as PremiumLevel
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 Nri.Ui.SideNav.V1 as SideNav
import Nri.Ui.Sprite.V1 as Sprite
2021-12-03 20:40:45 +03:00
import Nri.Ui.UiIcon.V1 as UiIcon
2018-02-13 00:32:38 +03:00
import Routes as Routes exposing (Route(..))
2020-06-19 23:52:02 +03:00
import Sort.Set as Set exposing (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
{ userPremiumLevel = PremiumLevel.Free
, 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
)