SearchResultListItem.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import React, { FC, useMemo } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import { UserPicture, PageListMeta, PagePathLabel } from '@growi/ui';
  4. import { DevidedPagePath } from '@growi/core';
  5. import { ISearchedPage } from './SearchResultList';
  6. import loggerFactory from '~/utils/logger';
  7. const logger = loggerFactory('growi:searchResultList');
  8. type Props ={
  9. page: ISearchedPage,
  10. onClickInvoked?: (pageId: string) => void,
  11. }
  12. const PageItemControl: FC<Props> = (props: {page: ISearchedPage}) => {
  13. const { page } = props;
  14. const { t } = useTranslation('');
  15. return (
  16. <>
  17. <button
  18. type="button"
  19. className="btn-link nav-link dropdown-toggle dropdown-toggle-no-caret border-0 rounded grw-btn-page-management py-0"
  20. data-toggle="dropdown"
  21. >
  22. <i className="fa fa-ellipsis-v text-muted"></i>
  23. </button>
  24. <div className="dropdown-menu dropdown-menu-right">
  25. {/* TODO: if there is the following button in XD add it here
  26. <button
  27. type="button"
  28. className="btn btn-link p-0"
  29. value={page.path}
  30. onClick={(e) => {
  31. window.location.href = e.currentTarget.value;
  32. }}
  33. >
  34. <i className="icon-login" />
  35. </button>
  36. */}
  37. {/*
  38. TODO: add function to the following buttons like using modal or others
  39. ref: https://estoc.weseek.co.jp/redmine/issues/79026
  40. */}
  41. <button className="dropdown-item text-danger" type="button" onClick={() => console.log('delete modal show')}>
  42. <i className="icon-fw icon-fire"></i>{t('Delete')}
  43. </button>
  44. <button className="dropdown-item" type="button" onClick={() => console.log('duplicate modal show')}>
  45. <i className="icon-fw icon-star"></i>{t('Add to bookmark')}
  46. </button>
  47. <button className="dropdown-item" type="button" onClick={() => console.log('duplicate modal show')}>
  48. <i className="icon-fw icon-docs"></i>{t('Duplicate')}
  49. </button>
  50. <button className="dropdown-item" type="button" onClick={() => console.log('rename function will be added')}>
  51. <i className="icon-fw icon-action-redo"></i>{t('Move/Rename')}
  52. </button>
  53. </div>
  54. </>
  55. );
  56. };
  57. const SearchResultListItem: FC<Props> = (props:Props) => {
  58. const { page } = props;
  59. // Add prefix 'id_' in pageId, because scrollspy of bootstrap doesn't work when the first letter of id attr of target component is numeral.
  60. const pageId = `#${page._id}`;
  61. const dPagePath = new DevidedPagePath(page.path, false, true);
  62. const pagePathElem = <PagePathLabel page={page} isFormerOnly />;
  63. const onClickInvoked = (pageId) => {
  64. if (props.onClickInvoked != null) {
  65. onClickInvoked(pageId);
  66. }
  67. };
  68. const renderPageItem = useMemo(() => {
  69. return (
  70. <li key={page._id} className="page-list-li w-100 border-bottom pr-4">
  71. <a
  72. className="d-block pt-3"
  73. href={pageId}
  74. onClick={() => onClickInvoked(page._id)}
  75. >
  76. <div className="d-flex">
  77. {/* checkbox */}
  78. <div className="form-check my-auto mx-2">
  79. <input className="form-check-input my-auto" type="checkbox" value="" id="flexCheckDefault" />
  80. </div>
  81. <div className="w-100">
  82. {/* page path */}
  83. <small className="mb-1">
  84. <i className="icon-fw icon-home"></i>
  85. {pagePathElem}
  86. </small>
  87. <div className="d-flex my-1 align-items-center">
  88. {/* page title */}
  89. <h3 className="mb-0">
  90. <UserPicture user={page.lastUpdateUser} />
  91. <span className="mx-2">{dPagePath.latter}</span>
  92. </h3>
  93. {/* page meta */}
  94. <div className="d-flex mx-2">
  95. <PageListMeta page={page} />
  96. </div>
  97. {/* doropdown icon includes page control buttons */}
  98. <div className="ml-auto">
  99. <PageItemControl page={page} />
  100. </div>
  101. </div>
  102. <div className="mt-1">{page.snippet}</div>
  103. </div>
  104. {/* eslint-disable-next-line react/no-danger */}
  105. <div className="mt-1" dangerouslySetInnerHTML={{ __html: page.elasticSearchResult.snippet }}></div>
  106. </div>
  107. </a>
  108. </li>
  109. );
  110. }, []);
  111. return (
  112. <>
  113. {renderPageItem}
  114. </>
  115. );
  116. };
  117. export default SearchResultListItem;