From 664db33d0a1595888fb2b97b46825cd689a3e8c9 Mon Sep 17 00:00:00 2001 From: amass Date: Fri, 19 Mar 2021 16:34:14 +0200 Subject: [PATCH] polish shared/RoutedTabsHeader & introduce RoutedTabsHeader.module.css --- .../layout/TabbedPage/TabbedPage.module.css | 41 ---------- .../RoutedTabsHeader/RoutedTabsHeader.jsx | 81 ++++++------------- .../RoutedTabsHeader.module.css | 45 +++++++++++ .../shared/RoutedTabsHeader/hooks.js | 41 ++++++++-- 4 files changed, 104 insertions(+), 104 deletions(-) create mode 100644 app/components/shared/RoutedTabsHeader/RoutedTabsHeader.module.css diff --git a/app/components/layout/TabbedPage/TabbedPage.module.css b/app/components/layout/TabbedPage/TabbedPage.module.css index 91bc1737ad..99ef41bd65 100644 --- a/app/components/layout/TabbedPage/TabbedPage.module.css +++ b/app/components/layout/TabbedPage/TabbedPage.module.css @@ -18,34 +18,6 @@ height: 114px; } -.tabbedPageHeader > .tabs { - position: absolute; - bottom: 0px; - left: 100px; - white-space: nowrap; -} - -.tabbedPageHeader > .tabs > .tab { - line-height: 35px; - margin-right: 55px; -} - -.tabbedPageHeader > .tabs > .tab:last-of-type { - margin-right: 0; -} - -.tabbedPageHeader > .tabs > .tabs-caret > { - position: absolute; - bottom: 0; - height: 5px; -} - -.tabbedPageHeader > .tabs > .tabs-caret > .active { - background-color: var(--accent-color); - position: absolute; - height: 5px; -} - .tabContent { position: absolute; overflow-x: hidden; @@ -66,14 +38,10 @@ background-color: transparent; } - @media screen and (max-width: 1179px) { .tabbedPageHeader { padding-left: 20px; } - .tabbedPageHeader > .tabs { - left: 55px; - } .tabContent { padding: 38px 20px 30px 20px; } @@ -89,15 +57,6 @@ padding-top: 30px; } - .tabbedPageHeader > .tabs { - font-size: 13px; - left: 25px; - right: 20px; - .tab { - margin-right: 45px; - } - } - .tabContent { padding: 0 10px 80px 10px; } diff --git a/app/components/shared/RoutedTabsHeader/RoutedTabsHeader.jsx b/app/components/shared/RoutedTabsHeader/RoutedTabsHeader.jsx index c0cb62d106..c8238e3bc2 100644 --- a/app/components/shared/RoutedTabsHeader/RoutedTabsHeader.jsx +++ b/app/components/shared/RoutedTabsHeader/RoutedTabsHeader.jsx @@ -1,22 +1,16 @@ -import { useState, useEffect, useCallback, useMemo, useRef } from "react"; +import { useMemo, useCallback } from "react"; import { NavLink as Link } from "react-router-dom"; import { spring, Motion } from "react-motion"; import { useRoutedTabsHeader } from "./hooks"; import theme from "theme"; +import styles from "./RoutedTabsHeader.module.css"; export const RoutedTab = (path, link) => ({ path, link }); const RoutedTabsHeader = ({ tabs, caret }) => { - const nodes = useRef(new Map()); + const { uiAnimations, caretLeft, caretWidth, nodes } = useRoutedTabsHeader(); - const [caretLeft, setCaretLeft] = useState(null); - const [caretWidth, setCaretWidth] = useState(null); - const [selectedTab, setSelectedTab] = useState(null); - const [localSidebarOnBottom, setLocalSidebarOnBottom] = useState(null); - - const { location, uiAnimations, sidebarOnBottom } = useRoutedTabsHeader(); - - const getAnimatedCaret = () => { + const getAnimatedCaret = useCallback(() => { const caretStyle = { left: spring(caretLeft, theme("springs.tab")), width: spring(caretWidth, theme("springs.tab")) @@ -25,78 +19,49 @@ const RoutedTabsHeader = ({ tabs, caret }) => { return ( {(style) => ( -
-
+
+
)} ); - }; + }, [caretLeft, caretWidth]); - const getStaticCaret = () => { + const getStaticCaret = useCallback(() => { const style = { left: caretLeft, width: caretWidth }; return ( -
-
+
+
); - }; + }, [caretLeft, caretWidth]); const tabLinks = useMemo( () => - tabs.map((t) => ( + tabs.map(({ path, link }) => ( nodes.current.set(t.path, ref)}> - - {t.link} + className={styles.tab} + key={path} + ref={(ref) => nodes.current.set(path, ref)}> + + {link} )), - [tabs] + [tabs, nodes] ); - const localCaret = uiAnimations ? getAnimatedCaret() : getStaticCaret(); - - const updateCaretPosition = useCallback(() => { - const selectedTab = location.pathname; - const tabForRoute = nodes.current.get(selectedTab); - if (!tabForRoute) return null; - const tabRect = tabForRoute.getBoundingClientRect(); - const caretLeft = tabForRoute.offsetLeft; - const caretWidth = tabRect.width; - setCaretLeft(caretLeft); - setCaretWidth(caretWidth); - setSelectedTab(selectedTab); - }, [location]); - - useEffect(() => { - setLocalSidebarOnBottom(sidebarOnBottom); - updateCaretPosition(); - }, [sidebarOnBottom, updateCaretPosition]); - - useEffect(() => { - if ( - selectedTab != location.pathname || - localSidebarOnBottom != sidebarOnBottom - ) { - updateCaretPosition(); - } - }, [ - location, - selectedTab, - sidebarOnBottom, - localSidebarOnBottom, - updateCaretPosition - ]); + const localCaret = useMemo( + () => (uiAnimations ? getAnimatedCaret() : getStaticCaret()), + [uiAnimations, getAnimatedCaret, getStaticCaret] + ); return ( -
+
{tabLinks} {caret ? caret : localCaret}
diff --git a/app/components/shared/RoutedTabsHeader/RoutedTabsHeader.module.css b/app/components/shared/RoutedTabsHeader/RoutedTabsHeader.module.css new file mode 100644 index 0000000000..4df2e95084 --- /dev/null +++ b/app/components/shared/RoutedTabsHeader/RoutedTabsHeader.module.css @@ -0,0 +1,45 @@ +.tabs { + position: absolute; + bottom: 0px; + left: 100px; + white-space: nowrap; +} + +.tabs > .tab { + line-height: 35px; + margin-right: 55px; +} + +.tabs > .tab:last-of-type { + margin-right: 0; +} + +.tabs > .tabCaret > { + position: absolute; + bottom: 0; + height: 5px; +} + +.tabs > .tabCaret > .active { + background-color: var(--accent-color); + position: absolute; + height: 5px; +} + +@media screen and (max-width: 1179px) { + .tabs { + left: 55px; + } +} + +@media screen and (max-width: 768px) { + .tabs { + font-size: 13px; + left: 25px; + right: 20px; + } + + .tabs > .tab { + margin-right: 45px; + } +} diff --git a/app/components/shared/RoutedTabsHeader/hooks.js b/app/components/shared/RoutedTabsHeader/hooks.js index 29ff6f4f4b..a17c7532d3 100644 --- a/app/components/shared/RoutedTabsHeader/hooks.js +++ b/app/components/shared/RoutedTabsHeader/hooks.js @@ -1,14 +1,45 @@ +import { useEffect, useCallback, useState, useRef } from "react"; import { useSelector } from "react-redux"; import * as sel from "selectors"; export function useRoutedTabsHeader() { - const location = useSelector(sel.location); + const nodes = useRef(new Map()); + const [caretLeft, setCaretLeft] = useState(null); + const [caretWidth, setCaretWidth] = useState(null); + const [selectedTab, setSelectedTab] = useState(null); + const [localSidebarOnBottom, setLocalSidebarOnBottom] = useState(null); + const { pathname } = useSelector(sel.location); const sidebarOnBottom = useSelector(sel.sidebarOnBottom); const uiAnimations = useSelector(sel.uiAnimations); - return { - location, + const updateCaretPosition = useCallback(() => { + const selectedTab = pathname; + const tabForRoute = nodes.current.get(selectedTab); + if (!tabForRoute) return null; + const tabRect = tabForRoute.getBoundingClientRect(); + const caretLeft = tabForRoute.offsetLeft; + const caretWidth = tabRect.width; + setCaretLeft(caretLeft); + setCaretWidth(caretWidth); + setSelectedTab(selectedTab); + }, [pathname]); + + useEffect(() => { + setLocalSidebarOnBottom(sidebarOnBottom); + updateCaretPosition(); + }, [sidebarOnBottom, updateCaretPosition]); + + useEffect(() => { + if (selectedTab != pathname || localSidebarOnBottom != sidebarOnBottom) { + updateCaretPosition(); + } + }, [ + pathname, + selectedTab, sidebarOnBottom, - uiAnimations - }; + localSidebarOnBottom, + updateCaretPosition + ]); + + return { uiAnimations, caretLeft, caretWidth, nodes }; }