PaackEng / paack-ui / UI.Document

The UI.Document is paack-ui's page presenter and document. Depending on the situation, it applies the sidebar menu, dialogs, and mobile's navbar over the current page.

For this, a page must provide some required data through the Document.Page record. That aggregated with the current rendering configuration provided by UI.RenderConfig and the Document.Model, multiplex between possible viewing layouts.

Example of usage:

view : RenderConfig -> Model.Model -> { body : List (Html Msg.Msg), title : String }
view renderConfig { documentModel, currentPage } =
    Document.document Msg.DocumentMsg
        documentModel
        (getPagePage >> Document.pageMap Msg.PageMsg)
        |> Document.withMenuPages
            [ Document.menuPage (Icon.packages "Packages")
                (Link.link "/packages")
                (currentPage == Page.Packages)
            ]
        |> Document.withMenuActions
            [ Document.menuAction
                (Icon.logout "Logout")
                Msg.SessionLogout
            ]
        |> Document.withMenuLogo "My company's logo" someLogoElement
        |> Document.toBrowserDocument renderConfig currentPage

getPagePage : Page.Page -> Document.Page Page.Msg
getPagePage page =
    case page of
        Page.Packages pageModel ->
            Document.page "Packages"
                (Document.bodySingle <| Packages.view pageModel)
                |> Document.pageWithDialog pageModel.maybeDialog
                |> Document.pageWithDefaultMenu

Model & Update


type Msg

The Document.Msg handles menu related messages.


type Model

Keep this one in your Model, it holds the current navigation state.

modelInit : UI.RenderConfig.RenderConfig -> Model

The default way of instantiating a Document.Model.

Document.modelInit renderConfig

modelWithClosedMenu : Model -> Model

Force the menu to be closed on the Document.Model.

Document.modelInitWithClosedMenu renderConfig

modelUpdate : Msg -> Model -> ( Model, Platform.Cmd.Cmd Msg )

Given a message, apply an update to the Document.Model.

modelUpdateWithoutPerform : Msg -> Model -> ( Model, UI.Effects.Effects Msg )

Similar to [modelUpdate], but using Effects.

Building


type Document pageSet msg

The Document.Document handles menu, dialogs and page viewing. It must be initialized using Document.document.

document : (Msg -> msg) -> Model -> (pageSet -> Page msg) -> Document pageSet msg

