kalutheo / elm-ui-explorer / UIExplorer

Anatomy of the UI Explorer

How to explore my UI ?

explore : Config a b c d -> List (UI a b c) -> UIExplorerProgram a b c d

Launches a UI Explorer Applicaton given a list of UI. This is the simplest way to initialize the UI Explorer app.

Here we have an example of a Button that we want to explore:

import UIExplorer exposing (UIExplorerProgram, defaultConfig, explore, storiesOf)

button : String -> String -> Html.Html msg
button label bgColor =
    Html.button
        [ style "background-color" bgColor ]
        [ Html.text label ]

main : UIExplorerProgram {} () {} ()
main =
    explore
        defaultConfig
        [ storiesOf
            "Button"
            [ ( "SignIn", \_ -> button "Sign In" "pink", {} )
            , ( "SignOut", \_ -> button "Sign Out" "cyan", {} )
            , ( "Loading", \_ -> button "Loading please wait..." "white", {} )
            ]
        ]

exploreWithCategories : Config a b c d -> List (UICategory a b c) -> UIExplorerProgram a b c d

Explore with Categories

Launches a UI Explorer Applicaton given a list of UI Categories. This is a more advanced way to initialize the UI Explorer app. It can be usefull if you want to organize your UI by family.

main : UIExplorerProgram {} () {} ()
main =
    exploreWithCategories
        defaultConfig
        (createCategories
            |> category "Getting Started"
                [ storiesOf
                    "About"
                    [ ( "About", \_ -> Docs.toMarkdown Docs.about, { hasMenu = False } ) ]
                ]
            |> category
                "Guidelines"
                [ storiesOf
                    "Principles"
                    [ ( "Principles", \_ -> Docs.toMarkdown Docs.principles, { hasMenu = False } ) ]
                ]
            |> category
                "Styles"
                [ storiesOf
                    "Colors"
                    [ ( "Brand", \_ -> ColorGuide.viewBrandColors, { hasMenu = True } )
                    , ( "Neutral", \_ -> ColorGuide.viewNeutralColors, { hasMenu = True } )
                    ]
                , storiesOf
                    "Typography"
                    [ ( "Typography", \_ -> TypographyGuide.view, { hasMenu = False } )
                    ]
                ]
        )
        defaultConfig

defaultConfig : Config {} b c d

Sensible default configuration to initialize the explorer.

Types


type UI a b c

A UI represents a view and lists a set of stories. For Example : A Button with following stories (Loading, Disabled)


type UICategory a b c

Represents a family of related views. For example using Atomic Design, we can have the following categories : Atoms, Molecules etc..


type alias Model a b c =
{ categories : List (UICategory a b c)
, selectedUIId : Maybe String
, selectedStoryId : Maybe String
, selectedCategory : Maybe String
, url : Url
, key : Browser.Navigation.Key
, customModel : a
, mobileMenuIsOpen : Basics.Bool
, colorMode : Maybe ColorMode 
}

Model of the UI Explorer. You should not interact with this Type unless you are trying to achieve more advanced stuff such as Plugin Creation.


type Msg a
    = ExternalMsg a
    | SelectStory String
    | UrlChange Url
    | LinkClicked Browser.UrlRequest
    | NoOp
    | MobileMenuToggled
    | ColorModeToggled

Messages of the UI Explorer. You should not interact with this Type unless you are trying to achieve more advanced stuff such as Plugin Creation.


type alias UIExplorerProgram a b c d =
Platform.Program d (Model a b c) (Msg b)

The Elm Program created by the UI Explorer.

The three argument should only be changed when using Plugins. Default values are sufficent most of the time.


type Logo b

Use this type to change the logo whether using image url or a html element

Advanced

Elm UI Explorer can be extended with Plugins. The package comes with core plugins and you can obviously create your own. Theses plugins allow to customize the appearance of the UI Explorer. Functions listed below are related to that.


type alias Config a b c d =
{ customModel : a
, customHeader : Maybe (CustomHeader b)
, update : b -> Model a b c -> ( Model a b c
, Platform.Cmd.Cmd b )
, init : d -> a -> a
, enableDarkMode : Basics.Bool
, subscriptions : Model a b c -> Platform.Sub.Sub b
, viewEnhancer : ViewEnhancer a b c
, menuViewEnhancer : MenuViewEnhancer a b c
, onModeChanged : Maybe (Maybe ColorMode -> Platform.Cmd.Cmd (Msg b))
, documentTitle : Maybe String 
}

Configuration Type used to extend the UI Explorer appearance and behaviour.


type alias CustomHeader b =
{ title : String
, logo : Logo b
, titleColor : Maybe String
, bgColor : Maybe String 
}

Use this type to customize the appearance of the header

config =
    { defaultConfig
        | customHeader =
            Just
                { title = "This is my Design System"
                , logo = UIExplorer.logoFromUrl "/some-fancy-logo.png"
                , titleColor = Just "#FF6E00"
                , bgColor = Just "#FFFFFF"
                }
    }


type alias ViewEnhancer a b c =
Model a b c -> Html (Msg b) -> Html (Msg b)

Gives a chance to Plugins to add features to the main view canvas. For example, the Notes plugin allows to add markdown notes for each stories:

main : UIExplorerProgram {} () PluginOption ()
main =
    explore
        { defaultConfig | viewEnhancer = ExplorerNotesPlugin.viewEnhancer }
        [ storiesOf
            "Button"
            [ ( "Primary", \_ -> Button.view "Submit" defaultButtonConfig (), {notes: "This is the primary style :-)"} )
            , ( "Secondary", \_ -> Button.view "Submit" { defaultButtonConfig | appearance = Secondary } (), {notes: "This is the secondary style"} )
        ]


type alias MenuViewEnhancer a b c =
Model a b c -> Html (Msg b) -> Html (Msg b)

Gives a chance to Plugins to add features to the stories selection menu. For example, the Menu Visibility Plugin allows to hide/show the menu :

menuViewEnhancer =
    \model menuView ->
        getCurrentSelectedStory model
            |> Maybe.map
                (\( _, _, option ) ->
                    if option.hasMenu then
                        menuView

                    else
                        Html.text ""
                )
            |> Maybe.withDefault (Html.text "")

Then in your stories :

storiesOf
    "About"
    [ ( "HideMenu", _ -> myView { hasMenu = False } ),
    ( "ShowMenu", _ -> myView { hasMenu = True } )
    ]

getCurrentSelectedStory : Model a b c -> Maybe (Story a b c)

Get the Current Selected Story. Usefull to retrieve the current selected story. It can be used with MenuViewEnhancer or ViewEnhancer to hide/display contextual content.

Helpers

category : String -> List (UI a b c) -> List (UICategory a b c) -> List (UICategory a b c)

Adds a UI Category to a list of categories. Convenient for running a UI Explorer devided into categories

   createCategories
        |> category "A Great Category"
            [ storiesOf
                "GreatUI"
                [ ( "SomeState", \_ -> GreatUI.view , {} ) ]
            ]

storiesOf : String -> Stories a b c -> UI a b c

Create a UI given an ID and stories

storiesOf
    "GreatUI"
    [ ( "Default", \_ -> GreatUI.view, {} )
    , ( "Loading", \_ -> GreatUI.viewLoading, {} )
    , ( "Failure", \_ -> GreatUI.viewFailure, {} )
    ]

createCategories : List (UICategory a b c)

Creates an empty list of UI Categories

logoFromHtml : Html (Msg b) -> Logo b

Create a logo from a html element

Use this function to set the logo in the CustomHeader

logoFromUrl : String -> Logo b

Create a logo from a string

Use this function to set the logo in the CustomHeader