From a4c8c289ea726fd8d1a96e410db2df44af93ecaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Horvat?= Date: Thu, 7 Dec 2023 18:14:48 +0100 Subject: [PATCH] Reposition menus on narrow screens and add 2-column view (#3044) * Fix positions of menus and overlays on narrow screens * Always show target locale code in the navbar * Implement a 2-column UI for middle screen widths between 600 and 800 pixels Also: * Expand Header navigation breakpoint to the middle screens * Prevent jumping when moving between tabs * useNarrowScreen() -> useWindowWidth() --- translate/src/App.css | 100 ++++++++++++++---- translate/src/hooks/useNarrowScreen.ts | 21 ---- translate/src/hooks/useWindowWidth.ts | 33 ++++++ .../entitieslist/components/EntitiesList.tsx | 6 +- .../entitydetails/components/Helpers.tsx | 5 +- .../modules/navbar/components/Navigation.tsx | 6 +- .../project/components/ProjectMenu.tsx | 2 +- 7 files changed, 121 insertions(+), 52 deletions(-) delete mode 100644 translate/src/hooks/useNarrowScreen.ts create mode 100644 translate/src/hooks/useWindowWidth.ts diff --git a/translate/src/App.css b/translate/src/App.css index e865a3d6a0..41ef39fc89 100644 --- a/translate/src/App.css +++ b/translate/src/App.css @@ -60,12 +60,8 @@ transform: rotate(3deg) translate(0px, -4px); } -@media screen and (max-width: 600px) { +@media screen and (max-width: 800px) { /* Header */ - #app > header { - min-width: auto; - } - #app .navigation > ul > li:first-child { margin-right: -7px; } @@ -74,9 +70,79 @@ display: none; } + #app .navigation > ul > li.locale { + display: block; + } + + #app .navigation > ul > li.locale .locale-name { + display: none; + } + + #app .navigation > ul > li.locale .locale-code { + color: inherit; + margin-left: -5px; + padding: 0; + } + + #app .project-info .panel, + #app .resource-menu .menu { + right: -1px; + } + /* Main Content */ #app > .main-content { - overflow-x: hidden; /* Prevent horizontal scroll */ + height: calc(100% - 60px); + overflow: hidden; + } + + #app > .main-content > .panel-list { + width: 33%; + } + + #app > .main-content > .panel-content { + overflow-y: auto; + width: 67%; + } + + /* Editor */ + #app .entity-details { + display: block; + height: 160%; /* Prevent jumping when moving between tabs */ + } + + #app .entity-details > section { + height: auto; + max-height: none; + overflow-y: inherit; + width: 100%; + } + + /* History */ + #app .entity-details .history { + background: var(--editor-menu-background); + } + + /* Helpers */ + #app > .main-content .third-column { + border-left: none; + } +} + +@media screen and (max-width: 600px) { + /* Header */ + #app .progress-chart .menu { + position: fixed; + top: 59px; + } + + #app .project-info .panel { + left: -1px; + right: -1px; + } + + #app .user-notifications-menu .menu { + right: -1px; + position: fixed; } #app > .main-content > .panel-list, @@ -101,14 +167,9 @@ display: block; } - /* Editor */ - #app .entity-details { - display: block; - } - - #app .entity-details > section { - height: auto; - max-height: none; + #app .filters-panel .menu { + border: 0; + left: 0; width: 100%; } @@ -121,14 +182,9 @@ margin-right: 15px; } - /* History */ - #app .entity-details .history { - background: var(--editor-menu-background); - } - - /* Helpers */ - #app > .main-content .third-column { - border-left: none; + #app .keyboard-shortcuts .overlay { + padding: 10px; + width: 360px; } #app > .main-content .third-column .react-tabs span.count { diff --git a/translate/src/hooks/useNarrowScreen.ts b/translate/src/hooks/useNarrowScreen.ts deleted file mode 100644 index ca1444fb84..0000000000 --- a/translate/src/hooks/useNarrowScreen.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useEffect, useState } from 'react'; - -const NARROW_SCREEN_MAX_WIDTH = 600; - -/** - * Return true if the screen is narrower than 600px. Useful in Responsive Web Design. - */ -export function useNarrowScreen(): boolean { - const [isNarrow, setIsNarrow] = useState( - window.innerWidth <= NARROW_SCREEN_MAX_WIDTH, - ); - - useEffect(() => { - const handleWindowResize = () => - setIsNarrow(window.innerWidth <= NARROW_SCREEN_MAX_WIDTH); - window.addEventListener('resize', handleWindowResize); - return () => window.removeEventListener('resize', handleWindowResize); - }, []); - - return isNarrow; -} diff --git a/translate/src/hooks/useWindowWidth.ts b/translate/src/hooks/useWindowWidth.ts new file mode 100644 index 0000000000..edf805d249 --- /dev/null +++ b/translate/src/hooks/useWindowWidth.ts @@ -0,0 +1,33 @@ +import { useEffect, useState } from 'react'; + +const BREAKPOINTS = { + narrow: 600, + medium: 800, +}; + +/** + * Return window width range: narrow, medium or wide. + * + * Useful in Responsive Web Design. + */ +export function useWindowWidth(): 'narrow' | 'medium' | 'wide' { + function get_range(): 'narrow' | 'medium' | 'wide' { + if (window.innerWidth <= BREAKPOINTS.narrow) { + return 'narrow'; + } + if (window.innerWidth <= BREAKPOINTS.medium) { + return 'medium'; + } + return 'wide'; + } + + const [windowWidth, setWindowWidth] = useState(get_range()); + + useEffect(() => { + const handleWindowResize = () => setWindowWidth(get_range()); + window.addEventListener('resize', handleWindowResize); + return () => window.removeEventListener('resize', handleWindowResize); + }, []); + + return windowWidth; +} diff --git a/translate/src/modules/entitieslist/components/EntitiesList.tsx b/translate/src/modules/entitieslist/components/EntitiesList.tsx index 2e3b5dc6e5..fe8c581c2d 100644 --- a/translate/src/modules/entitieslist/components/EntitiesList.tsx +++ b/translate/src/modules/entitieslist/components/EntitiesList.tsx @@ -15,7 +15,7 @@ import { useEntities } from '~/modules/entities/hooks'; import { SkeletonLoader } from '~/modules/loaders'; import { ENTITY_NOT_FOUND } from '~/modules/notification/messages'; import { useAppDispatch, useAppSelector, useAppStore } from '~/hooks'; -import { useNarrowScreen } from '~/hooks/useNarrowScreen'; +import { useWindowWidth } from '~/hooks/useWindowWidth'; import { usePrevious } from '~/hooks/usePrevious'; import { checkSelection, @@ -273,7 +273,7 @@ export function EntitiesList(): React.ReactElement<'div'> { } const selectedEntitiesCount = batchactions.entities.length; - const isNarrowScreen = useNarrowScreen(); + const windowWidth = useWindowWidth(); const entitiesList = useContext(EntitiesListContext); const quitBatchActions = useCallback(() => dispatch(resetSelection()), []); const showBatchActions = useCallback(() => entitiesList.show(false), []); @@ -296,7 +296,7 @@ export function EntitiesList(): React.ReactElement<'div'> { ))} {hasNextPage && } - {selectedEntitiesCount === 0 || !isNarrowScreen ? null : ( + {selectedEntitiesCount === 0 || windowWidth !== 'narrow' ? null : ( { const { setTab } = useContext(HelperSelection); + const windowWidth = useWindowWidth(); const isTerminologyProject = parameters.project === 'terminology'; @@ -138,7 +139,7 @@ export function Helpers({ ); } - if (useNarrowScreen()) { + if (windowWidth === 'narrow' || windowWidth === 'medium') { return ( <>
diff --git a/translate/src/modules/navbar/components/Navigation.tsx b/translate/src/modules/navbar/components/Navigation.tsx index 401ddf5035..0bbade5d02 100644 --- a/translate/src/modules/navbar/components/Navigation.tsx +++ b/translate/src/modules/navbar/components/Navigation.tsx @@ -34,7 +34,7 @@ export function Navigation(): React.ReactElement<'nav'> { return (