diff --git a/ui/src/Layout.elm b/ui/src/Layout.elm index 7a58956..18f1d6f 100644 --- a/ui/src/Layout.elm +++ b/ui/src/Layout.elm @@ -36,6 +36,8 @@ type alias FrameControls msg = , recentOptions : List String , recentActive : String , clearFlash : msg + , showMenu : Bool + , toggleMenu : msg } @@ -43,26 +45,30 @@ frame : FrameControls msg -> Session -> Page -> Maybe (Html msg) -> List (Html m frame controls session activePage modal content = div [ class "app" ] [ header [] - [ ul [ class "navbar", attribute "role" "navigation" ] - [ li [ class "navbar-brand" ] + [ nav [ class "navbar" ] + [ span [ class "navbar-toggle", Events.onClick controls.toggleMenu ] + [ i [ class "fas fa-bars" ] [] ] + , span [ class "navbar-brand" ] [ a [ Route.href Route.Home ] [ text "@ inbucket" ] ] - , if session.config.monitorVisible then - navbarLink Monitor Route.Monitor [ text "Monitor" ] activePage - - else - text "" - , navbarLink Status Route.Status [ text "Status" ] activePage - , navbarRecent activePage controls - , li [ class "navbar-mailbox" ] - [ form [ Events.onSubmit (controls.viewMailbox controls.mailboxValue) ] - [ input - [ type_ "text" - , placeholder "mailbox" - , value controls.mailboxValue - , Events.onInput controls.mailboxOnInput + , ul [ classList [ ( "main-nav", True ), ( "active", controls.showMenu ) ] ] + [ li [ class "navbar-mailbox" ] + [ form [ Events.onSubmit (controls.viewMailbox controls.mailboxValue) ] + [ input + [ type_ "text" + , placeholder "mailbox" + , value controls.mailboxValue + , Events.onInput controls.mailboxOnInput + ] + [] ] - [] ] + , if session.config.monitorVisible then + navbarLink Monitor Route.Monitor [ text "Monitor" ] activePage + + else + text "" + , navbarLink Status Route.Status [ text "Status" ] activePage + , navbarRecent activePage controls ] ] ] @@ -123,7 +129,7 @@ externalLink url title = navbarLink : Page -> Route -> List (Html a) -> Page -> Html a navbarLink page route linkContent activePage = li [ classList [ ( "navbar-active", page == activePage ) ] ] - [ a [ Route.href route ] linkContent ] + [ a [ class "navbar-active-bg", Route.href route ] linkContent ] {-| Renders list of recent mailboxes, selecting the currently active mailbox. @@ -157,6 +163,6 @@ navbarRecent page controls = [ class "navbar-recent" , classList [ ( "navbar-dropdown", True ), ( "navbar-active", active ) ] ] - [ span [] [ text title ] + [ span [ class "navbar-active-bg" ] [ text title ] , div [ class "navbar-dropdown-content" ] (List.map recentLink recentMailboxes) ] diff --git a/ui/src/Main.elm b/ui/src/Main.elm index cebecaf..10b50d9 100644 --- a/ui/src/Main.elm +++ b/ui/src/Main.elm @@ -25,6 +25,7 @@ import Url exposing (Url) type alias Model = { page : PageModel , mailboxName : String + , showMenu : Bool } @@ -63,6 +64,7 @@ init configValue location key = initModel = { page = Home subModel , mailboxName = "" + , showMenu = False } route = @@ -82,6 +84,7 @@ type Msg | ClearFlash | OnMailboxNameInput String | ViewMailbox String + | ToggleMenu | HomeMsg Home.Msg | MailboxMsg Mailbox.Msg | MonitorMsg Monitor.Msg @@ -213,6 +216,9 @@ updateMain msg model session = , Route.pushUrl session.key (Route.Mailbox name) ) + ToggleMenu -> + ( { model | showMenu = not model.showMenu }, Cmd.none ) + _ -> updatePage msg model @@ -248,6 +254,9 @@ changeRouteTo route model = let session = getSession model + + newModel = + { model | showMenu = False } in case route of Route.Unknown path -> @@ -257,26 +266,26 @@ changeRouteTo route model = , table = [ ( "Path", path ) ] } in - ( applyToModelSession (Session.showFlash flash) model + ( applyToModelSession (Session.showFlash flash) newModel , Cmd.none ) Route.Home -> Home.init session - |> updateWith Home HomeMsg model + |> updateWith Home HomeMsg newModel Route.Mailbox name -> Mailbox.init session name Nothing - |> updateWith Mailbox MailboxMsg model + |> updateWith Mailbox MailboxMsg newModel Route.Message mailbox id -> Mailbox.init session mailbox (Just id) - |> updateWith Mailbox MailboxMsg model + |> updateWith Mailbox MailboxMsg newModel Route.Monitor -> if session.config.monitorVisible then Monitor.init session - |> updateWith Monitor MonitorMsg model + |> updateWith Monitor MonitorMsg newModel else let @@ -285,13 +294,13 @@ changeRouteTo route model = , table = [ ( "Error", "Monitor disabled by configuration." ) ] } in - ( applyToModelSession (Session.showFlash flash) model + ( applyToModelSession (Session.showFlash flash) newModel , Cmd.none ) Route.Status -> Status.init session - |> updateWith Status StatusMsg model + |> updateWith Status StatusMsg newModel getSession : Model -> Session @@ -370,6 +379,8 @@ view model = , recentOptions = session.persistent.recentMailboxes , recentActive = mailbox , clearFlash = ClearFlash + , showMenu = model.showMenu + , toggleMenu = ToggleMenu } framePage : diff --git a/ui/src/navbar.css b/ui/src/navbar.css index 804c2b5..d0b905b 100644 --- a/ui/src/navbar.css +++ b/ui/src/navbar.css @@ -1,17 +1,94 @@ /** NAV BAR */ -@media screen and (min-width: 768px) { - .navbar, +:root { + --navbar-color: #9d9d9d; +} + +.navbar { + background-color: #222; + background-image: linear-gradient(to bottom, #3c3c3c 0, #222 100%); + text-shadow: 0 -1px 0 rgba(0,0,0,0.2); +} + +.main-nav { + display: none; + list-style: none; +} + +.main-nav.active { + display: block; +} + +.navbar-brand { + font-size: 18px; +} + +.navbar-toggle { + color: var(--navbar-color); + font-size: 24px; + position: absolute; + top: 10px; + right: 20px; +} + +.navbar a, +.navbar-dropdown span { + color: var(--navbar-color); + display: block; + padding: 15px; + text-decoration: none; +} + +.navbar li { + color: var(--navbar-color); +} + +li.navbar-active .navbar-active-bg { + background-color: #080808; +} + +li.navbar-active a, +li.navbar-active span, +.navbar a:hover { + color: #ffffff; +} + +.navbar-dropdown-content { +} + +.navbar-dropdown-content a { + background: transparent !important; + color: var(--navbar-color) !important; + display: block; +} + +.navbar-mailbox { + padding: 15px; +} + +.navbar-mailbox input { + border: 1px solid var(--border-color); + border-radius: 4px; + padding: 5px 10px; + width: 250px; +} + +@media screen and (min-width: 1000px) { + .main-nav, .navbar-bg { height: 50px; } .navbar { + align-items: center; display: flex; + } + + .main-nav { + display: flex; + flex-grow: 2; line-height: 20px; - list-style: none; padding: 0; - text-shadow: 0 -1px 0 rgba(0,0,0,0.2); } .navbar-bg { @@ -23,30 +100,7 @@ z-index: -1; } - .navbar li { - color: #9d9d9d; - } - - .navbar a, - .navbar-dropdown span { - color: #9d9d9d; - display: inline-block; - padding: 15px; - text-decoration: none; - } - - li.navbar-active { - background-color: #080808; - } - - li.navbar-active a, - li.navbar-active span, - .navbar a:hover { - color: #ffffff; - } - .navbar-brand { - font-size: 18px; margin-left: -15px; } @@ -54,16 +108,8 @@ margin: 0 auto; } - .navbar-mailbox { - padding: 8px 0 !important; - } - .navbar-mailbox input { - border: 1px solid var(--border-color); - border-radius: 4px; - padding: 5px 10px; margin-top: 1px; - width: 250px; } .navbar-dropdown-content {