GrowiSubNavigation.jsx 5.6 KB

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