1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 09:37:02 +00:00

ui: Give Layout it's own Model/Msg

This commit is contained in:
James Hillyerd
2019-02-17 10:24:07 -08:00
parent 7cd45ff3c7
commit cfbd30d8b0
2 changed files with 95 additions and 71 deletions

View File

@@ -1,4 +1,4 @@
module Layout exposing (Page(..), frame) module Layout exposing (Model, Msg, Page(..), frame, init, reset, update)
import Data.Session as Session exposing (Session) import Data.Session as Session exposing (Session)
import Html exposing (..) import Html exposing (..)
@@ -29,44 +29,91 @@ type Page
| Status | Status
type alias FrameControls msg = type alias Model msg =
{ menuVisible : Bool { mapMsg : Msg -> msg
, toggleMenu : msg
, recentVisible : Bool
, showRecent : Bool -> msg
, viewMailbox : String -> msg
, mailboxOnInput : String -> msg
, mailboxValue : String
, recentOptions : List String
, recentActive : String
, clearFlash : msg , clearFlash : msg
, viewMailbox : String -> msg
, menuVisible : Bool
, recentVisible : Bool
, mailboxName : String
} }
frame : FrameControls msg -> Session -> Page -> Maybe (Html msg) -> List (Html msg) -> Html msg init : (Msg -> msg) -> msg -> (String -> msg) -> Model msg
frame controls session activePage modal content = init mapMsg clearFlash viewMailbox =
{ mapMsg = mapMsg
, clearFlash = clearFlash
, viewMailbox = viewMailbox
, menuVisible = False
, recentVisible = False
, mailboxName = ""
}
{-| Resets layout state, used when navigating to a new page.
-}
reset : Model msg -> Model msg
reset model =
{ model
| menuVisible = False
, recentVisible = False
, mailboxName = ""
}
type Msg
= ToggleMenu
| ShowRecent Bool
| OnMailboxNameInput String
update : Msg -> Model msg -> Model msg
update msg model =
case msg of
ToggleMenu ->
{ model | menuVisible = not model.menuVisible }
ShowRecent visible ->
{ model | recentVisible = visible }
OnMailboxNameInput name ->
{ model | mailboxName = name }
type alias State msg =
{ model : Model msg
, session : Session
, activePage : Page
, activeMailbox : String
, modal : Maybe (Html msg)
, content : List (Html msg)
}
frame : State msg -> Html msg
frame { model, session, activePage, activeMailbox, modal, content } =
div [ class "app" ] div [ class "app" ]
[ header [] [ header []
[ nav [ class "navbar" ] [ nav [ class "navbar" ]
[ span [ class "navbar-toggle", Events.onClick controls.toggleMenu ] [ span [ class "navbar-toggle", Events.onClick (ToggleMenu |> model.mapMsg) ]
[ i [ class "fas fa-bars" ] [] ] [ i [ class "fas fa-bars" ] [] ]
, span [ class "navbar-brand" ] , span [ class "navbar-brand" ]
[ a [ Route.href Route.Home ] [ text "@ inbucket" ] ] [ a [ Route.href Route.Home ] [ text "@ inbucket" ] ]
, ul [ class "main-nav", classList [ ( "active", controls.menuVisible ) ] ] , ul [ class "main-nav", classList [ ( "active", model.menuVisible ) ] ]
[ if session.config.monitorVisible then [ if session.config.monitorVisible then
navbarLink Monitor Route.Monitor [ text "Monitor" ] activePage navbarLink Monitor Route.Monitor [ text "Monitor" ] activePage
else else
text "" text ""
, navbarLink Status Route.Status [ text "Status" ] activePage , navbarLink Status Route.Status [ text "Status" ] activePage
, navbarRecent activePage controls , navbarRecent activePage activeMailbox model session
, li [ class "navbar-mailbox" ] , li [ class "navbar-mailbox" ]
[ form [ Events.onSubmit (controls.viewMailbox controls.mailboxValue) ] [ form [ Events.onSubmit (model.viewMailbox model.mailboxName) ]
[ input [ input
[ type_ "text" [ type_ "text"
, placeholder "mailbox" , placeholder "mailbox"
, value controls.mailboxValue , value model.mailboxName
, Events.onInput controls.mailboxOnInput , Events.onInput (OnMailboxNameInput >> model.mapMsg)
] ]
[] []
] ]
@@ -76,11 +123,11 @@ frame controls session activePage modal content =
] ]
, div [ class "navbar-bg" ] [ text "" ] , div [ class "navbar-bg" ] [ text "" ]
, frameModal modal , frameModal modal
, div [ class "page" ] ([ errorFlash controls session.flash ] ++ content) , div [ class "page" ] ([ errorFlash model session.flash ] ++ content)
, footer [] , footer []
[ div [ class "footer" ] [ div [ class "footer" ]
[ externalLink "https://www.inbucket.org" "Inbucket" [ externalLink "https://www.inbucket.org" "Inbucket"
, text " is an open source projected hosted at " , text " is an open source project hosted on "
, externalLink "https://github.com/jhillyerd/inbucket" "GitHub" , externalLink "https://github.com/jhillyerd/inbucket" "GitHub"
, text "." , text "."
] ]
@@ -100,7 +147,7 @@ frameModal maybeModal =
text "" text ""
errorFlash : FrameControls msg -> Maybe Session.Flash -> Html msg errorFlash : Model msg -> Maybe Session.Flash -> Html msg
errorFlash controls maybeFlash = errorFlash controls maybeFlash =
let let
row ( heading, message ) = row ( heading, message ) =
@@ -136,8 +183,8 @@ navbarLink page route linkContent activePage =
{-| Renders list of recent mailboxes, selecting the currently active mailbox. {-| Renders list of recent mailboxes, selecting the currently active mailbox.
-} -}
navbarRecent : Page -> FrameControls msg -> Html msg navbarRecent : Page -> String -> Model msg -> Session -> Html msg
navbarRecent page controls = navbarRecent page activeMailbox model session =
let let
-- Active means we are viewing a specific mailbox. -- Active means we are viewing a specific mailbox.
active = active =
@@ -146,7 +193,7 @@ navbarRecent page controls =
-- Recent tab title is the name of the current mailbox when active. -- Recent tab title is the name of the current mailbox when active.
title = title =
if active then if active then
controls.recentActive activeMailbox
else else
"Recent Mailboxes" "Recent Mailboxes"
@@ -154,13 +201,13 @@ navbarRecent page controls =
-- Mailboxes to show in recent list, doesn't include active mailbox. -- Mailboxes to show in recent list, doesn't include active mailbox.
recentMailboxes = recentMailboxes =
if active then if active then
List.tail controls.recentOptions |> Maybe.withDefault [] List.tail session.persistent.recentMailboxes |> Maybe.withDefault []
else else
controls.recentOptions session.persistent.recentMailboxes
dropdownExpanded = dropdownExpanded =
if controls.recentVisible then if model.recentVisible then
"true" "true"
else else
@@ -173,15 +220,15 @@ navbarRecent page controls =
[ class "navbar-dropdown-container" [ class "navbar-dropdown-container"
, classList [ ( "navbar-active", active ) ] , classList [ ( "navbar-active", active ) ]
, attribute "aria-haspopup" "true" , attribute "aria-haspopup" "true"
, ariaExpanded controls.recentVisible , ariaExpanded model.recentVisible
, Events.onMouseOver (controls.showRecent True) , Events.onMouseOver (ShowRecent True |> model.mapMsg)
, Events.onMouseOut (controls.showRecent False) , Events.onMouseOut (ShowRecent False |> model.mapMsg)
] ]
[ span [ class "navbar-dropdown" ] [ span [ class "navbar-dropdown" ]
[ text title [ text title
, button , button
[ class "navbar-dropdown-button" [ class "navbar-dropdown-button"
, Events.onClick (controls.showRecent (not controls.recentVisible)) , Events.onClick (ShowRecent (not model.recentVisible) |> model.mapMsg)
] ]
[ i [ class "fas fa-chevron-down" ] [] ] [ i [ class "fas fa-chevron-down" ] [] ]
] ]

View File

@@ -23,10 +23,8 @@ import Url exposing (Url)
type alias Model = type alias Model =
{ page : PageModel { layout : Layout.Model Msg
, mailboxName : String , page : PageModel
, menuVisible : Bool
, recentVisible : Bool
} }
@@ -63,10 +61,8 @@ init configValue location key =
Home.init session Home.init session
initModel = initModel =
{ page = Home subModel { layout = Layout.init LayoutMsg ClearFlash ViewMailbox
, mailboxName = "" , page = Home subModel
, menuVisible = False
, recentVisible = False
} }
route = route =
@@ -84,10 +80,8 @@ type Msg
| SessionUpdated (Result D.Error Session.Persistent) | SessionUpdated (Result D.Error Session.Persistent)
| TimeZoneLoaded Time.Zone | TimeZoneLoaded Time.Zone
| ClearFlash | ClearFlash
| OnMailboxNameInput String
| ViewMailbox String | ViewMailbox String
| ToggleMenu | LayoutMsg Layout.Msg
| ShowRecent Bool
| HomeMsg Home.Msg | HomeMsg Home.Msg
| MailboxMsg Mailbox.Msg | MailboxMsg Mailbox.Msg
| MonitorMsg Monitor.Msg | MonitorMsg Monitor.Msg
@@ -211,19 +205,13 @@ updateMain msg model session =
, Cmd.none , Cmd.none
) )
OnMailboxNameInput name ->
( { model | mailboxName = name }, Cmd.none )
ViewMailbox name -> ViewMailbox name ->
( applyToModelSession Session.clearFlash { model | mailboxName = "" } ( applyToModelSession Session.clearFlash model
, Route.pushUrl session.key (Route.Mailbox name) , Route.pushUrl session.key (Route.Mailbox name)
) )
ToggleMenu -> LayoutMsg subMsg ->
( { model | menuVisible = not model.menuVisible }, Cmd.none ) ( { model | layout = Layout.update subMsg model.layout }, Cmd.none )
ShowRecent visible ->
( { model | recentVisible = visible }, Cmd.none )
_ -> _ ->
updatePage msg model updatePage msg model
@@ -262,7 +250,7 @@ changeRouteTo route model =
getSession model getSession model
newModel = newModel =
{ model | menuVisible = False, recentVisible = False } { model | layout = Layout.reset model.layout }
in in
case route of case route of
Route.Unknown path -> Route.Unknown path ->
@@ -378,19 +366,6 @@ view model =
_ -> _ ->
"" ""
controls =
{ menuVisible = model.menuVisible
, toggleMenu = ToggleMenu
, recentVisible = model.recentVisible
, showRecent = ShowRecent
, viewMailbox = ViewMailbox
, mailboxOnInput = OnMailboxNameInput
, mailboxValue = model.mailboxName
, recentOptions = session.persistent.recentMailboxes
, recentActive = mailbox
, clearFlash = ClearFlash
}
framePage : framePage :
Layout.Page Layout.Page
-> (msg -> Msg) -> (msg -> Msg)
@@ -399,11 +374,13 @@ view model =
framePage page toMsg { title, modal, content } = framePage page toMsg { title, modal, content } =
Document title Document title
[ Layout.frame [ Layout.frame
controls { model = model.layout
session , session = session
page , activePage = page
(Maybe.map (Html.map toMsg) modal) , activeMailbox = mailbox
(List.map (Html.map toMsg) content) , modal = Maybe.map (Html.map toMsg) modal
, content = List.map (Html.map toMsg) content
}
] ]
in in
case model.page of case model.page of