GrowiNavbar.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import React, {
  2. FC, memo, useMemo, useRef,
  3. } from 'react';
  4. import { useTranslation } from 'next-i18next';
  5. import dynamic from 'next/dynamic';
  6. import { useRipple } from 'react-use-ripple';
  7. import { UncontrolledTooltip } from 'reactstrap';
  8. import {
  9. useIsSearchPage, useIsGuestUser, useIsReadOnlyUser, useIsSearchServiceConfigured, useAppTitle, useConfidential,
  10. } from '~/stores/context';
  11. import { usePageCreateModal } from '~/stores/modal';
  12. import { useCurrentPagePath } from '~/stores/page';
  13. import { useIsDeviceSmallerThanMd } from '~/stores/ui';
  14. import { GlobalSearchProps } from './GlobalSearch';
  15. import styles from './GrowiNavbar.module.scss';
  16. const NavbarRight = memo((): JSX.Element => {
  17. const { t } = useTranslation();
  18. const { data: currentPagePath } = useCurrentPagePath();
  19. const { data: isGuestUser } = useIsGuestUser();
  20. const { data: isReadOnlyUser } = useIsReadOnlyUser();
  21. // ripple
  22. const newButtonRef = useRef(null);
  23. useRipple(newButtonRef, { rippleColor: 'rgba(255, 255, 255, 0.3)' });
  24. const { open: openCreateModal } = usePageCreateModal();
  25. const isAuthenticated = isGuestUser === false;
  26. const authenticatedNavItem = useMemo(() => {
  27. return (
  28. <>
  29. {!isReadOnlyUser
  30. && <li className="nav-item d-none d-md-block">
  31. <button
  32. className="px-md-3 nav-link btn-create-page border-0 bg-transparent"
  33. type="button"
  34. ref={newButtonRef}
  35. data-testid="newPageBtn"
  36. onClick={() => openCreateModal(currentPagePath || '')}
  37. >
  38. <i className="icon-pencil mr-2"></i>
  39. <span className="d-none d-lg-block">{ t('commons:New') }</span>
  40. </button>
  41. </li>
  42. }
  43. </>
  44. );
  45. }, [isReadOnlyUser, t, openCreateModal, currentPagePath]);
  46. const notAuthenticatedNavItem = useMemo(() => {
  47. return (
  48. <>
  49. <li id="login-user" className="nav-item"><a className="nav-link" href="/login">Login</a></li>
  50. </>
  51. );
  52. }, []);
  53. return (
  54. <>
  55. {isAuthenticated ? authenticatedNavItem : notAuthenticatedNavItem}
  56. </>
  57. );
  58. });
  59. NavbarRight.displayName = 'NavbarRight';
  60. type ConfidentialProps = {
  61. confidential?: string,
  62. }
  63. const Confidential: FC<ConfidentialProps> = memo((props: ConfidentialProps): JSX.Element => {
  64. const { confidential } = props;
  65. if (confidential == null || confidential.length === 0) {
  66. return <></>;
  67. }
  68. return (
  69. <li className="nav-item confidential text-light">
  70. <i id="confidentialTooltip" className="icon-info d-md-none" />
  71. <span className="d-none d-md-inline">
  72. {confidential}
  73. </span>
  74. <UncontrolledTooltip
  75. placement="bottom"
  76. target="confidentialTooltip"
  77. className="d-md-none"
  78. >
  79. {confidential}
  80. </UncontrolledTooltip>
  81. </li>
  82. );
  83. });
  84. Confidential.displayName = 'Confidential';
  85. type Props = {
  86. isGlobalSearchHidden?: boolean
  87. }
  88. export const GrowiNavbar = (props: Props): JSX.Element => {
  89. const { isGlobalSearchHidden } = props;
  90. const GlobalSearch = dynamic<GlobalSearchProps>(() => import('./GlobalSearch').then(mod => mod.GlobalSearch), { ssr: false });
  91. const { data: appTitle } = useAppTitle();
  92. const { data: confidential } = useConfidential();
  93. const { data: isSearchServiceConfigured } = useIsSearchServiceConfigured();
  94. const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
  95. const { data: isSearchPage } = useIsSearchPage();
  96. return (
  97. <nav id="grw-navbar" className={`navbar grw-navbar ${styles['grw-navbar']} navbar-expand navbar-dark sticky-top mb-0 px-0`}>
  98. <div className="grw-app-title d-none d-md-block">
  99. {appTitle}
  100. </div>
  101. {/* Navbar Right */}
  102. <ul className="navbar-nav ml-auto">
  103. <NavbarRight />
  104. <Confidential confidential={confidential} />
  105. </ul>
  106. <div className="grw-global-search-container position-absolute">
  107. { !isGlobalSearchHidden && isSearchServiceConfigured && !isDeviceSmallerThanMd && !isSearchPage && (
  108. <GlobalSearch />
  109. ) }
  110. </div>
  111. </nav>
  112. );
  113. };