From b16dada82ed848b2e3f89f80147702bee21d49de Mon Sep 17 00:00:00 2001 From: Tristan Espinoza Date: Fri, 15 Nov 2024 16:22:23 -0800 Subject: [PATCH 1/9] fix: renamed files, components, imports, exports, contexts, and methods --- .../{Nav/NavBar.jsx => Menubar/Menubar.jsx} | 54 ++++---- .../MenubarItem.jsx} | 12 +- .../MenubarMenu.jsx} | 16 +-- .../components/{Nav => Menubar}/contexts.jsx | 6 +- .../IDE/components/Header/MobileNav.jsx | 10 +- client/modules/IDE/components/Header/Nav.jsx | 124 +++++++++--------- 6 files changed, 109 insertions(+), 113 deletions(-) rename client/components/{Nav/NavBar.jsx => Menubar/Menubar.jsx} (51%) rename client/components/{Nav/NavMenuItem.jsx => Menubar/MenubarItem.jsx} (73%) rename client/components/{Nav/NavDropdownMenu.jsx => Menubar/MenubarMenu.jsx} (75%) rename client/components/{Nav => Menubar}/contexts.jsx (62%) diff --git a/client/components/Nav/NavBar.jsx b/client/components/Menubar/Menubar.jsx similarity index 51% rename from client/components/Nav/NavBar.jsx rename to client/components/Menubar/Menubar.jsx index c8ae7c6377..ebd78b97d5 100644 --- a/client/components/Nav/NavBar.jsx +++ b/client/components/Menubar/Menubar.jsx @@ -1,16 +1,16 @@ import PropTypes from 'prop-types'; import React, { useCallback, useMemo, useRef, useState } from 'react'; import useModalClose from '../../common/useModalClose'; -import { MenuOpenContext, NavBarContext } from './contexts'; +import { MenuOpenContext, MenubarContext } from './contexts'; -function NavBar({ children, className }) { - const [dropdownOpen, setDropdownOpen] = useState('none'); +function Menubar({ children, className }) { + const [menuOpen, setMenuOpen] = useState('none'); const timerRef = useRef(null); const handleClose = useCallback(() => { - setDropdownOpen('none'); - }, [setDropdownOpen]); + setMenuOpen('none'); + }, [setMenuOpen]); const nodeRef = useModalClose(handleClose); @@ -22,71 +22,67 @@ function NavBar({ children, className }) { }, [timerRef]); const handleBlur = useCallback(() => { - timerRef.current = setTimeout(() => setDropdownOpen('none'), 10); - }, [timerRef, setDropdownOpen]); + timerRef.current = setTimeout(() => setMenuOpen('none'), 10); + }, [timerRef, setMenuOpen]); - const toggleDropdownOpen = useCallback( - (dropdown) => { - setDropdownOpen((prevState) => - prevState === dropdown ? 'none' : dropdown - ); + const toggleMenuOpen = useCallback( + (menu) => { + setMenuOpen((prevState) => (prevState === menu ? 'none' : menu)); }, - [setDropdownOpen] + [setMenuOpen] ); const contextValue = useMemo( () => ({ - createDropdownHandlers: (dropdown) => ({ + createMenuHandlers: (menu) => ({ onMouseOver: () => { - setDropdownOpen((prevState) => - prevState === 'none' ? 'none' : dropdown - ); + setMenuOpen((prevState) => (prevState === 'none' ? 'none' : menu)); }, onClick: () => { - toggleDropdownOpen(dropdown); + toggleMenuOpen(menu); }, onBlur: handleBlur, onFocus: clearHideTimeout }), - createMenuItemHandlers: (dropdown) => ({ + createMenuItemHandlers: (menu) => ({ onMouseUp: (e) => { if (e.button === 2) { return; } - setDropdownOpen('none'); + setMenuOpen('none'); }, onBlur: handleBlur, onFocus: () => { clearHideTimeout(); - setDropdownOpen(dropdown); + setMenuOpen(menu); } }), - toggleDropdownOpen + toggleMenuOpen }), - [setDropdownOpen, toggleDropdownOpen, clearHideTimeout, handleBlur] + [setMenuOpen, toggleMenuOpen, clearHideTimeout, handleBlur] ); return ( - +
- + {children}
-
+ ); } -NavBar.propTypes = { +Menubar.propTypes = { children: PropTypes.node, className: PropTypes.string }; -NavBar.defaultProps = { +Menubar.defaultProps = { children: null, className: 'nav' }; -export default NavBar; +export default Menubar; diff --git a/client/components/Nav/NavMenuItem.jsx b/client/components/Menubar/MenubarItem.jsx similarity index 73% rename from client/components/Nav/NavMenuItem.jsx rename to client/components/Menubar/MenubarItem.jsx index 09436e43ee..8c08aa9c03 100644 --- a/client/components/Nav/NavMenuItem.jsx +++ b/client/components/Menubar/MenubarItem.jsx @@ -1,12 +1,12 @@ import PropTypes from 'prop-types'; import React, { useContext, useMemo } from 'react'; import ButtonOrLink from '../../common/ButtonOrLink'; -import { NavBarContext, ParentMenuContext } from './contexts'; +import { MenubarContext, ParentMenuContext } from './contexts'; -function NavMenuItem({ hideIf, className, ...rest }) { +function MenubarItem({ hideIf, className, ...rest }) { const parent = useContext(ParentMenuContext); - const { createMenuItemHandlers } = useContext(NavBarContext); + const { createMenuItemHandlers } = useContext(MenubarContext); const handlers = useMemo(() => createMenuItemHandlers(parent), [ createMenuItemHandlers, @@ -24,7 +24,7 @@ function NavMenuItem({ hideIf, className, ...rest }) { ); } -NavMenuItem.propTypes = { +MenubarItem.propTypes = { ...ButtonOrLink.propTypes, onClick: PropTypes.func, value: PropTypes.string, @@ -35,11 +35,11 @@ NavMenuItem.propTypes = { className: PropTypes.string }; -NavMenuItem.defaultProps = { +MenubarItem.defaultProps = { onClick: null, value: null, hideIf: false, className: 'nav__dropdown-item' }; -export default NavMenuItem; +export default MenubarItem; diff --git a/client/components/Nav/NavDropdownMenu.jsx b/client/components/Menubar/MenubarMenu.jsx similarity index 75% rename from client/components/Nav/NavDropdownMenu.jsx rename to client/components/Menubar/MenubarMenu.jsx index d2c5744c46..4dd47d3fb5 100644 --- a/client/components/Nav/NavDropdownMenu.jsx +++ b/client/components/Menubar/MenubarMenu.jsx @@ -2,24 +2,24 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import React, { useContext, useMemo } from 'react'; import TriangleIcon from '../../images/down-filled-triangle.svg'; -import { MenuOpenContext, NavBarContext, ParentMenuContext } from './contexts'; +import { MenuOpenContext, MenubarContext, ParentMenuContext } from './contexts'; export function useMenuProps(id) { const activeMenu = useContext(MenuOpenContext); const isOpen = id === activeMenu; - const { createDropdownHandlers } = useContext(NavBarContext); + const { createMenuHandlers } = useContext(MenubarContext); - const handlers = useMemo(() => createDropdownHandlers(id), [ - createDropdownHandlers, + const handlers = useMemo(() => createMenuHandlers(id), [ + createMenuHandlers, id ]); return { isOpen, handlers }; } -function NavDropdownMenu({ id, title, children }) { +function MenubarMenu({ id, title, children }) { const { isOpen, handlers } = useMenuProps(id); return ( @@ -46,14 +46,14 @@ function NavDropdownMenu({ id, title, children }) { ); } -NavDropdownMenu.propTypes = { +MenubarMenu.propTypes = { id: PropTypes.string.isRequired, title: PropTypes.node.isRequired, children: PropTypes.node }; -NavDropdownMenu.defaultProps = { +MenubarMenu.defaultProps = { children: null }; -export default NavDropdownMenu; +export default MenubarMenu; diff --git a/client/components/Nav/contexts.jsx b/client/components/Menubar/contexts.jsx similarity index 62% rename from client/components/Nav/contexts.jsx rename to client/components/Menubar/contexts.jsx index 896d7283f4..ab3bb9ffcf 100644 --- a/client/components/Nav/contexts.jsx +++ b/client/components/Menubar/contexts.jsx @@ -4,8 +4,8 @@ export const ParentMenuContext = createContext('none'); export const MenuOpenContext = createContext('none'); -export const NavBarContext = createContext({ - createDropdownHandlers: () => ({}), +export const MenubarContext = createContext({ + createMenuHandlers: () => ({}), createMenuItemHandlers: () => ({}), - toggleDropdownOpen: () => {} + toggleMenuOpen: () => {} }); diff --git a/client/modules/IDE/components/Header/MobileNav.jsx b/client/modules/IDE/components/Header/MobileNav.jsx index 37fa16bed3..c1fd718a8f 100644 --- a/client/modules/IDE/components/Header/MobileNav.jsx +++ b/client/modules/IDE/components/Header/MobileNav.jsx @@ -5,10 +5,10 @@ import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import { sortBy } from 'lodash'; import classNames from 'classnames'; -import { ParentMenuContext } from '../../../../components/Nav/contexts'; -import NavBar from '../../../../components/Nav/NavBar'; -import { useMenuProps } from '../../../../components/Nav/NavDropdownMenu'; -import NavMenuItem from '../../../../components/Nav/NavMenuItem'; +import { ParentMenuContext } from '../../../../components/Menubar/contexts'; +import Menubar from '../../../../components/Menubar/Menubar'; +import { useMenuProps } from '../../../../components/Menubar/MenubarMenu'; +import NavMenuItem from '../../../../components/Menubar/MenubarItem'; import { prop, remSize } from '../../../../theme'; import AsteriskIcon from '../../../../images/p5-asterisk.svg'; import IconButton from '../../../../common/IconButton'; @@ -36,7 +36,7 @@ import Overlay from '../../../App/components/Overlay'; import ProjectName from './ProjectName'; import CollectionCreate from '../../../User/components/CollectionCreate'; -const Nav = styled(NavBar)` +const Nav = styled(Menubar)` background: ${prop('MobilePanel.default.background')}; color: ${prop('primaryTextColor')}; padding: ${remSize(8)} 0; diff --git a/client/modules/IDE/components/Header/Nav.jsx b/client/modules/IDE/components/Header/Nav.jsx index 3492c4388a..dc6b0c6b71 100644 --- a/client/modules/IDE/components/Header/Nav.jsx +++ b/client/modules/IDE/components/Header/Nav.jsx @@ -4,13 +4,13 @@ import { sortBy } from 'lodash'; import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; -import NavDropdownMenu from '../../../../components/Nav/NavDropdownMenu'; -import NavMenuItem from '../../../../components/Nav/NavMenuItem'; +import MenubarMenu from '../../../../components/Menubar/MenubarMenu'; +import MenubarItem from '../../../../components/Menubar/MenubarItem'; import { availableLanguages, languageKeyToLabel } from '../../../../i18n'; import getConfig from '../../../../utils/getConfig'; import { showToast } from '../../actions/toast'; import { setLanguage } from '../../actions/preferences'; -import NavBar from '../../../../components/Nav/NavBar'; +import Menubar from '../../../../components/Menubar/Menubar'; import CaretLeftIcon from '../../../../images/left-arrow.svg'; import LogoIcon from '../../../../images/p5js-logo-small.svg'; import { selectRootFile } from '../../selectors/files'; @@ -37,10 +37,10 @@ const Nav = ({ layout }) => { return isMobile ? ( ) : ( - + - + ); }; @@ -159,9 +159,9 @@ const ProjectMenu = () => { )} - - {t('Nav.File.New')} - + {t('Nav.File.New')} + { > {t('Common.Save')} {metaKeyName}+S - - + dispatch(cloneProject())} > {t('Nav.File.Duplicate')} - - + + {t('Nav.File.Share')} - - + + {t('Nav.File.Download')} - - + {t('Nav.File.Open')} - - + { href={`/${user.username}/sketches/${project?.id}/add-to-collection`} > {t('Nav.File.AddToCollection')} - - + {t('Nav.File.Examples')} - - - - + + + + {t('Nav.Edit.TidyCode')} {metaKeyName}+Shift+F - - + + {t('Nav.Edit.Find')} {metaKeyName}+F - - + + {t('Nav.Edit.Replace')} {replaceCommand} - - - - dispatch(newFile(rootFile.id))}> + + + + dispatch(newFile(rootFile.id))}> {t('Nav.Sketch.AddFile')} {newFileCommand} - - dispatch(newFolder(rootFile.id))}> + + dispatch(newFolder(rootFile.id))}> {t('Nav.Sketch.AddFolder')} - - dispatch(startSketch())}> + + dispatch(startSketch())}> {t('Nav.Sketch.Run')} {metaKeyName}+Enter - - dispatch(stopSketch())}> + + dispatch(stopSketch())}> {t('Nav.Sketch.Stop')} Shift+{metaKeyName}+Enter - - - - dispatch(showKeyboardShortcutModal())}> + + + + dispatch(showKeyboardShortcutModal())}> {t('Nav.Help.KeyboardShortcuts')} - - + + {t('Nav.Help.Reference')} - - {t('Nav.Help.About')} - + + {t('Nav.Help.About')} + ); }; @@ -261,14 +261,14 @@ const LanguageMenu = () => { } return ( - + {sortBy(availableLanguages).map((key) => ( // eslint-disable-next-line react/jsx-no-bind - + {languageKeyToLabel(key)} - + ))} - + ); }; @@ -305,7 +305,7 @@ const AuthenticatedUserMenu = () => { return ( ); }; From 0f9cf65c9c050ebed8c86bd9070f41ac1b29a3f0 Mon Sep 17 00:00:00 2001 From: Tristan Espinoza Date: Mon, 18 Nov 2024 14:05:14 -0800 Subject: [PATCH 2/9] refactor: separated UserMenu from the menubar component, wrapped both in a header container, removed navigation role from UserMenu --- client/components/Menubar/Menubar.jsx | 12 +++++------- client/modules/IDE/components/Header/Nav.jsx | 16 ++++++++++------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/client/components/Menubar/Menubar.jsx b/client/components/Menubar/Menubar.jsx index ebd78b97d5..b806246515 100644 --- a/client/components/Menubar/Menubar.jsx +++ b/client/components/Menubar/Menubar.jsx @@ -64,13 +64,11 @@ function Menubar({ children, className }) { return ( -
-
- - {children} - -
-
+
+ + {children} + +
); } diff --git a/client/modules/IDE/components/Header/Nav.jsx b/client/modules/IDE/components/Header/Nav.jsx index dc6b0c6b71..0e5f2cdac7 100644 --- a/client/modules/IDE/components/Header/Nav.jsx +++ b/client/modules/IDE/components/Header/Nav.jsx @@ -37,10 +37,14 @@ const Nav = ({ layout }) => { return isMobile ? ( ) : ( - - - - + <> +
+ + + + +
+ ); }; @@ -275,7 +279,7 @@ const LanguageMenu = () => { const UnauthenticatedUserMenu = () => { const { t } = useTranslation(); return ( -
    +
      {getConfig('TRANSLATIONS_ENABLED') && }
    • @@ -303,7 +307,7 @@ const AuthenticatedUserMenu = () => { const dispatch = useDispatch(); return ( -
        +
          {getConfig('TRANSLATIONS_ENABLED') && } Date: Mon, 18 Nov 2024 14:07:06 -0800 Subject: [PATCH 3/9] style: updated header and menubar styles --- client/styles/components/_nav.scss | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/client/styles/components/_nav.scss b/client/styles/components/_nav.scss index 1f4a7fc364..4ddc96b327 100644 --- a/client/styles/components/_nav.scss +++ b/client/styles/components/_nav.scss @@ -6,23 +6,31 @@ flex-direction: row; justify-content: space-between; - @include themify() { - border-bottom: 1px dashed map-get($theme-map, 'nav-border-color'); - } - & button { padding: 0; } } +.nav__header { + display: flex; + flex-direction: row; + justify-content: space-between; + height: 100%; + align-items: center; + + @include themify() { + border-bottom: 1px dashed map-get($theme-map, 'nav-border-color'); + } + // padding-left: #{math.div(20, $base-font-size)}rem; +} + .nav__items-left, .nav__items-right { list-style: none; display: flex; flex-direction: row; - justify-content: flex-end; - height: 100%; align-items: center; + height: 100%; } .preview-nav__editor-svg { From 246597f9442dfc70d83a80125d740fb05c6a503e Mon Sep 17 00:00:00 2001 From: Tristan Espinoza Date: Mon, 18 Nov 2024 15:52:26 -0800 Subject: [PATCH 4/9] refactor: moved LanguageMenu into left items --- client/modules/IDE/components/Header/Nav.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/modules/IDE/components/Header/Nav.jsx b/client/modules/IDE/components/Header/Nav.jsx index 0e5f2cdac7..6721209761 100644 --- a/client/modules/IDE/components/Header/Nav.jsx +++ b/client/modules/IDE/components/Header/Nav.jsx @@ -251,6 +251,7 @@ const ProjectMenu = () => { {t('Nav.Help.About')} + {getConfig('TRANSLATIONS_ENABLED') && }
        ); }; @@ -280,7 +281,6 @@ const UnauthenticatedUserMenu = () => { const { t } = useTranslation(); return (
          - {getConfig('TRANSLATIONS_ENABLED') && }
        • @@ -308,7 +308,6 @@ const AuthenticatedUserMenu = () => { return (
            - {getConfig('TRANSLATIONS_ENABLED') && } Date: Mon, 18 Nov 2024 16:06:30 -0800 Subject: [PATCH 5/9] refactor: split new MenubarMenu component into Trigger, List, and Menu components --- client/components/Menubar/MenubarMenu.jsx | 65 ++++++++++++++++------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/client/components/Menubar/MenubarMenu.jsx b/client/components/Menubar/MenubarMenu.jsx index 4dd47d3fb5..5453e6c8d8 100644 --- a/client/components/Menubar/MenubarMenu.jsx +++ b/client/components/Menubar/MenubarMenu.jsx @@ -19,29 +19,58 @@ export function useMenuProps(id) { return { isOpen, handlers }; } +function MenubarTrigger({ id, title, ...props }) { + const { isOpen, handlers } = useMenuProps(id); + + return ( + + ); +} + +MenubarTrigger.propTypes = { + id: PropTypes.string.isRequired, + title: PropTypes.node.isRequired +}; + +function MenubarList({ id, children }) { + return ( +
              + + {children} + +
            + ); +} + +MenubarList.propTypes = { + id: PropTypes.string.isRequired, + children: PropTypes.node +}; + +MenubarList.defaultProps = { + children: null +}; + function MenubarMenu({ id, title, children }) { const { isOpen, handlers } = useMenuProps(id); return (
          • - -
              - - {children} - -
            + + {children}
          • ); } From 7c3b896800f5828cf99eaa02565b760736887417 Mon Sep 17 00:00:00 2001 From: Tristan Espinoza Date: Mon, 18 Nov 2024 16:08:52 -0800 Subject: [PATCH 6/9] test: updated snapshots --- .../__snapshots__/Nav.unit.test.jsx.snap | 732 +++++++++--------- 1 file changed, 366 insertions(+), 366 deletions(-) diff --git a/client/modules/IDE/components/Header/__snapshots__/Nav.unit.test.jsx.snap b/client/modules/IDE/components/Header/__snapshots__/Nav.unit.test.jsx.snap index af56a1a418..d9140653c1 100644 --- a/client/modules/IDE/components/Header/__snapshots__/Nav.unit.test.jsx.snap +++ b/client/modules/IDE/components/Header/__snapshots__/Nav.unit.test.jsx.snap @@ -2,7 +2,9 @@ exports[`Nav renders dashboard version for desktop 1`] = ` -
            +
          - + `; exports[`Nav renders editor version for desktop 1`] = ` -
          +
        • +
        - + `; From b2eb033a463be90db1aba6daaa503d3e32094dfc Mon Sep 17 00:00:00 2001 From: Tristan Espinoza Date: Tue, 19 Nov 2024 10:06:35 -0800 Subject: [PATCH 7/9] refactor: removed menuitem roles from sign up and login, added role=presentation to or --- client/modules/IDE/components/Header/Nav.jsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/modules/IDE/components/Header/Nav.jsx b/client/modules/IDE/components/Header/Nav.jsx index 6721209761..6ddc38bda2 100644 --- a/client/modules/IDE/components/Header/Nav.jsx +++ b/client/modules/IDE/components/Header/Nav.jsx @@ -282,15 +282,17 @@ const UnauthenticatedUserMenu = () => { return (
        • - + {t('Nav.Login')}
        • -
        • {t('Nav.LoginOr')}
        • +
        • + {t('Nav.LoginOr')} +
        • - + {t('Nav.SignUp')} From 06e915277cbb3471cb9c2523c2853c43a0b6637c Mon Sep 17 00:00:00 2001 From: Tristan Espinoza Date: Tue, 19 Nov 2024 10:08:02 -0800 Subject: [PATCH 8/9] fix: lint fixes --- client/components/Menubar/MenubarMenu.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/components/Menubar/MenubarMenu.jsx b/client/components/Menubar/MenubarMenu.jsx index 5453e6c8d8..67c7eb91e3 100644 --- a/client/components/Menubar/MenubarMenu.jsx +++ b/client/components/Menubar/MenubarMenu.jsx @@ -65,7 +65,7 @@ MenubarList.defaultProps = { }; function MenubarMenu({ id, title, children }) { - const { isOpen, handlers } = useMenuProps(id); + const { isOpen } = useMenuProps(id); return (
        • From 905ac20605f183b91779c638e59a59fc757219c8 Mon Sep 17 00:00:00 2001 From: Tristan Espinoza Date: Tue, 19 Nov 2024 10:18:19 -0800 Subject: [PATCH 9/9] chore: added separators between components within MenubarMenu --- client/components/Menubar/MenubarMenu.jsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/client/components/Menubar/MenubarMenu.jsx b/client/components/Menubar/MenubarMenu.jsx index 67c7eb91e3..34192b237b 100644 --- a/client/components/Menubar/MenubarMenu.jsx +++ b/client/components/Menubar/MenubarMenu.jsx @@ -19,6 +19,10 @@ export function useMenuProps(id) { return { isOpen, handlers }; } +/* ------------------------------------------------------------------------------------------------- + * MenubarTrigger + * -----------------------------------------------------------------------------------------------*/ + function MenubarTrigger({ id, title, ...props }) { const { isOpen, handlers } = useMenuProps(id); @@ -45,6 +49,10 @@ MenubarTrigger.propTypes = { title: PropTypes.node.isRequired }; +/* ------------------------------------------------------------------------------------------------- + * MenubarList + * -----------------------------------------------------------------------------------------------*/ + function MenubarList({ id, children }) { return (
            @@ -64,6 +72,10 @@ MenubarList.defaultProps = { children: null }; +/* ------------------------------------------------------------------------------------------------- + * MenubarMenu + * -----------------------------------------------------------------------------------------------*/ + function MenubarMenu({ id, title, children }) { const { isOpen } = useMenuProps(id);