PagePathNav.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import React, { FC } from 'react';
  2. import { DevidedPagePath } from '@growi/core/dist/models';
  3. import { pagePathUtils } from '@growi/core/dist/utils';
  4. import dynamic from 'next/dynamic';
  5. import Sticky from 'react-stickynode';
  6. import { useIsNotFound } from '~/stores/page';
  7. import LinkedPagePath from '../../../models/linked-page-path';
  8. import { PagePathHierarchicalLink } from '../PagePathHierarchicalLink';
  9. import { CollapsedParentsDropdown } from '../PagePathHierarchicalLink/CollapsedParentsDropdown';
  10. import styles from './PagePathNav.module.scss';
  11. const { isTrashPage } = pagePathUtils;
  12. type Props = {
  13. pagePath: string,
  14. pageId?: string | null,
  15. isSingleLineMode?: boolean,
  16. isCollapseParents?: boolean,
  17. formerLinkClassName?: string,
  18. latterLinkClassName?: string,
  19. }
  20. const CopyDropdown = dynamic(() => import('../CopyDropdown').then(mod => mod.CopyDropdown), { ssr: false });
  21. const Separator = (): JSX.Element => {
  22. return <span className={styles['grw-mr-02em']}>/</span>;
  23. };
  24. export const PagePathNav: FC<Props> = (props: Props) => {
  25. const {
  26. pageId, pagePath, isSingleLineMode, isCollapseParents,
  27. formerLinkClassName, latterLinkClassName,
  28. } = props;
  29. const dPagePath = new DevidedPagePath(pagePath, false, true);
  30. const { data: isNotFound } = useIsNotFound();
  31. const isInTrash = isTrashPage(pagePath);
  32. let formerLink;
  33. let latterLink;
  34. // one line
  35. if (dPagePath.isRoot || dPagePath.isFormerRoot || (!isCollapseParents && isSingleLineMode)) {
  36. const linkedPagePath = new LinkedPagePath(pagePath);
  37. latterLink = <PagePathHierarchicalLink linkedPagePath={linkedPagePath} isInTrash={isInTrash} />;
  38. }
  39. // collapse parents
  40. else if (isCollapseParents) {
  41. const linkedPagePathFormer = new LinkedPagePath(dPagePath.former);
  42. const linkedPagePathLatter = new LinkedPagePath(dPagePath.latter);
  43. latterLink = (
  44. <>
  45. <CollapsedParentsDropdown linkedPagePath={linkedPagePathFormer} />
  46. <Separator />
  47. <PagePathHierarchicalLink linkedPagePath={linkedPagePathLatter} basePath={dPagePath.former} isInTrash={isInTrash} />
  48. </>
  49. );
  50. }
  51. // two line
  52. else {
  53. const linkedPagePathFormer = new LinkedPagePath(dPagePath.former);
  54. const linkedPagePathLatter = new LinkedPagePath(dPagePath.latter);
  55. formerLink = <PagePathHierarchicalLink linkedPagePath={linkedPagePathFormer} isInTrash={isInTrash} />;
  56. latterLink = (
  57. <>
  58. <Separator />
  59. <PagePathHierarchicalLink linkedPagePath={linkedPagePathLatter} basePath={dPagePath.former} isInTrash={isInTrash} />
  60. </>
  61. );
  62. }
  63. const copyDropdownId = `copydropdown-${pageId}`;
  64. return (
  65. <div>
  66. <span className={formerLinkClassName}>{formerLink}</span>
  67. <div className="d-flex align-items-center">
  68. <h1 className={`m-0 text-truncate ${latterLinkClassName}`}>
  69. {latterLink}
  70. </h1>
  71. { pageId != null && !isNotFound && (
  72. <div className="mx-2">
  73. <CopyDropdown pageId={pageId} pagePath={pagePath} dropdownToggleId={copyDropdownId} dropdownToggleClassName="p-2">
  74. <i className="ti ti-clipboard"></i>
  75. </CopyDropdown>
  76. </div>
  77. ) }
  78. </div>
  79. </div>
  80. );
  81. };
  82. type PagePathNavStickyProps = Omit<Props, 'isCollapseParents'>;
  83. export const PagePathNavSticky = (props: PagePathNavStickyProps): JSX.Element => {
  84. return (
  85. // Controlling pointer-events
  86. // 1. disable pointer-events with 'pe-none'
  87. <Sticky className={`${styles['grw-page-path-nav-sticky']} mb-4`} innerClass="mt-1 pe-none" innerActiveClass="active">
  88. {({ status }: { status: boolean }) => {
  89. const isCollapseParents = status === Sticky.STATUS_FIXED;
  90. return (
  91. // Controlling pointer-events
  92. // 2. enable pointer-events with 'pe-auto' only against the children
  93. // which width is minimized by 'd-inline-block'
  94. <div className="d-inline-block pe-auto">
  95. <PagePathNav {...props} isCollapseParents={isCollapseParents} latterLinkClassName={isCollapseParents ? 'fs-3' : 'fs-2'} />
  96. </div>
  97. );
  98. }}
  99. </Sticky>
  100. );
  101. };