GrowiSubNavigation.jsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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 { createSubscribedElement } from '../UnstatedUtils';
  6. import AppContainer from '../../services/AppContainer';
  7. import RevisionPath from '../Page/RevisionPath';
  8. import PageContainer from '../../services/PageContainer';
  9. import TagLabels from '../Page/TagLabels';
  10. import LikeButton from '../LikeButton';
  11. import BookmarkButton from '../BookmarkButton';
  12. import PageCreator from './PageCreator';
  13. import RevisionAuthor from './RevisionAuthor';
  14. const GrowiSubNavigation = (props) => {
  15. const isPageForbidden = document.querySelector('#grw-subnav').getAttribute('data-is-forbidden-page') === 'true';
  16. const { appContainer, pageContainer } = props;
  17. const {
  18. pageId, path, createdAt, creator, updatedAt, revisionAuthor, isHeaderSticky, isSubnavCompact,
  19. } = pageContainer.state;
  20. const isPageNotFound = pageId == null;
  21. const isPageInTrash = isTrashPage(path);
  22. // Display only the RevisionPath
  23. if (isPageNotFound || isPageForbidden || isPageInTrash) {
  24. return (
  25. <div className="d-flex align-items-center px-3 py-3 grw-subnavbar">
  26. <h1 className="m-0">
  27. <RevisionPath
  28. behaviorType={appContainer.config.behaviorType}
  29. pageId={pageId}
  30. pagePath={pageContainer.state.path}
  31. isPageNotFound={isPageNotFound}
  32. isPageForbidden={isPageForbidden}
  33. isPageInTrash={isPageInTrash}
  34. />
  35. </h1>
  36. </div>
  37. );
  38. }
  39. const additionalClassNames = ['grw-subnavbar'];
  40. if (isHeaderSticky) {
  41. additionalClassNames.push('grw-subnavbar-sticky');
  42. }
  43. if (isSubnavCompact) {
  44. additionalClassNames.push('grw-subnavbar-compact');
  45. }
  46. return (
  47. <div className={`d-flex align-items-center justify-content-between px-3 py-1 ${additionalClassNames.join(' ')}`}>
  48. {/* Page Path */}
  49. <div>
  50. <h1 className="m-0">
  51. <RevisionPath behaviorType={appContainer.config.behaviorType} pageId={pageId} pagePath={pageContainer.state.path} />
  52. </h1>
  53. { !isPageNotFound && !isPageForbidden && (
  54. <TagLabels />
  55. ) }
  56. </div>
  57. <div className="d-flex align-items-center">
  58. {/* Header Button */}
  59. <div className="mr-2">
  60. <LikeButton pageId={pageId} isLiked={pageContainer.state.isLiked} />
  61. </div>
  62. <div>
  63. <BookmarkButton pageId={pageId} crowi={appContainer} />
  64. </div>
  65. {/* Page Authors */}
  66. <ul className="authors text-nowrap d-none d-lg-block">
  67. { creator != null && (
  68. <li>
  69. <PageCreator creator={creator} createdAt={createdAt} isCompactMode={isSubnavCompact} />
  70. </li>
  71. ) }
  72. { revisionAuthor != null && (
  73. <li className="mt-1">
  74. <RevisionAuthor revisionAuthor={revisionAuthor} updatedAt={updatedAt} isCompactMode={isSubnavCompact} />
  75. </li>
  76. ) }
  77. </ul>
  78. </div>
  79. </div>
  80. );
  81. };
  82. /**
  83. * Wrapper component for using unstated
  84. */
  85. const GrowiSubNavigationWrapper = (props) => {
  86. return createSubscribedElement(GrowiSubNavigation, props, [AppContainer, PageContainer]);
  87. };
  88. GrowiSubNavigation.propTypes = {
  89. t: PropTypes.func.isRequired, // i18next
  90. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  91. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  92. };
  93. export default withTranslation()(GrowiSubNavigationWrapper);