PagePathHierarchicalLink.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import React, { memo, useCallback } from 'react';
  2. import Link from 'next/link';
  3. import urljoin from 'url-join';
  4. import type LinkedPagePath from '../../../models/linked-page-path';
  5. import styles from './PagePathHierarchicalLink.module.scss';
  6. type PagePathHierarchicalLinkProps = {
  7. linkedPagePath: LinkedPagePath,
  8. linkedPagePathByHtml?: LinkedPagePath,
  9. basePath?: string,
  10. isInTrash?: boolean,
  11. isIconHidden?: boolean,
  12. // !!INTERNAL USE ONLY!!
  13. isInnerElem?: boolean,
  14. };
  15. export const PagePathHierarchicalLink = memo((props: PagePathHierarchicalLinkProps): JSX.Element => {
  16. const {
  17. linkedPagePath, linkedPagePathByHtml, basePath, isInTrash, isInnerElem,
  18. } = props;
  19. const isIconHidden = props.isIconHidden ?? false;
  20. // eslint-disable-next-line react/prop-types
  21. const RootElm = useCallback(({ children }) => {
  22. return isInnerElem
  23. ? <>{children}</>
  24. : <span className="text-break" id="grw-page-path-hierarchical-link">{children}</span>;
  25. }, [isInnerElem]);
  26. // render root element
  27. if (linkedPagePath.isRoot) {
  28. if (basePath != null || isIconHidden) {
  29. return <></>;
  30. }
  31. return isInTrash
  32. ? (
  33. <RootElm>
  34. <span className="path-segment">
  35. <Link href="/trash" prefetch={false}>
  36. <span className="material-symbols-outlined">delete</span>
  37. </Link>
  38. </span>
  39. <span className={`separator ${styles.separator}`}><a href="/">/</a></span>
  40. </RootElm>
  41. )
  42. : (
  43. <RootElm>
  44. <span className="path-segment">
  45. <Link href="/" prefetch={false}>
  46. {/* TODO: Size adjust */}
  47. <span className="material-symbols-outlined">home</span>
  48. <span className={`separator ${styles.separator}`}>/</span>
  49. </Link>
  50. </span>
  51. </RootElm>
  52. );
  53. }
  54. const isParentExists = linkedPagePath.parent != null;
  55. const isParentRoot = linkedPagePath.parent?.isRoot;
  56. const isSeparatorRequired = isParentExists && !isParentRoot;
  57. const shouldDangerouslySetInnerHTML = linkedPagePathByHtml != null;
  58. const href = encodeURI(urljoin(basePath || '/', linkedPagePath.href));
  59. return (
  60. <RootElm>
  61. { isParentExists && (
  62. <PagePathHierarchicalLink
  63. linkedPagePath={linkedPagePath.parent}
  64. linkedPagePathByHtml={linkedPagePathByHtml?.parent}
  65. basePath={basePath}
  66. isInTrash={isInTrash || linkedPagePath.isInTrash}
  67. isInnerElem
  68. isIconHidden={isIconHidden}
  69. />
  70. ) }
  71. { isSeparatorRequired && (
  72. <span className={`separator ${styles.separator}`}>/</span>
  73. ) }
  74. <Link href={href} prefetch={false} legacyBehavior>
  75. {
  76. shouldDangerouslySetInnerHTML
  77. // eslint-disable-next-line react/no-danger
  78. ? <a className="page-segment" dangerouslySetInnerHTML={{ __html: linkedPagePathByHtml.pathName }}></a>
  79. : <a className="page-segment">{linkedPagePath.pathName}</a>
  80. }
  81. </Link>
  82. </RootElm>
  83. );
  84. });