Browse Source

back to original

yohei0125 4 years ago
parent
commit
4cf455571d
1 changed files with 141 additions and 0 deletions
  1. 141 0
      packages/app/src/components/SearchPage/SearchResultListItem.tsx

+ 141 - 0
packages/app/src/components/SearchPage/SearchResultListItem.tsx

@@ -0,0 +1,141 @@
+import React, { FC, memo, useCallback } from 'react';
+
+import Clamp from 'react-multiline-clamp';
+
+import { UserPicture, PageListMeta, PagePathLabel } from '@growi/ui';
+import { pagePathUtils, DevidedPagePath } from '@growi/core';
+import { useIsDeviceSmallerThanLg } from '~/stores/ui';
+
+import { IPageSearchResultData } from '../../interfaces/search';
+import PageItemControl from '../Common/Dropdown/PageItemControl';
+
+const { isTopPage } = pagePathUtils;
+
+type Props = {
+  page: IPageSearchResultData,
+  isSelected: boolean,
+  isChecked: boolean,
+  isEnableActions: boolean,
+  shortBody?: string
+  onClickCheckbox?: (pageId: string) => void,
+  onClickSearchResultItem?: (pageId: string) => void,
+  onClickDeleteButton?: (pageId: string) => void,
+}
+
+const SearchResultListItem: FC<Props> = memo((props:Props) => {
+  const {
+    // todo: refactoring variable name to clear what changed
+    page: { pageData, pageMeta }, isSelected, onClickSearchResultItem, onClickCheckbox, isChecked, isEnableActions, shortBody,
+  } = props;
+
+  const { data: isDeviceSmallerThanLg } = useIsDeviceSmallerThanLg();
+
+  const pagePath: DevidedPagePath = new DevidedPagePath(pageData.path, true);
+
+  const pageTitle = (
+    <PagePathLabel
+      path={pageMeta.elasticSearchResult?.highlightedPath || pageData.path}
+      isLatterOnly
+      isPathIncludedHtml={pageMeta.elasticSearchResult?.isHtmlInPath}
+    >
+    </PagePathLabel>
+  );
+  const pagePathElem = (
+    <PagePathLabel
+      path={pageMeta.elasticSearchResult?.highlightedPath || pageData.path}
+      isFormerOnly
+      isPathIncludedHtml={pageMeta.elasticSearchResult?.isHtmlInPath}
+    />
+  );
+
+  // click event handler
+  const clickHandler = useCallback(() => {
+    // do nothing if mobile
+    if (isDeviceSmallerThanLg) {
+      return;
+    }
+
+    if (onClickSearchResultItem != null) {
+      onClickSearchResultItem(pageData._id);
+    }
+  }, [isDeviceSmallerThanLg, onClickSearchResultItem, pageData._id]);
+
+  const responsiveListStyleClass = `${isDeviceSmallerThanLg ? '' : `list-group-item-action ${isSelected ? 'active' : ''}`}`;
+  return (
+    <li
+      key={pageData._id}
+      className={`w-100 grw-search-result-item border-bottom ${responsiveListStyleClass}`}
+    >
+      <div
+        className="h-100 text-break"
+        onClick={clickHandler}
+      >
+        <div className="d-flex h-100">
+          {/* checkbox */}
+          <div className="form-check d-flex align-items-center justify-content-center px-md-2 pl-3 pr-2 search-item-checkbox">
+            <input
+              className="form-check-input position-relative m-0"
+              type="checkbox"
+              id="flexCheckDefault"
+              onChange={() => {
+                if (onClickCheckbox != null) {
+                  onClickCheckbox(pageData._id);
+                }
+              }}
+              checked={isChecked}
+            />
+          </div>
+          <div className="search-item-text p-md-3 pl-2 py-3 pr-3 flex-grow-1">
+            {/* page path */}
+            <h6 className="mb-1 py-1">
+              <a href={pagePath.isRoot ? pagePath.latter : pagePath.former}>
+                <i className="icon-fw icon-home"></i>
+                {pagePathElem}
+              </a>
+            </h6>
+            <div className="d-flex align-items-center mb-2">
+              {/* Picture */}
+              <span className="mr-2 d-none d-md-block">
+                <UserPicture user={pageData.lastUpdateUser} size="sm" />
+              </span>
+              {/* page title */}
+              <Clamp lines={1}>
+                <span className="py-1 h5 mr-2 mb-0">
+                  <a href={`/${pageData._id}`}>{pageTitle}</a>
+                </span>
+              </Clamp>
+
+              {/* page meta */}
+              <div className="d-none d-md-flex item-meta py-0 px-1">
+                <PageListMeta page={pageData} bookmarkCount={pageMeta.bookmarkCount} />
+              </div>
+              {/* doropdown icon includes page control buttons */}
+              <div className="item-control ml-auto">
+                <PageItemControl
+                  page={pageData}
+                  onClickDeleteButton={props.onClickDeleteButton}
+                  isEnableActions={isEnableActions}
+                  isDeletable={!isTopPage(pageData.path)}
+                />
+              </div>
+            </div>
+            <div className="grw-search-result-list-snippet py-1">
+              <Clamp lines={2}>
+                {
+                  pageMeta.elasticSearchResult != null && pageMeta.elasticSearchResult?.snippet.length !== 0 ? (
+                    <div dangerouslySetInnerHTML={{ __html: pageMeta.elasticSearchResult.snippet }}></div>
+                  ) : (
+                    <div>{ shortBody != null ? shortBody : 'Loading ...' }</div> // TODO: improve indicator
+                  )
+                }
+              </Clamp>
+            </div>
+          </div>
+        </div>
+        {/* TODO: adjust snippet position */}
+      </div>
+    </li>
+  );
+});
+
+export default SearchResultListItem;