GrowiNavbar.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import React, { FC, memo, useMemo } from 'react';
  2. import PropTypes from 'prop-types';
  3. import { useTranslation } from 'react-i18next';
  4. import { UncontrolledTooltip } from 'reactstrap';
  5. import AppContainer from '~/client/services/AppContainer';
  6. import {
  7. useIsSearchPage, useCurrentPagePath, useIsGuestUser,
  8. } from '~/stores/context';
  9. import { usePageCreateModal } from '~/stores/modal';
  10. import { useIsDeviceSmallerThanMd } from '~/stores/ui';
  11. import GrowiLogo from '../Icons/GrowiLogo';
  12. import InAppNotificationDropdown from '../InAppNotification/InAppNotificationDropdown';
  13. import { withUnstatedContainers } from '../UnstatedUtils';
  14. import { AppearanceModeDropdown } from './AppearanceModeDropdown';
  15. import GlobalSearch from './GlobalSearch';
  16. import PersonalDropdown from './PersonalDropdown';
  17. const NavbarRight = memo((): JSX.Element => {
  18. const { t } = useTranslation();
  19. const { data: currentPagePath } = useCurrentPagePath();
  20. const { data: isGuestUser } = useIsGuestUser();
  21. const { open: openCreateModal } = usePageCreateModal();
  22. const isAuthenticated = isGuestUser === false;
  23. const authenticatedNavItem = useMemo(() => {
  24. return (
  25. <>
  26. <li className="nav-item">
  27. <InAppNotificationDropdown />
  28. </li>
  29. <li className="nav-item d-none d-md-block">
  30. <button
  31. className="px-md-3 nav-link btn-create-page border-0 bg-transparent"
  32. type="button"
  33. data-testid="newPageBtn"
  34. onClick={() => openCreateModal(currentPagePath || '')}
  35. >
  36. <i className="icon-pencil mr-2"></i>
  37. <span className="d-none d-lg-block">{ t('New') }</span>
  38. </button>
  39. </li>
  40. <li className="grw-personal-dropdown nav-item dropdown">
  41. <AppearanceModeDropdown isAuthenticated={isAuthenticated} />
  42. </li>
  43. <li className="grw-personal-dropdown nav-item dropdown dropdown-toggle dropdown-toggle-no-caret" data-testid="grw-personal-dropdown">
  44. <PersonalDropdown />
  45. </li>
  46. </>
  47. );
  48. }, [t, currentPagePath, openCreateModal, isAuthenticated]);
  49. const notAuthenticatedNavItem = useMemo(() => {
  50. return (
  51. <>
  52. <li className="grw-personal-dropdown nav-item dropdown">
  53. <AppearanceModeDropdown isAuthenticated={isAuthenticated} />
  54. </li>
  55. <li id="login-user" className="nav-item"><a className="nav-link" href="/login">Login</a></li>;
  56. </>
  57. );
  58. }, []);
  59. return (
  60. <>
  61. {isAuthenticated ? authenticatedNavItem : notAuthenticatedNavItem}
  62. </>
  63. );
  64. });
  65. type ConfidentialProps = {
  66. confidential?: string,
  67. }
  68. const Confidential: FC<ConfidentialProps> = memo((props: ConfidentialProps) => {
  69. const { confidential } = props;
  70. if (confidential == null) {
  71. return null;
  72. }
  73. return (
  74. <li className="nav-item confidential text-light">
  75. <i id="confidentialTooltip" className="icon-info d-md-none" />
  76. <span className="d-none d-md-inline">
  77. {confidential}
  78. </span>
  79. <UncontrolledTooltip
  80. placement="bottom"
  81. target="confidentialTooltip"
  82. className="d-md-none"
  83. >
  84. {confidential}
  85. </UncontrolledTooltip>
  86. </li>
  87. );
  88. });
  89. interface NavbarLogoProps {
  90. logoSrc?: string,
  91. }
  92. const GrowiNavbarLogo: FC<NavbarLogoProps> = memo((props: NavbarLogoProps) => {
  93. const { logoSrc } = props;
  94. return logoSrc != null
  95. ? (<img src={logoSrc} className="picture picture-lg p-2 mx-2" id="settingBrandLogo" width="32" />)
  96. : <GrowiLogo />;
  97. });
  98. const GrowiNavbar = (props) => {
  99. const { appContainer } = props;
  100. const {
  101. crowi, isSearchServiceConfigured, customizedLogoSrc,
  102. } = appContainer.config;
  103. const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
  104. const { data: isSearchPage } = useIsSearchPage();
  105. return (
  106. <>
  107. {/* Brand Logo */}
  108. <div className="navbar-brand mr-0">
  109. <a className="grw-logo d-block" href="/">
  110. <GrowiNavbarLogo logoSrc={customizedLogoSrc} />
  111. </a>
  112. </div>
  113. <div className="grw-app-title d-none d-md-block">
  114. {crowi.title}
  115. </div>
  116. {/* Navbar Right */}
  117. <ul className="navbar-nav ml-auto">
  118. <NavbarRight></NavbarRight>
  119. <Confidential confidential={crowi.confidential}></Confidential>
  120. </ul>
  121. { isSearchServiceConfigured && !isDeviceSmallerThanMd && !isSearchPage && (
  122. <div className="grw-global-search grw-global-search-top position-absolute">
  123. <GlobalSearch />
  124. </div>
  125. ) }
  126. </>
  127. );
  128. };
  129. /**
  130. * Wrapper component for using unstated
  131. */
  132. const GrowiNavbarWrapper = withUnstatedContainers(GrowiNavbar, [AppContainer]);
  133. GrowiNavbar.propTypes = {
  134. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  135. };
  136. export default GrowiNavbarWrapper;