CustomNavbar.jsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import React, { useEffect, useState } from 'react';
  2. import PropTypes from 'prop-types';
  3. import {
  4. Nav, NavItem, NavLink, TabContent, TabPane,
  5. } from 'reactstrap';
  6. import { withTranslation } from 'react-i18next';
  7. import { withUnstatedContainers } from './UnstatedUtils';
  8. import CustomNavbarContainer from '../services/CustomNavbarContainer';
  9. const CustomNavbar = (props) => {
  10. const { t, customNavbarContainer } = props;
  11. const { switchActiveTab } = customNavbarContainer;
  12. const { activeTab } = customNavbarContainer.state;
  13. // [TODO: set default active tab by gw4079]
  14. const [sliderWidth, setSliderWidth] = useState(null);
  15. const [sliderMarginLeft, setSliderMarginLeft] = useState(null);
  16. // Might make this dynamic for px, %, pt, em
  17. function getPercentage(min, max) {
  18. return min / max * 100;
  19. }
  20. const random = Math.random().toString(32).substring(2);
  21. const navTitleId = `custom-navtitle-${random}`;
  22. const navTabId = `custom-navtab-${random}`;
  23. // [TODO: apply animation by gw4075]
  24. useEffect(() => {
  25. if (activeTab === '') {
  26. return;
  27. }
  28. const navTitle = document.getElementById(navTitleId);
  29. const navTabs = document.querySelectorAll(`li.${navTabId}`);
  30. if (navTitle == null || navTabs == null) {
  31. return;
  32. }
  33. let tempML = 0;
  34. const styles = [].map.call(navTabs, (el) => {
  35. const width = getPercentage(el.offsetWidth, navTitle.offsetWidth);
  36. const marginLeft = tempML;
  37. tempML += width;
  38. return { width, marginLeft };
  39. });
  40. const { width, marginLeft } = styles[props.navTabMapping[activeTab].index];
  41. setSliderWidth(width);
  42. setSliderMarginLeft(marginLeft);
  43. }, [activeTab]);
  44. return (
  45. <React.Fragment>
  46. <Nav className="nav-title" id={navTitleId}>
  47. {Object.entries(props.navTabMapping).map(([key, value]) => {
  48. return (
  49. <NavItem key={key} type="button" className={`p-0 ${navTabId} ${activeTab === key && 'active'}`}>
  50. <NavLink onClick={() => { switchActiveTab(key) }}>
  51. {value.icon}
  52. {t(value.i18n)}
  53. </NavLink>
  54. </NavItem>
  55. );
  56. })}
  57. </Nav>
  58. <hr className="my-0 grw-nav-slide-hr border-none" style={{ width: `${sliderWidth}%`, marginLeft: `${sliderMarginLeft}%` }} />
  59. <TabContent activeTab={activeTab} className="p-5">
  60. {Object.entries(props.navTabMapping).map(([key, value]) => {
  61. return (
  62. <TabPane key={key} tabId={key}>
  63. {value.tabContent}
  64. </TabPane>
  65. );
  66. })}
  67. </TabContent>
  68. </React.Fragment>
  69. );
  70. };
  71. /**
  72. * Wrapper component for using unstated
  73. */
  74. const CustomNavbarWrapper = withUnstatedContainers(CustomNavbar, [CustomNavbarContainer]);
  75. CustomNavbar.propTypes = {
  76. t: PropTypes.func.isRequired, // i18next
  77. customNavbarContainer: PropTypes.instanceOf(CustomNavbarContainer).isRequired,
  78. navTabMapping: PropTypes.object,
  79. };
  80. export default withTranslation()(CustomNavbarWrapper);