Sidebar.jsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import {
  5. withNavigationUIController,
  6. LayoutManager,
  7. NavigationProvider,
  8. ThemeProvider,
  9. } from '@atlaskit/navigation-next';
  10. import { createSubscribedElement } from './UnstatedUtils';
  11. import AppContainer from '../services/AppContainer';
  12. import SidebarNav from './Sidebar/SidebarNav';
  13. import RecentChanges from './Sidebar/RecentChanges';
  14. import CustomSidebar from './Sidebar/CustomSidebar';
  15. const sidebarDefaultWidth = 240;
  16. class Sidebar extends React.Component {
  17. static propTypes = {
  18. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  19. navigationUIController: PropTypes.any.isRequired,
  20. };
  21. state = {
  22. currentContentsId: 'recent',
  23. };
  24. componentWillMount() {
  25. this.initBreakpointEvents();
  26. }
  27. initBreakpointEvents() {
  28. const { appContainer, navigationUIController } = this.props;
  29. document.addEventListener('DOMContentLoaded', () => {
  30. // get the value of '--breakpoint-*'
  31. // const breakpointSm = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--breakpoint-sm'), 10);
  32. const breakpointMd = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--breakpoint-md'), 10);
  33. const smHandler = (mql) => {
  34. if (mql.matches) {
  35. // cache width
  36. this.sidebarWidthCached = navigationUIController.state.productNavWidth;
  37. appContainer.setState({ isDrawerOpened: false });
  38. navigationUIController.disableResize();
  39. navigationUIController.expand();
  40. // fix width
  41. navigationUIController.setState({ productNavWidth: sidebarDefaultWidth });
  42. }
  43. else {
  44. appContainer.setState({ isDrawerOpened: false });
  45. navigationUIController.enableResize();
  46. // restore width
  47. if (this.sidebarWidthCached != null) {
  48. navigationUIController.setState({ productNavWidth: this.sidebarWidthCached });
  49. }
  50. }
  51. };
  52. // const mediaQueryForXs = window.matchMedia(`(max-width: ${breakpointSm}px)`);
  53. const mediaQueryForSm = window.matchMedia(`(max-width: ${breakpointMd}px)`);
  54. // add event listener
  55. // mediaQueryForXs.addListener(xsHandler);
  56. mediaQueryForSm.addListener(smHandler);
  57. // initialize
  58. // xsHandler(mediaQueryForXs);
  59. smHandler(mediaQueryForSm);
  60. });
  61. }
  62. backdropClickedHandler = () => {
  63. const { appContainer } = this.props;
  64. appContainer.setState({ isDrawerOpened: false });
  65. }
  66. itemSelectedHandler = (contentsId) => {
  67. const { navigationUIController } = this.props;
  68. const { currentContentsId } = this.state;
  69. // already selected
  70. if (currentContentsId === contentsId) {
  71. navigationUIController.toggleCollapse();
  72. }
  73. // switch and expand
  74. else {
  75. this.setState({ currentContentsId: contentsId });
  76. navigationUIController.expand();
  77. }
  78. }
  79. renderGlobalNavigation = () => (
  80. <SidebarNav currentContentsId={this.state.currentContentsId} onItemSelected={this.itemSelectedHandler} />
  81. );
  82. renderSidebarContents = () => {
  83. let contents = <CustomSidebar />;
  84. switch (this.state.currentContentsId) {
  85. case 'recent':
  86. contents = <RecentChanges />;
  87. break;
  88. }
  89. return contents;
  90. }
  91. render() {
  92. const { isDrawerOpened } = this.props.appContainer.state;
  93. return (
  94. <>
  95. <div className={`grw-sidebar ${isDrawerOpened ? 'open' : ''}`}>
  96. <ThemeProvider
  97. theme={theme => ({
  98. ...theme,
  99. context: 'product',
  100. })}
  101. >
  102. <LayoutManager
  103. globalNavigation={this.renderGlobalNavigation}
  104. productNavigation={() => null}
  105. containerNavigation={this.renderSidebarContents}
  106. experimental_hideNavVisuallyOnCollapse
  107. experimental_flyoutOnHover
  108. experimental_alternateFlyoutBehaviour
  109. // experimental_fullWidthFlyout
  110. shouldHideGlobalNavShadow
  111. showContextualNavigation
  112. >
  113. </LayoutManager>
  114. </ThemeProvider>
  115. </div>
  116. { isDrawerOpened && (
  117. <div className="grw-sidebar-backdrop modal-backdrop show" onClick={this.backdropClickedHandler}></div>
  118. ) }
  119. </>
  120. );
  121. }
  122. }
  123. const SidebarWithNavigationUI = withNavigationUIController(Sidebar);
  124. const SidebarWithNavigationUIAndTranslation = withTranslation()(SidebarWithNavigationUI);
  125. /**
  126. * Wrapper component for using unstated
  127. */
  128. const SidebarWrapper = (props) => {
  129. return createSubscribedElement(SidebarWithNavigationUIAndTranslation, props, [AppContainer]);
  130. };
  131. export default () => (
  132. <NavigationProvider><SidebarWrapper /></NavigationProvider>
  133. );