Document.document holds the minimum amount of information required for all the features (menu, dialogs, and page's layout) to work.

The first parameter is a function that should transform Document.Msg in a message type controlled by the user.

The second is the current Document.Model, do not initialize this on view, hold it on the app's model, and then pass it to this function.

The third (and last) parameter is a lambda used to obtain the current page's container.

Document.Document Msg.FromNav
    model.documentModel
    (\page ->
        case page of
            Page.CardsEdit ->
                Pages.CardsEdit.View.container

            Page.AccountProfile ->
                Pages.AcountProfile.View.container
    )

Page


type Page msg

The Document.Page msg describes the current page in its current state.

The title field is exposed as to the browser and reused on the mobile's navbar.

When it is Just someElement, the dialog field is shown over the page.

The hasMenu field can hide the menu when undesired, e.g., login page.

The content field must be the element holding the page's view.

{ content = Document.bodySingle <| Element.el [] [ Element.text "Element body" ]
, title = "Example page"
, dialog = Nothing -- or Just <| Document.dialog <| ...
, hasMenu = True
}

page : String -> PageBody msg -> Page msg

Initializes a page's description

Document.page "My page's title"
    (Document.bodySingle <| SomePage.view somePageModel)

pageWithDialog : Maybe (UI.Dialog.Dialog msg) -> Page msg -> Page msg

Overlay (or not) a dialog over the page.

Document.pageWithDialog
    (Just <| Element.text "Hello World")
    someDocumentPage

pageWithDefaultMenu : Page msg -> Page msg

Make the document's default menu available in this page.

Document.pageWithDefaultMenu
    someDocumentPage

pageMap : (a -> b) -> Page a -> Page b

Transform the messages produced by a container.

PageBody


type alias PageBody msg =
UI.Internal.Page.PageBody msg

The Document.PageBody msg manages different kinds of pages' body. By now, the content is either a typical single page or a stacked child of mobile's views.

The typical single page renders the way they come. The stacked child has a different header on mobile, where a back button replaces the sandwich button.

bodySingle : Element msg -> PageBody msg

Document.bodySingle indicates that the current page is a simple single page. It expects the final page's view in the only parameter.

Document.bodySingle <| view renderConfig model


type alias Stack msg =
UI.Internal.Page.Stack msg

Stacked children are typical on mobile. The most significant difference is they have a customizable navbar where a back button replaces the sandwich menu, allowing the user to return to a higher scope. Besides that, they can add custom buttons to the right side of the title.

This record holds a stack child's configuration. That includes the back button's message, a title which overwrites the main page's title, and the customized buttons.

{ title = "Edit: Card " ++ selectedCard.number
, buttons =
    [ Icon.print "Print card"
        |> Button.fromIcon
        |> Button.cmd (Msg.PrintCard selectedCard) Button.light
    ]
, goBackMsg = Msg.DiscardCardChanges
}

bodyStack : Stack msg -> Element msg -> PageBody msg

Document.bodyStack indicates that the current page is a stack child's page. It expects the child's configuration and the final page's view as its parameters.

Document.bodyStack
    { title = "Edit: Card " ++ selectedCard.number
    , buttons =
        [ Icon.print "Print card"
            |> Button.fromIcon
            |> Button.cmd (Msg.PrintCard selectedCard) Button.light
        ]
    , goBackMsg = Msg.DiscardCardChanges
    }
<|
    cardEditView renderConfig selectedCard

Menu

withMenuLogo : String -> Element msg -> Document page msg -> Document page msg

Document.withMenuLogo replaces the logo shown on the menu. By now, this logo is only visible at the desktop's sidebar.

The first parameter is a hint that exists for accessibility reasons.

Document.withMenuLogo "Paack - Time Matters"
    Vectors.paackLogoWhite
    someNav

withMenuActions : List (MenuAction msg) -> Document page msg -> Document page msg

Document.withMenuActions replaces the list of the menu's actions. Therefore changing the list of items showed at the bottom of the sidebar.

Document.withMenuActions
    [ Document.menuAction
        (Icon.language "Change to English")
        (Msg.SetLanguage Lang.English)
    , Document.menuAction
        (Icon.logout "Logout")
        Msg.SessionLogout
    ]
    someNav


type MenuAction msg

This record must be generated with Document.menuAction

menuAction : UI.Icon.Icon -> msg -> MenuAction msg

Document.menuPage describes an action to Document.withMenuActions.

Document.menuAction
    (Icon.logout "Logout")
    Msg.SessionLogout

withMenuPages : List MenuPage -> Document page msg -> Document page msg

Document.withMenuPages replaces the list of the menu's navigable pages. Therefore changing the list of items showed at the top of the sidebar.

Document.withMenuPages
    [ Document.menuPage (Icon.edit "Manage cards")
        (Link.link "/edit-cards")
        (currentPage == Page.CardsEdit)
    , Document.menuPage (Icon.add "New manager")
        (Link.link "/add-manager")
        (currentPage == Page.ManagerAdd)
    ]
    someNav

withExtraHtml : List (Html msg) -> Document page msg -> Document page msg

Document.withExtraHtml allows injecting unrelated elements in the page.


type MenuPage

This record must be generated with Document.menuPage

menuPage : UI.Icon.Icon -> UI.Link.Link -> Basics.Bool -> MenuPage

Document.menuPage describes a page to Document.withMenuPages.

Document.menuPage (Icon.edit "Edit cards")
    (Link.link "/edit-cards")
    (currentPage == Pages.CardsEdit)

withSidebarStyle : SidebarStyle -> Document page msg -> Document page msg

Document.withSidebarStyle takes a SidebarStyle setting the appearance/behavior of the sidebar when it is enabled by the hasMenu flag.

sidebarPersistent : SidebarStyle

Persistent style of the sidebar. It occupies more space when open pushing the content right.

sidebarNonPersistent : SidebarStyle

Non-persistent style of the sidebar. Like the mobile sidebar, this style makes the sidebar open over the content with an overlay behind it.

withLegacyTransitionMenuStyle : Document page msg -> Document page msg

Document.withLegacyTransitionMenuStyle takes a Legacy SidebarStyle setting the appearance/behavior of the sidebar when it is enabled by the hasMenu flag.

showMenu : Msg

Message to force the exhibition of the sidebar/menu.

hideMenu : Msg

Message to force hiding the sidebar/menu.

Rendering

toBrowserDocument : UI.RenderConfig.RenderConfig -> pageSet -> Document pageSet msg -> { body : List (Html msg), title : String }

End of the builder's life. The result of this function is a ready-to-use Browser.Document.

There is an additional parameter that is the page identifier, used to obtain the current container.

Document.toBrowserDocument renderConfig currentPage document