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 Html exposing (..)
@@ -29,44 +29,91 @@ type Page
| Status
type alias FrameControls msg =
{ menuVisible : Bool
, toggleMenu : msg
, recentVisible : Bool
, showRecent : Bool -> msg
, viewMailbox : String -> msg
, mailboxOnInput : String -> msg
, mailboxValue : String
, recentOptions : List String
, recentActive : String
type alias Model msg =
{ mapMsg : Msg -> 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
frame controls session activePage modal content =
init : (Msg -> msg) -> msg -> (String -> msg) -> Model msg
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" ]
[ header []
[ 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" ] [] ]
, span [ class "navbar-brand" ]
[ 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
navbarLink Monitor Route.Monitor [ text "Monitor" ] activePage
else
text ""
, navbarLink Status Route.Status [ text "Status" ] activePage
, navbarRecent activePage controls
, navbarRecent activePage activeMailbox model session
, li [ class "navbar-mailbox" ]
[ form [ Events.onSubmit (controls.viewMailbox controls.mailboxValue) ]
[ form [ Events.onSubmit (model.viewMailbox model.mailboxName) ]
[ input
[ type_ "text"
, placeholder "mailbox"
, value controls.mailboxValue
, Events.onInput controls.mailboxOnInput
, value model.mailboxName
, Events.onInput (OnMailboxNameInput >> model.mapMsg)
]
[]
]
@@ -76,11 +123,11 @@ frame controls session activePage modal content =
]
, div [ class "navbar-bg" ] [ text "" ]
, frameModal modal
, div [ class "page" ] ([ errorFlash controls session.flash ] ++ content)
, div [ class "page" ] ([ errorFlash model session.flash ] ++ content)
, footer []
[ div [ class "footer" ]
[ 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"
, text "."
]
@@ -100,7 +147,7 @@ frameModal maybeModal =
text ""
errorFlash : FrameControls msg -> Maybe Session.Flash -> Html msg
errorFlash : Model msg -> Maybe Session.Flash -> Html msg
errorFlash controls maybeFlash =
let
row ( heading, message ) =
@@ -136,8 +183,8 @@ navbarLink page route linkContent activePage =
{-| Renders list of recent mailboxes, selecting the currently active mailbox.
-}
navbarRecent : Page -> FrameControls msg -> Html msg
navbarRecent page controls =
navbarRecent : Page -> String -> Model msg -> Session -> Html msg
navbarRecent page activeMailbox model session =
let
-- Active means we are viewing a specific mailbox.
active =
@@ -146,7 +193,7 @@ navbarRecent page controls =
-- Recent tab title is the name of the current mailbox when active.
title =
if active then
controls.recentActive
activeMailbox
else
"Recent Mailboxes"
@@ -154,13 +201,13 @@ navbarRecent page controls =
-- Mailboxes to show in recent list, doesn't include active mailbox.
recentMailboxes =
if active then
List.tail controls.recentOptions |> Maybe.withDefault []
List.tail session.persistent.recentMailboxes |> Maybe.withDefault []
else
controls.recentOptions
session.persistent.recentMailboxes
dropdownExpanded =
if controls.recentVisible then
if model.recentVisible then
"true"
else
@@ -173,15 +220,15 @@ navbarRecent page controls =
[ class "navbar-dropdown-container"
, classList [ ( "navbar-active", active ) ]
, attribute "aria-haspopup" "true"
, ariaExpanded controls.recentVisible
, Events.onMouseOver (controls.showRecent True)
, Events.onMouseOut (controls.showRecent False)
, ariaExpanded model.recentVisible
, Events.onMouseOver (ShowRecent True |> model.mapMsg)
, Events.onMouseOut (ShowRecent False |> model.mapMsg)
]
[ span [ class "navbar-dropdown" ]
[ text title
, 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" ] [] ]
]

View File

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