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

Merge branch 'feature/mouse-out-delay' into develop

This commit is contained in:
James Hillyerd
2020-04-05 17:47:57 -07:00
2 changed files with 120 additions and 18 deletions

View File

@@ -38,7 +38,10 @@ import Html.Attributes
) )
import Html.Events as Events import Html.Events as Events
import Modal import Modal
import Process
import Route exposing (Route) import Route exposing (Route)
import Task
import Timer exposing (Timer)
{-| Used to highlight current page in navbar. {-| Used to highlight current page in navbar.
@@ -52,8 +55,9 @@ type Page
type alias Model msg = type alias Model msg =
{ mapMsg : Msg -> msg { mapMsg : Msg -> msg
, menuVisible : Bool , mainMenuVisible : Bool
, recentVisible : Bool , recentMenuVisible : Bool
, recentMenuTimer : Timer
, mailboxName : String , mailboxName : String
} }
@@ -61,8 +65,9 @@ type alias Model msg =
init : (Msg -> msg) -> Model msg init : (Msg -> msg) -> Model msg
init mapMsg = init mapMsg =
{ mapMsg = mapMsg { mapMsg = mapMsg
, menuVisible = False , mainMenuVisible = False
, recentVisible = False , recentMenuVisible = False
, recentMenuTimer = Timer.empty
, mailboxName = "" , mailboxName = ""
} }
@@ -72,20 +77,24 @@ init mapMsg =
reset : Model msg -> Model msg reset : Model msg -> Model msg
reset model = reset model =
{ model { model
| menuVisible = False | mainMenuVisible = False
, recentVisible = False , recentMenuVisible = False
, recentMenuTimer = Timer.cancel model.recentMenuTimer
, mailboxName = "" , mailboxName = ""
} }
type Msg type Msg
= ClearFlash = ClearFlash
| MainMenuToggled
| ModalFocused Modal.Msg | ModalFocused Modal.Msg
| ModalUnfocused | ModalUnfocused
| OnMailboxNameInput String | OnMailboxNameInput String
| OpenMailbox | OpenMailbox
| ShowRecent Bool | RecentMenuMouseOver
| ToggleMenu | RecentMenuMouseOut
| RecentMenuTimeout Timer
| RecentMenuToggled
update : Msg -> Model msg -> Session -> ( Model msg, Session, Cmd msg ) update : Msg -> Model msg -> Session -> ( Model msg, Session, Cmd msg )
@@ -97,6 +106,12 @@ update msg model session =
, Cmd.none , Cmd.none
) )
MainMenuToggled ->
( { model | mainMenuVisible = not model.mainMenuVisible }
, session
, Cmd.none
)
ModalFocused message -> ModalFocused message ->
( model ( model
, Modal.updateSession message session , Modal.updateSession message session
@@ -122,14 +137,43 @@ update msg model session =
, Route.pushUrl session.key (Route.Mailbox model.mailboxName) , Route.pushUrl session.key (Route.Mailbox model.mailboxName)
) )
ShowRecent visible -> RecentMenuMouseOver ->
( { model | recentVisible = visible } ( { model
| recentMenuVisible = True
, recentMenuTimer = Timer.cancel model.recentMenuTimer
}
, session , session
, Cmd.none , Cmd.none
) )
ToggleMenu -> RecentMenuMouseOut ->
( { model | menuVisible = not model.menuVisible } let
newTimer =
Timer.replace model.recentMenuTimer
in
( { model
| recentMenuTimer = newTimer
}
, session
, Timer.schedule (RecentMenuTimeout >> model.mapMsg) newTimer 400
)
RecentMenuTimeout timer ->
if timer == model.recentMenuTimer then
( { model
| recentMenuVisible = False
, recentMenuTimer = Timer.cancel timer
}
, session
, Cmd.none
)
else
-- Timer was no longer valid.
( model, session, Cmd.none )
RecentMenuToggled ->
( { model | recentMenuVisible = not model.recentMenuVisible }
, session , session
, Cmd.none , Cmd.none
) )
@@ -150,11 +194,11 @@ frame { model, session, activePage, activeMailbox, modal, content } =
div [ class "app" ] div [ class "app" ]
[ header [] [ header []
[ nav [ class "navbar" ] [ nav [ class "navbar" ]
[ button [ class "navbar-toggle", Events.onClick (ToggleMenu |> model.mapMsg) ] [ button [ class "navbar-toggle", Events.onClick (MainMenuToggled |> 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", model.menuVisible ) ] ] , ul [ class "main-nav", classList [ ( "active", model.mainMenuVisible ) ] ]
[ if session.config.monitorVisible then [ if session.config.monitorVisible then
navbarLink Monitor Route.Monitor [ text "Monitor" ] activePage navbarLink Monitor Route.Monitor [ text "Monitor" ] activePage
@@ -256,15 +300,15 @@ navbarRecent page activeMailbox model session =
[ 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 model.recentVisible , ariaExpanded model.recentMenuVisible
, Events.onMouseOver (ShowRecent True |> model.mapMsg) , Events.onMouseOver (RecentMenuMouseOver |> model.mapMsg)
, Events.onMouseOut (ShowRecent False |> model.mapMsg) , Events.onMouseOut (RecentMenuMouseOut |> 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 (ShowRecent (not model.recentVisible) |> model.mapMsg) , Events.onClick (RecentMenuToggled |> model.mapMsg)
] ]
[ i [ class "fas fa-chevron-down" ] [] ] [ i [ class "fas fa-chevron-down" ] [] ]
] ]

58
ui/src/Timer.elm Normal file
View File

@@ -0,0 +1,58 @@
module Timer exposing (Timer, cancel, empty, replace, schedule)
import Process
import Task
{-| Implements an identity to track an asynchronous timer.
-}
type Timer
= Empty
| Idle Int
| Timer Int
empty : Timer
empty =
Empty
schedule : (Timer -> msg) -> Timer -> Float -> Cmd msg
schedule message timer millis =
Task.perform (always (message timer)) (Process.sleep millis)
{-| Replaces the provided timer with a newly created one.
-}
replace : Timer -> Timer
replace previous =
case previous of
Empty ->
Timer 0
Idle index ->
Timer (next index)
Timer index ->
Timer (next index)
{-| Cancels the provided timer without creating a replacement.
-}
cancel : Timer -> Timer
cancel previous =
case previous of
Timer index ->
Idle index
_ ->
previous
next : Int -> Int
next index =
if index > 2 ^ 30 then
0
else
index + 1