| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- 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,
- isEnableActions: boolean,
- isSelected?: boolean,
- isChecked?: boolean,
- shortBody?: string
- showCheckbox?: boolean, // whether you show checkbox on the left side of an item
- showPageUpdatedTime?: boolean, // whether you show page's updatedAt at the top-right corner of an item
- onClickCheckbox?: (pageId: string) => void,
- onClickSearchResultItem?: (pageId: string) => void,
- onClickDeleteButton?: (pageId: string) => void,
- }
- const defaultProps = {
- isSelected: false,
- isChecked: false,
- showCheckbox: false,
- showPageUpdatedTime: false,
- };
- const PageListItem: FC<Props> = memo((props:Props) => {
- const {
- // todo: refactoring variable name to clear what changed
- page: { pageData, pageMeta }, isSelected, onClickSearchResultItem, onClickCheckbox,
- isChecked, isEnableActions, shortBody, showCheckbox, showPageUpdatedTime,
- } = 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">
- {showCheckbox && (
- <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 d-flex justify-content-between">
- <a className="d-block" href={pagePath.isRoot ? pagePath.latter : pagePath.former}>
- <i className="icon-fw icon-home"></i>
- {pagePathElem}
- </a>
- {/* Todo: show actual time of page updated and apply color */}
- {showPageUpdatedTime && (
- <p className="mb-0 mr-4 text-muted">Updated: 2056/01/25 03:52:24</p>
- )}
- </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>
- );
- });
- PageListItem.defaultProps = defaultProps;
- export default PageListItem;
|