GrowiSubNavigation.jsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import { DevidedPagePath } from '@growi/core';
  5. import PagePathHierarchicalLink from '~/components/PagePathHierarchicalLink';
  6. import LinkedPagePath from '~/models/linked-page-path';
  7. import { withUnstatedContainers } from '../UnstatedUtils';
  8. import AppContainer from '~/client/services/AppContainer';
  9. import NavigationContainer from '~/client/services/NavigationContainer';
  10. import PageContainer from '~/client/services/PageContainer';
  11. import { useCurrentCreatedAt } from '~/stores/context';
  12. import CopyDropdown from '../Page/CopyDropdown';
  13. import TagLabels from '../Page/TagLabels';
  14. import SubnavButtons from './SubNavButtons';
  15. import PageEditorModeManager from './PageEditorModeManager';
  16. import AuthorInfo from './AuthorInfo';
  17. import DrawerToggler from './DrawerToggler';
  18. const PagePathNav = ({
  19. // eslint-disable-next-line react/prop-types
  20. pageId, pagePath, isEditorMode, isCompactMode,
  21. }) => {
  22. const dPagePath = new DevidedPagePath(pagePath, false, true);
  23. let formerLink;
  24. let latterLink;
  25. // one line
  26. if (dPagePath.isRoot || dPagePath.isFormerRoot || isEditorMode) {
  27. const linkedPagePath = new LinkedPagePath(pagePath);
  28. latterLink = <PagePathHierarchicalLink linkedPagePath={linkedPagePath} />;
  29. }
  30. // two line
  31. else {
  32. const linkedPagePathFormer = new LinkedPagePath(dPagePath.former);
  33. const linkedPagePathLatter = new LinkedPagePath(dPagePath.latter);
  34. formerLink = <PagePathHierarchicalLink linkedPagePath={linkedPagePathFormer} />;
  35. latterLink = <PagePathHierarchicalLink linkedPagePath={linkedPagePathLatter} basePath={dPagePath.former} />;
  36. }
  37. const copyDropdownId = `copydropdown${isCompactMode ? '-subnav-compact' : ''}-${pageId}`;
  38. const copyDropdownToggleClassName = 'd-block text-muted bg-transparent btn-copy border-0 py-0';
  39. return (
  40. <div className="grw-page-path-nav">
  41. {formerLink}
  42. <span className="d-flex align-items-center">
  43. <h1 className="m-0">{latterLink}</h1>
  44. <div className="mx-2">
  45. <CopyDropdown
  46. pageId={pageId}
  47. pagePath={pagePath}
  48. dropdownToggleId={copyDropdownId}
  49. dropdownToggleClassName={copyDropdownToggleClassName}
  50. >
  51. <i className="ti-clipboard"></i>
  52. </CopyDropdown>
  53. </div>
  54. </span>
  55. </div>
  56. );
  57. };
  58. const GrowiSubNavigation = (props) => {
  59. const {
  60. appContainer, navigationContainer, pageContainer, isCompactMode,
  61. } = props;
  62. const { isDrawerMode, editorMode, isDeviceSmallerThanMd } = navigationContainer.state;
  63. const {
  64. pageId, path, creator, updatedAt, revisionAuthor, isPageExist,
  65. } = pageContainer.state;
  66. const { data: createdAt } = useCurrentCreatedAt();
  67. const { isGuestUser } = appContainer;
  68. const isEditorMode = editorMode !== 'view';
  69. // Tags cannot be edited while the new page and editorMode is view
  70. const isTagLabelHidden = (editorMode !== 'edit' && !isPageExist);
  71. function onPageEditorModeButtonClicked(viewType) {
  72. navigationContainer.setEditorMode(viewType);
  73. }
  74. return (
  75. <div className={`grw-subnav container-fluid d-flex align-items-center justify-content-between ${isCompactMode ? 'grw-subnav-compact d-print-none' : ''}`}>
  76. {/* Left side */}
  77. <div className="d-flex grw-subnav-left-side">
  78. { isDrawerMode && (
  79. <div className={`d-none d-md-flex align-items-center ${isEditorMode ? 'mr-2 pr-2' : 'border-right mr-4 pr-4'}`}>
  80. <DrawerToggler />
  81. </div>
  82. ) }
  83. <div className="grw-path-nav-container">
  84. { pageContainer.isAbleToShowTagLabel && !isCompactMode && !isTagLabelHidden && (
  85. <div className="grw-taglabels-container">
  86. <TagLabels editorMode={editorMode} />
  87. </div>
  88. ) }
  89. <PagePathNav pageId={pageId} pagePath={path} isEditorMode={isEditorMode} isCompactMode={isCompactMode} />
  90. </div>
  91. </div>
  92. {/* Right side */}
  93. <div className="d-flex">
  94. <div className="d-flex flex-column align-items-end">
  95. <div className="d-flex">
  96. <SubnavButtons isCompactMode={isCompactMode} />
  97. </div>
  98. <div className="mt-2">
  99. {pageContainer.isAbleToShowPageEditorModeManager && (
  100. <PageEditorModeManager
  101. onPageEditorModeButtonClicked={onPageEditorModeButtonClicked}
  102. isBtnDisabled={isGuestUser}
  103. editorMode={editorMode}
  104. isDeviceSmallerThanMd={isDeviceSmallerThanMd}
  105. />
  106. )}
  107. </div>
  108. </div>
  109. {/* Page Authors */}
  110. { (pageContainer.isAbleToShowPageAuthors && !isCompactMode) && (
  111. <ul className="authors text-nowrap border-left d-none d-lg-block d-edit-none py-2 pl-4 mb-0 ml-3">
  112. <li className="pb-1">
  113. <AuthorInfo user={creator} date={createdAt} locate="subnav" />
  114. </li>
  115. <li className="mt-1 pt-1 border-top">
  116. <AuthorInfo user={revisionAuthor} date={updatedAt} mode="update" locate="subnav" />
  117. </li>
  118. </ul>
  119. ) }
  120. </div>
  121. </div>
  122. );
  123. };
  124. /**
  125. * Wrapper component for using unstated
  126. */
  127. const GrowiSubNavigationWrapper = withUnstatedContainers(GrowiSubNavigation, [AppContainer, NavigationContainer, PageContainer]);
  128. GrowiSubNavigation.propTypes = {
  129. t: PropTypes.func.isRequired, // i18next
  130. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  131. navigationContainer: PropTypes.instanceOf(NavigationContainer).isRequired,
  132. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  133. isCompactMode: PropTypes.bool,
  134. };
  135. export default withTranslation()(GrowiSubNavigationWrapper);