GrowiSubNavigation.jsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { DevidedPagePath } from '@growi/core';
  4. import PagePathHierarchicalLink from '~/components/PagePathHierarchicalLink';
  5. import LinkedPagePath from '~/models/linked-page-path';
  6. import { withUnstatedContainers } from '../UnstatedUtils';
  7. import AppContainer from '~/client/services/AppContainer';
  8. import PageContainer from '~/client/services/PageContainer';
  9. import {
  10. EditorMode, useDrawerMode, useEditorMode, useIsDeviceSmallerThanMd,
  11. } from '~/stores/ui';
  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 { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
  60. const { data: isDrawerMode } = useDrawerMode();
  61. const { data: editorMode, mutate: mutateEditorMode } = useEditorMode();
  62. const {
  63. appContainer, pageContainer, isCompactMode,
  64. } = props;
  65. const {
  66. pageId, path, createdAt, creator, updatedAt, revisionAuthor, isPageExist,
  67. } = pageContainer.state;
  68. const { isGuestUser } = appContainer;
  69. const isEditorMode = editorMode !== EditorMode.View;
  70. // Tags cannot be edited while the new page and editorMode is view
  71. const isTagLabelHidden = (editorMode !== EditorMode.Editor && !isPageExist);
  72. function onPageEditorModeButtonClicked(viewType) {
  73. mutateEditorMode(viewType);
  74. }
  75. return (
  76. <div className={`grw-subnav container-fluid d-flex align-items-center justify-content-between ${isCompactMode ? 'grw-subnav-compact d-print-none' : ''}`}>
  77. {/* Left side */}
  78. <div className="d-flex grw-subnav-left-side">
  79. { isDrawerMode && (
  80. <div className={`d-none d-md-flex align-items-center ${isEditorMode ? 'mr-2 pr-2' : 'border-right mr-4 pr-4'}`}>
  81. <DrawerToggler />
  82. </div>
  83. ) }
  84. <div className="grw-path-nav-container">
  85. { pageContainer.isAbleToShowTagLabel && !isCompactMode && !isTagLabelHidden && (
  86. <div className="grw-taglabels-container">
  87. <TagLabels editorMode={editorMode} />
  88. </div>
  89. ) }
  90. <PagePathNav pageId={pageId} pagePath={path} isEditorMode={isEditorMode} isCompactMode={isCompactMode} />
  91. </div>
  92. </div>
  93. {/* Right side */}
  94. <div className="d-flex">
  95. <div className="d-flex flex-column align-items-end">
  96. <div className="d-flex">
  97. <SubnavButtons isCompactMode={isCompactMode} />
  98. </div>
  99. <div className="mt-2">
  100. {pageContainer.isAbleToShowPageEditorModeManager && (
  101. <PageEditorModeManager
  102. onPageEditorModeButtonClicked={onPageEditorModeButtonClicked}
  103. isBtnDisabled={isGuestUser}
  104. editorMode={editorMode}
  105. isDeviceSmallerThanMd={isDeviceSmallerThanMd}
  106. />
  107. )}
  108. </div>
  109. </div>
  110. {/* Page Authors */}
  111. { (pageContainer.isAbleToShowPageAuthors && !isCompactMode) && (
  112. <ul className="authors text-nowrap border-left d-none d-lg-block d-edit-none py-2 pl-4 mb-0 ml-3">
  113. <li className="pb-1">
  114. <AuthorInfo user={creator} date={createdAt} locate="subnav" />
  115. </li>
  116. <li className="mt-1 pt-1 border-top">
  117. <AuthorInfo user={revisionAuthor} date={updatedAt} mode="update" locate="subnav" />
  118. </li>
  119. </ul>
  120. ) }
  121. </div>
  122. </div>
  123. );
  124. };
  125. /**
  126. * Wrapper component for using unstated
  127. */
  128. const GrowiSubNavigationWrapper = withUnstatedContainers(GrowiSubNavigation, [AppContainer, PageContainer]);
  129. GrowiSubNavigation.propTypes = {
  130. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  131. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  132. isCompactMode: PropTypes.bool,
  133. };
  134. export default GrowiSubNavigationWrapper;