GrowiSubNavigation.jsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import { isTrashPage } from '@commons/util/path-utils';
  5. import DevidedPagePath from '@commons/models/devided-page-path';
  6. import LinkedPagePath from '@commons/models/linked-page-path';
  7. import PagePathHierarchicalLink from '@commons/components/PagePathHierarchicalLink';
  8. import { createSubscribedElement } from '../UnstatedUtils';
  9. import AppContainer from '../../services/AppContainer';
  10. import RevisionPathControls from '../Page/RevisionPathControls';
  11. import PageContainer from '../../services/PageContainer';
  12. import TagLabels from '../Page/TagLabels';
  13. import LikeButton from '../LikeButton';
  14. import BookmarkButton from '../BookmarkButton';
  15. import PageCreator from './PageCreator';
  16. import RevisionAuthor from './RevisionAuthor';
  17. // eslint-disable-next-line react/prop-types
  18. const PagePathNav = ({ pageId, pagePath, isPageForbidden }) => {
  19. const dPagePath = new DevidedPagePath(pagePath, false, true);
  20. let formerLink;
  21. let latterLink;
  22. // when the path is root or first level
  23. if (dPagePath.isRoot || dPagePath.isFormerRoot) {
  24. const linkedPagePath = new LinkedPagePath(pagePath);
  25. latterLink = <PagePathHierarchicalLink linkedPagePath={linkedPagePath} />;
  26. }
  27. // when the path is second level or deeper
  28. else {
  29. const linkedPagePathFormer = new LinkedPagePath(dPagePath.former);
  30. const linkedPagePathLatter = new LinkedPagePath(dPagePath.latter);
  31. formerLink = <PagePathHierarchicalLink linkedPagePath={linkedPagePathFormer} />;
  32. latterLink = <PagePathHierarchicalLink linkedPagePath={linkedPagePathLatter} basePath={dPagePath.former} />;
  33. }
  34. return (
  35. <div className="grw-page-path-nav">
  36. {formerLink}
  37. <span className="d-flex align-items-center flex-wrap">
  38. <h1 className="m-0">{latterLink}</h1>
  39. <RevisionPathControls
  40. pageId={pageId}
  41. pagePath={pagePath}
  42. isPageForbidden={isPageForbidden}
  43. />
  44. </span>
  45. </div>
  46. );
  47. };
  48. const GrowiSubNavigation = (props) => {
  49. const isPageForbidden = document.querySelector('#grw-subnav').getAttribute('data-is-forbidden-page') === 'true';
  50. const { appContainer, pageContainer } = props;
  51. const {
  52. pageId, path, createdAt, creator, updatedAt, revisionAuthor,
  53. } = pageContainer.state;
  54. const isPageNotFound = pageId == null;
  55. const isPageInTrash = isTrashPage(path);
  56. // Display only the RevisionPath
  57. if (isPageNotFound || isPageForbidden) {
  58. return (
  59. <div className="px-3 py-3 grw-subnavbar">
  60. <PagePathNav pageId={pageId} pagePath={path} isPageForbidden={isPageForbidden} />
  61. </div>
  62. );
  63. }
  64. const additionalClassNames = ['grw-subnavbar'];
  65. return (
  66. <div className={`d-flex align-items-center justify-content-between px-3 py-1 ${additionalClassNames.join(' ')}`}>
  67. {/* Page Path */}
  68. <div>
  69. <PagePathNav pageId={pageId} pagePath={path} isPageForbidden={isPageForbidden} />
  70. { !isPageNotFound && !isPageForbidden && (
  71. <TagLabels />
  72. ) }
  73. </div>
  74. <div className="d-flex align-items-center">
  75. { !isPageInTrash && (
  76. /* Header Button */
  77. <div className="mr-2">
  78. <LikeButton pageId={pageId} isLiked={pageContainer.state.isLiked} />
  79. </div>
  80. ) }
  81. { !isPageInTrash && (
  82. <div>
  83. <BookmarkButton pageId={pageId} crowi={appContainer} />
  84. </div>
  85. ) }
  86. {/* Page Authors */}
  87. <ul className="authors text-nowrap d-none d-lg-block d-edit-none">
  88. { creator != null && (
  89. <li>
  90. <PageCreator creator={creator} createdAt={createdAt} />
  91. </li>
  92. ) }
  93. { revisionAuthor != null && (
  94. <li className="mt-1">
  95. <RevisionAuthor revisionAuthor={revisionAuthor} updatedAt={updatedAt} />
  96. </li>
  97. ) }
  98. </ul>
  99. </div>
  100. </div>
  101. );
  102. };
  103. /**
  104. * Wrapper component for using unstated
  105. */
  106. const GrowiSubNavigationWrapper = (props) => {
  107. return createSubscribedElement(GrowiSubNavigation, props, [AppContainer, PageContainer]);
  108. };
  109. GrowiSubNavigation.propTypes = {
  110. t: PropTypes.func.isRequired, // i18next
  111. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  112. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  113. };
  114. export default withTranslation()(GrowiSubNavigationWrapper);