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:
@@ -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" ] [] ]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user