Преглед на файлове

Merge pull request #8473 from weseek/imprv/139438-139433-seach-result-fix

imprv:  Fix broken layout of search result page
Yuki Takei преди 2 години
родител
ревизия
d87e8e1e1e

+ 1 - 0
apps/app/public/static/locales/en_US/translation.json

@@ -538,6 +538,7 @@
     "search_again" : "Search again",
     "number_of_list_to_display" : "Display",
     "page_number_unit" : "pages",
+    "hit_number_unit" : "hit",
     "sort_axis": {
       "relationScore": "Sort by relevance",
       "createdAt": "Creation date",

+ 1 - 0
apps/app/public/static/locales/ja_JP/translation.json

@@ -571,6 +571,7 @@
     "search_again" : "再検索",
     "number_of_list_to_display" : "表示件数",
     "page_number_unit" : "件",
+    "hit_number_unit" : "件",
     "sort_axis": {
       "relationScore": "関連度順",
       "createdAt": "作成日時",

+ 1 - 0
apps/app/public/static/locales/zh_CN/translation.json

@@ -541,6 +541,7 @@
     "search_again" : "再次搜索",
     "number_of_list_to_display" : "显示器的数量",
     "page_number_unit" : "例",
+    "hit_number_unit" : "例",
     "sort_axis": {
       "relationScore": "按相关性排序",
       "createdAt": "按创建日期排序",

+ 8 - 17
apps/app/src/components/SearchPage.tsx

@@ -28,8 +28,6 @@ const INITIAL_PAGIONG_SIZE = 20;
 
 type SearchResultListHeadProps = {
   searchResult: IFormattedSearchResult,
-  searchingKeyword: string,
-  offset: number,
   pagingSize: number,
   onPagingSizeChanged: (size: number) => void,
 }
@@ -38,13 +36,10 @@ const SearchResultListHead = React.memo((props: SearchResultListHeadProps): JSX.
   const { t } = useTranslation();
 
   const {
-    searchResult, searchingKeyword, offset, pagingSize,
-    onPagingSizeChanged,
+    searchResult, // pagingSize, onPagingSizeChanged,
   } = props;
 
-  const { took, total, hitsCount } = searchResult.meta;
-  const leftNum = offset + 1;
-  const rightNum = offset + hitsCount;
+  const { took, total } = searchResult.meta;
 
   if (total === 0) {
     return (
@@ -57,15 +52,14 @@ const SearchResultListHead = React.memo((props: SearchResultListHeadProps): JSX.
   return (
     <div className="d-flex align-items-center justify-content-between">
       <div className="text-nowrap">
-        {t('search_result.result_meta')}
-        <span className="search-result-keyword ms-2">{`${searchingKeyword}`}</span>
-        <span className="ms-3">{`${leftNum}-${rightNum}`} / {total}</span>
+        <span className="ms-3 fw-bold">{total} {t('search_result.hit_number_unit', 'hit')}</span>
         { took != null && (
           // blackout 70px rectangle in VRT
           <span data-vrt-blackout className="ms-3 text-muted d-inline-block" style={{ minWidth: '70px' }}>({took}ms)</span>
         ) }
       </div>
-      <div className="input-group flex-nowrap search-result-select-group ms-auto d-md-flex d-none">
+      {/* TODO: infinite scroll for search result */}
+      {/* <div className="input-group flex-nowrap search-result-select-group ms-auto d-md-flex d-none">
         <div>
           <label className="form-label input-group-text text-muted" htmlFor="inputGroupSelect01">{t('search_result.number_of_list_to_display')}</label>
         </div>
@@ -79,7 +73,7 @@ const SearchResultListHead = React.memo((props: SearchResultListHeadProps): JSX.
             return <option key={limit} value={limit}>{limit} {t('search_result.page_number_unit')}</option>;
           })}
         </select>
-      </div>
+      </div> */}
     </div>
   );
 });
@@ -185,11 +179,10 @@ export const SearchPage = (): JSX.Element => {
           >
             <button
               type="button"
-              className="btn btn-outline-danger text-nowrap border-0 px-2"
+              className="btn border-0 text-danger"
               disabled={isDisabled}
               onClick={deleteAllButtonClickedHandler}
             >
-              <span className="material-symbols-outlined">delete</span>
               {t('search_result.delete_all_selected_page')}
             </button>
           </OperateAllControl>
@@ -221,13 +214,11 @@ export const SearchPage = (): JSX.Element => {
     return (
       <SearchResultListHead
         searchResult={data}
-        searchingKeyword={keyword ?? ''}
-        offset={offset}
         pagingSize={limit}
         onPagingSizeChanged={pagingSizeChangedHandler}
       />
     );
-  }, [data, keyword, limit, offset, pagingSizeChangedHandler]);
+  }, [data, limit, pagingSizeChangedHandler]);
 
   const searchPager = useMemo(() => {
     // when pager is not needed

+ 5 - 5
apps/app/src/components/SearchPage/OperateAllControl.tsx

@@ -1,11 +1,10 @@
-import React, {
-  ChangeEvent, forwardRef, ForwardRefRenderFunction, useImperativeHandle, useRef,
-} from 'react';
+import type { ChangeEvent, ForwardRefRenderFunction } from 'react';
+import React, { forwardRef, useImperativeHandle, useRef } from 'react';
 
 import { Input } from 'reactstrap';
 
-import { ISelectableAndIndeterminatable } from '~/client/interfaces/selectable-all';
-import { IndeterminateInputElement } from '~/interfaces/indeterminate-input-elm';
+import type { ISelectableAndIndeterminatable } from '~/client/interfaces/selectable-all';
+import type { IndeterminateInputElement } from '~/interfaces/indeterminate-input-elm';
 
 type Props = {
   isCheckboxDisabled?: boolean,
@@ -58,6 +57,7 @@ const OperateAllControlSubstance: ForwardRefRenderFunction<ISelectableAndIndeter
         type="checkbox"
         id="cb-check-all"
         data-testid="cb-select-all"
+        className="ms-2"
         innerRef={selectAllCheckboxElm}
         disabled={isCheckboxDisabled}
         onChange={checkboxChangedHandler}

+ 9 - 0
apps/app/src/components/SearchPage/SearchControl.module.scss

@@ -0,0 +1,9 @@
+
+@use '@growi/core/scss/bootstrap/init' as bs;
+
+@use '@growi/ui/scss/atoms/btn-muted';
+
+// == Colors
+.btn-delete {
+  @include btn-muted.colorize(bs.$red);
+}

+ 24 - 22
apps/app/src/components/SearchPage/SearchControl.tsx

@@ -5,13 +5,15 @@ import React, {
 import { useTranslation } from 'next-i18next';
 
 import { SORT_AXIS, SORT_ORDER } from '~/interfaces/search';
-import { ISearchConditions, ISearchConfigurations } from '~/stores/search';
+import type { ISearchConditions, ISearchConfigurations } from '~/stores/search';
 
 import SearchForm from '../SearchForm';
 
 import SearchOptionModal from './SearchOptionModal';
 import SortControl from './SortControl';
 
+import styles from './SearchControl.module.scss';
+
 type Props = {
   isSearchServiceReachable: boolean,
   isEnableSort: boolean,
@@ -93,26 +95,12 @@ const SearchControl = React.memo((props: Props): JSX.Element => {
             onSubmit={searchFormSubmittedHandler}
           />
         </div>
-
-        {/* sort option: show when screen is larger than lg */}
-        {isEnableSort && (
-          <div className="me-4 d-lg-flex d-none">
-            <SortControl
-              sort={sort}
-              order={order}
-              onChange={changeSortHandler}
-            />
-          </div>
-        )}
       </div>
       {/* TODO: replace the following elements deleteAll button , relevance button and include specificPath button component */}
       <div className="search-control d-flex align-items-center py-md-2 py-3 px-md-4 px-3 border-bottom border-gray">
-        <div className="d-flex">
-          {allControl}
-        </div>
-        {/* sort option: show when screen is smaller than lg */}
+        {/* sort option */}
         {isEnableSort && (
-          <div className="me-md-4 me-2 d-flex d-lg-none ms-auto">
+          <div className="flex-grow-1">
             <SortControl
               sort={sort}
               order={order}
@@ -129,11 +117,13 @@ const SearchControl = React.memo((props: Props): JSX.Element => {
                 className="btn"
                 onClick={() => setIsFileterOptionModalShown(true)}
               >
-                <i className="icon-equalizer"></i>
+                <span className="material-symbols-outlined">
+                  tune
+                </span>
               </button>
             </div>
-            <div className="d-none d-lg-flex align-items-center ms-auto search-control-include-options">
-              <div className="border rounded px-2 py-1 me-3">
+            <div className="d-none d-lg-flex align-items-center search-control-include-options">
+              <div className="px-2 py-1">
                 <div className="form-check form-check-succsess">
                   <input
                     className="form-check-input me-2"
@@ -150,7 +140,7 @@ const SearchControl = React.memo((props: Props): JSX.Element => {
                   </label>
                 </div>
               </div>
-              <div className="border rounded px-2 py-1">
+              <div className="px-2 py-1">
                 <div className="form-check form-check-succsess">
                   <input
                     className="form-check-input me-2"
@@ -160,7 +150,7 @@ const SearchControl = React.memo((props: Props): JSX.Element => {
                     onChange={e => changeIncludeTrashPagesHandler(e.target.checked)}
                   />
                   <label
-                    className="form-label form-check-label d-flex align-items-center text-secondary with-no-font-weight"
+                    className="form-label form-check-label mb-0 d-flex align-items-center text-secondary with-no-font-weight"
                     htmlFor="flexCheckChecked"
                   >
                     {t('Include Subordinated Target Page', { target: '/trash' })}
@@ -170,6 +160,18 @@ const SearchControl = React.memo((props: Props): JSX.Element => {
             </div>
           </>
         )}
+        <div className="d-flex">
+          <div className="btn-group">
+            {/* TODO: imprv to delete all result UI */}
+            {/* <button className={`btn btn-sm rounded ${styles['btn-delete']}`} type="button" data-bs-toggle="dropdown" aria-expanded="false">
+              <span className="material-symbols-outlined ">delete</span>
+              <span className="material-symbols-outlined ">expand_more</span>
+            </button> */}
+            {/* <ul className="dropdown-menu"> */}
+            {allControl}
+            {/* </ul> */}
+          </div>
+        </div>
       </div>
 
       <SearchOptionModal

+ 4 - 3
apps/app/src/components/SearchPage/SearchOptionModal.tsx

@@ -1,4 +1,5 @@
-import React, { FC } from 'react';
+import type { FC } from 'react';
+import React from 'react';
 
 import { useTranslation } from 'next-i18next';
 import {
@@ -51,7 +52,7 @@ const SearchOptionModal: FC<Props> = (props: Props) => {
       </ModalHeader>
       <ModalBody>
         <div className="d-flex p-2">
-          <div className="border border-gray me-3">
+          <div className="me-3">
             <label className="form-label px-3 py-2 mb-0 d-flex align-items-center">
               <input
                 className="me-2"
@@ -62,7 +63,7 @@ const SearchOptionModal: FC<Props> = (props: Props) => {
               {t('Include Subordinated Target Page', { target: '/user' })}
             </label>
           </div>
-          <div className="border border-gray">
+          <div className="">
             <label className="form-label px-3 py-2 mb-0 d-flex align-items-center">
               <input
                 className="me-2"

+ 3 - 0
apps/app/src/components/SearchPage/SortControl.module.scss

@@ -0,0 +1,3 @@
+.sort-control {
+  min-width: 180px;
+}

+ 32 - 35
apps/app/src/components/SearchPage/SortControl.tsx

@@ -1,7 +1,12 @@
-import React, { FC } from 'react';
+import type { FC } from 'react';
+import React from 'react';
+
 import { useTranslation } from 'next-i18next';
+
 import { SORT_AXIS, SORT_ORDER } from '../../interfaces/search';
 
+import styles from './SortControl.module.scss';
+
 const { DESC, ASC } = SORT_ORDER;
 
 type Props = {
@@ -22,43 +27,35 @@ const SortControl: FC <Props> = (props: Props) => {
     }
   };
 
-  const renderOrderIcon = () => {
-    const iconClassName = ASC === order ? 'fa fa-sort-amount-asc' : 'fa fa-sort-amount-desc';
-    return <i className={iconClassName} aria-hidden="true" />;
-  };
 
   return (
     <>
-      <div className="input-group flex-nowrap">
-        <div>
-          <div className="input-group-text border text-muted" id="btnGroupAddon">
-            {renderOrderIcon()}
-          </div>
-        </div>
-        <div className="border rounded-end">
-          <button
-            type="button"
-            className="btn dropdown-toggle py-1"
-            data-bs-toggle="dropdown"
-          >
-            <span className="me-2 text-secondary">{t(`search_result.sort_axis.${sort}`)}</span>
-          </button>
-          <div className="dropdown-menu dropdown-menu-right">
-            {Object.values(SORT_AXIS).map((sortAxis) => {
-              const nextOrder = (sort !== sortAxis || order === ASC) ? DESC : ASC;
-              return (
-                <button
-                  key={sortAxis}
-                  className="dropdown-item"
-                  type="button"
-                  onClick={() => { onClickChangeSort(sortAxis, nextOrder) }}
-                >
-                  <span>{t(`search_result.sort_axis.${sortAxis}`)}</span>
-                </button>
-              );
-            })}
-          </div>
-        </div>
+      <div className={`btn-group ${styles['sort-control']}`}>
+        <button
+          className="d-flex align-items-center btn btn-sm btn-outline-neutral-secondary rounded-pill"
+          type="button"
+          data-bs-toggle="dropdown"
+          aria-expanded="false"
+        >
+          <span className="material-symbols-outlined py-0">sort</span>
+          <span className="ms-2 me-auto">{t(`search_result.sort_axis.${sort}`)}</span>
+          <span className="material-symbols-outlined py-0">expand_more</span>
+        </button>
+        <ul className="dropdown-menu">
+          {Object.values(SORT_AXIS).map((sortAxis) => {
+            const nextOrder = (sort !== sortAxis || order === ASC) ? DESC : ASC;
+            return (
+              <button
+                key={sortAxis}
+                className="dropdown-item"
+                type="button"
+                onClick={() => { onClickChangeSort(sortAxis, nextOrder) }}
+              >
+                <span>{t(`search_result.sort_axis.${sortAxis}`)}</span>
+              </button>
+            );
+          })}
+        </ul>
       </div>
     </>
   );