diff --git a/ui/v2.5/src/components/Changelog/versions/v0110.md b/ui/v2.5/src/components/Changelog/versions/v0110.md index 3fe202ac1..44a36205b 100644 --- a/ui/v2.5/src/components/Changelog/versions/v0110.md +++ b/ui/v2.5/src/components/Changelog/versions/v0110.md @@ -8,6 +8,7 @@ * Added interface options to disable creating performers/studios/tags from dropdown selectors. ([#1814](https://github.com/stashapp/stash/pull/1814)) ### 🎨 Improvements +* Reworked main navbar and positioned at bottom for mobile devices. ([#1769](https://github.com/stashapp/stash/pull/1769)) * Show files being deleted in the Delete dialogs. ([#1852](https://github.com/stashapp/stash/pull/1852)) * Added specific page titles. ([#1831](https://github.com/stashapp/stash/pull/1831)) * Added es-ES language option. ([#1886](https://github.com/stashapp/stash/pull/1886)) diff --git a/ui/v2.5/src/components/MainNavbar.tsx b/ui/v2.5/src/components/MainNavbar.tsx index 3cde0140f..330ffa4ad 100644 --- a/ui/v2.5/src/components/MainNavbar.tsx +++ b/ui/v2.5/src/components/MainNavbar.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useRef, useState, useCallback } from "react"; import { defineMessages, FormattedMessage, @@ -21,6 +21,8 @@ interface IMenuItem { message: MessageDescriptor; href: string; icon: IconName; + hotkey: string; + userCreatable?: boolean; } const messages = defineMessages({ @@ -72,51 +74,68 @@ const allMenuItems: IMenuItem[] = [ message: messages.scenes, href: "/scenes", icon: "play-circle", + hotkey: "g s", }, { name: "images", message: messages.images, href: "/images", icon: "image", + hotkey: "g i", }, { name: "movies", message: messages.movies, href: "/movies", icon: "film", + hotkey: "g v", + userCreatable: true, }, { name: "markers", message: messages.markers, href: "/scenes/markers", icon: "map-marker-alt", + hotkey: "g k", }, { name: "galleries", message: messages.galleries, href: "/galleries", icon: "images", + hotkey: "g l", + userCreatable: true, }, { name: "performers", message: messages.performers, href: "/performers", icon: "user", + hotkey: "g p", + userCreatable: true, }, { name: "studios", message: messages.studios, href: "/studios", icon: "video", + hotkey: "g u", + userCreatable: true, }, { name: "tags", message: messages.tags, href: "/tags", icon: "tag", + hotkey: "g t", + userCreatable: true, }, ]; +const newPathsList = allMenuItems + .filter((item) => item.userCreatable) + .map((item) => item.href); + export const MainNavbar: React.FC = () => { const history = useHistory(); const location = useLocation(); @@ -144,15 +163,18 @@ export const MainNavbar: React.FC = () => { const navbarRef = useRef(); const intl = useIntl(); - const maybeCollapse = (event: Event) => { - if ( - navbarRef.current && - event.target instanceof Node && - !navbarRef.current.contains(event.target) - ) { - setExpanded(false); - } - }; + const maybeCollapse = useCallback( + (event: Event) => { + if ( + navbarRef.current && + event.target instanceof Node && + !navbarRef.current.contains(event.target) + ) { + setExpanded(false); + } + }, + [setExpanded] + ); useEffect(() => { if (expanded) { @@ -163,65 +185,38 @@ export const MainNavbar: React.FC = () => { document.removeEventListener("click", maybeCollapse); document.removeEventListener("touchstart", maybeCollapse); }; - }, [expanded]); + }, [expanded, maybeCollapse]); - function goto(page: string) { - history.push(page); - if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur(); - } - } + const goto = useCallback( + (page: string) => { + history.push(page); + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + }, + [history] + ); - const newPath = - location.pathname === "/performers" - ? "/performers/new" - : location.pathname === "/studios" - ? "/studios/new" - : location.pathname === "/movies" - ? "/movies/new" - : location.pathname === "/tags" - ? "/tags/new" - : location.pathname === "/galleries" - ? "/galleries/new" - : null; - const newButton = - newPath === null ? ( - "" - ) : ( - - - - ); + const { pathname } = location; + const newPath = newPathsList.includes(pathname) ? `${pathname}/new` : null; // set up hotkeys useEffect(() => { Mousetrap.bind("?", () => setShowManual(!showManual)); - Mousetrap.bind("g s", () => goto("/scenes")); - Mousetrap.bind("g i", () => goto("/images")); - Mousetrap.bind("g v", () => goto("/movies")); - Mousetrap.bind("g k", () => goto("/scenes/markers")); - Mousetrap.bind("g l", () => goto("/galleries")); - Mousetrap.bind("g p", () => goto("/performers")); - Mousetrap.bind("g u", () => goto("/studios")); - Mousetrap.bind("g t", () => goto("/tags")); Mousetrap.bind("g z", () => goto("/settings")); + menuItems.forEach((item) => + Mousetrap.bind(item.hotkey, () => goto(item.href)) + ); + if (newPath) { Mousetrap.bind("n", () => history.push(newPath)); } return () => { Mousetrap.unbind("?"); - Mousetrap.unbind("g s"); - Mousetrap.unbind("g v"); - Mousetrap.unbind("g k"); - Mousetrap.unbind("g l"); - Mousetrap.unbind("g p"); - Mousetrap.unbind("g u"); - Mousetrap.unbind("g t"); Mousetrap.unbind("g z"); + menuItems.forEach((item) => Mousetrap.unbind(item.hotkey)); if (newPath) { Mousetrap.unbind("n"); @@ -232,13 +227,60 @@ export const MainNavbar: React.FC = () => { function maybeRenderLogout() { if (SessionUtils.isLoggedIn()) { return ( - ); } } + const handleDismiss = useCallback(() => setExpanded(false), [setExpanded]); + + function renderUtilityButtons() { + return ( + <> + + + + + + + + {maybeRenderLogout()} + + ); + } + return ( <> setShowManual(false)} /> @@ -253,62 +295,54 @@ export const MainNavbar: React.FC = () => { onToggle={setExpanded} ref={navbarRef} > - setExpanded(false)} - > - - - - - - - + - + <> + + + -