TableOfContents.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import ReactMarkdown from 'react-markdown';
  3. import { blinkElem } from '~/client/util/blink-section-header';
  4. import { addSmoothScrollEvent } from '~/client/util/smooth-scroll';
  5. import { useIsUserPage } from '~/stores/context';
  6. import { useTocOptions } from '~/stores/renderer';
  7. import loggerFactory from '~/utils/logger';
  8. import { StickyStretchableScroller } from './StickyStretchableScroller';
  9. import styles from './TableOfContents.module.scss';
  10. // eslint-disable-next-line no-unused-vars
  11. const logger = loggerFactory('growi:TableOfContents');
  12. const TableOfContents = (): JSX.Element => {
  13. const { data: isUserPage } = useIsUserPage();
  14. const [tocHtml, setTocHtml] = useState('');
  15. const { data: rendererOptions } = useTocOptions();
  16. const calcViewHeight = useCallback(() => {
  17. // calculate absolute top of '#revision-toc' element
  18. const parentElem = document.querySelector('.grw-side-contents-container');
  19. const containerElem = document.querySelector('#revision-toc');
  20. if (parentElem == null || containerElem == null) {
  21. return 0;
  22. }
  23. const parentBottom = parentElem.getBoundingClientRect().bottom;
  24. const containerTop = containerElem.getBoundingClientRect().top;
  25. const containerComputedStyle = getComputedStyle(containerElem);
  26. const containerPaddingTop = parseFloat(containerComputedStyle['padding-top']);
  27. // get smaller bottom line of window height - .system-version height - margin 5px) and containerTop
  28. let bottom = Math.min(window.innerHeight - 20 - 5, parentBottom);
  29. if (isUserPage) {
  30. // raise the bottom line by the height and margin-top of UserContentLinks
  31. bottom -= 45;
  32. }
  33. // bottom - revisionToc top
  34. return bottom - (containerTop + containerPaddingTop);
  35. }, [isUserPage]);
  36. useEffect(() => {
  37. const tocDom = document.getElementById('revision-toc-content');
  38. if (tocDom == null) { return }
  39. const anchorsInToc = Array.from(tocDom.getElementsByTagName('a'));
  40. addSmoothScrollEvent(anchorsInToc, blinkElem);
  41. }, [tocHtml]);
  42. return (
  43. <div id="revision-toc" className={`revision-toc ${styles['revision-toc']}`}>
  44. <StickyStretchableScroller
  45. stickyElemSelector=".grw-side-contents-sticky-container"
  46. calcViewHeight={calcViewHeight}
  47. >
  48. <div
  49. id="revision-toc-content"
  50. className="revision-toc-content mb-3"
  51. >
  52. {/* parse blank to show toc (https://github.com/weseek/growi/pull/6277) */}
  53. <ReactMarkdown {...rendererOptions}>
  54. {''}
  55. </ReactMarkdown>
  56. </div>
  57. </StickyStretchableScroller>
  58. </div>
  59. );
  60. };
  61. export default TableOfContents;