TableOfContents.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import React, { type JSX, useCallback } from 'react';
  2. import { pagePathUtils } from '@growi/core/dist/utils';
  3. import ReactMarkdown from 'react-markdown';
  4. import { useCurrentPagePath } from '~/states/page';
  5. import { useTocOptions } from '~/states/ui/toc';
  6. import loggerFactory from '~/utils/logger';
  7. import { StickyStretchableScroller } from './StickyStretchableScroller';
  8. import styles from './TableOfContents.module.scss';
  9. const { isUsersHomepage: _isUsersHomepage } = pagePathUtils;
  10. const _logger = loggerFactory('growi:TableOfContents');
  11. type Props = {
  12. tagsElementHeight?: number;
  13. };
  14. const TableOfContents = ({ tagsElementHeight }: Props): JSX.Element => {
  15. const currentPagePath = useCurrentPagePath();
  16. const isUsersHomePage =
  17. currentPagePath != null && _isUsersHomepage(currentPagePath);
  18. const { data: rendererOptions } = useTocOptions();
  19. const calcViewHeight = useCallback(() => {
  20. // calculate absolute top of '#revision-toc' element
  21. const parentElem = document.querySelector('.grw-side-contents-container');
  22. const containerElem = document.querySelector('#revision-toc');
  23. // rendererOptions for redo calcViewHeight()
  24. // see: https://github.com/growilabs/growi/pull/6791
  25. if (
  26. parentElem == null ||
  27. containerElem == null ||
  28. rendererOptions == null ||
  29. tagsElementHeight == null
  30. ) {
  31. return 0;
  32. }
  33. const parentBottom = parentElem.getBoundingClientRect().bottom;
  34. const containerTop = containerElem.getBoundingClientRect().top;
  35. const containerComputedStyle = getComputedStyle(containerElem);
  36. const containerPaddingTop = parseFloat(
  37. containerComputedStyle['padding-top'],
  38. );
  39. // get smaller bottom line of window height - .system-version height - margin 5px) and containerTop
  40. let bottom = Math.min(window.innerHeight - 20 - 5, parentBottom);
  41. if (isUsersHomePage) {
  42. // raise the bottom line by the height and margin-top of UserContentLinks
  43. bottom -= 90;
  44. }
  45. // bottom - revisionToc top
  46. return bottom - (containerTop + containerPaddingTop);
  47. }, [isUsersHomePage, rendererOptions, tagsElementHeight]);
  48. return (
  49. <div id="revision-toc" className={`revision-toc ${styles['revision-toc']}`}>
  50. <StickyStretchableScroller
  51. stickyElemSelector=".grw-side-contents-sticky-container"
  52. calcViewHeight={calcViewHeight}
  53. >
  54. <div
  55. id="revision-toc-content"
  56. data-testid="revision-toc-content"
  57. className="revision-toc-content mb-3"
  58. >
  59. {/* parse blank to show toc (https://github.com/growilabs/growi/pull/6277) */}
  60. <ReactMarkdown {...rendererOptions}> </ReactMarkdown>
  61. </div>
  62. </StickyStretchableScroller>
  63. </div>
  64. );
  65. };
  66. export default TableOfContents;