From a03602a1d4643d019788fb931990608877f6c162 Mon Sep 17 00:00:00 2001 From: Kristofer Koishigawa Date: Wed, 28 Aug 2019 15:52:19 +0900 Subject: [PATCH] fix(search): update search bar index and styling (#36656) * Adjust search bar to only show hits for News * Dropdown links working. Working on basic pagination * Links to articles and temporarily routing to the News search result page working * Fix colors for search bar and drop down * Added Lato 300 font weight. Search bar now looks and works like it does on News. * feat:update styles * Update client/src/components/search/searchBar/SearchBar.js Co-Authored-By: Ahmad Abdolsaheb * Added Lato 300 font weight. Search bar now looks and works like it does on News. Co-authored-by: Ahmad Abdolsaheb --- client/gatsby-config.js | 2 +- .../components/search/WithInstantSearch.js | 6 +- client/src/components/search/redux/index.js | 2 +- .../components/search/searchBar/SearchBar.js | 11 +++- .../components/search/searchBar/SearchHits.js | 13 ++-- .../search/searchBar/SearchSuggestion.js | 15 +++-- .../search/searchBar/searchbar-base.css | 29 +++------ .../components/search/searchBar/searchbar.css | 62 ++++++++++++++++--- .../search/searchPage/SearchPageHits.js | 59 +++++------------- client/src/pages/search.js | 10 +-- 10 files changed, 111 insertions(+), 98 deletions(-) diff --git a/client/gatsby-config.js b/client/gatsby-config.js index e936b34e99..52e822295e 100644 --- a/client/gatsby-config.js +++ b/client/gatsby-config.js @@ -126,7 +126,7 @@ module.exports = { { resolve: 'gatsby-plugin-google-fonts', options: { - fonts: ['Lato:400,400i,500', 'Roboto Mono:400,700'] + fonts: ['Lato:300,400,400i,500,700', 'Roboto Mono:400,700'] } }, 'gatsby-plugin-sitemap', diff --git a/client/src/components/search/WithInstantSearch.js b/client/src/components/search/WithInstantSearch.js index 8ffb443420..0667fc7068 100644 --- a/client/src/components/search/WithInstantSearch.js +++ b/client/src/components/search/WithInstantSearch.js @@ -15,7 +15,7 @@ import { import { createSelector } from 'reselect'; -const DEBOUNCE_TIME = 400; +const DEBOUNCE_TIME = 100; const propTypes = { children: PropTypes.any, @@ -120,11 +120,11 @@ class InstantSearchRoot extends Component { - + {this.props.children} ); diff --git a/client/src/components/search/redux/index.js b/client/src/components/search/redux/index.js index ffcf545bdb..e7cf59c998 100644 --- a/client/src/components/search/redux/index.js +++ b/client/src/components/search/redux/index.js @@ -6,7 +6,7 @@ export const ns = 'search'; const initialState = { query: '', - indexName: 'query_suggestions', + indexName: 'news', isSearchDropdownEnabled: true, isSearchBarFocused: false }; diff --git a/client/src/components/search/searchBar/SearchBar.js b/client/src/components/search/searchBar/SearchBar.js index 4aeefc6e44..e3c3ad080f 100644 --- a/client/src/components/search/searchBar/SearchBar.js +++ b/client/src/components/search/searchBar/SearchBar.js @@ -4,7 +4,6 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { createSelector } from 'reselect'; import { SearchBox } from 'react-instantsearch-dom'; -import { navigate } from 'gatsby'; import { isSearchDropdownEnabledSelector, @@ -41,7 +40,7 @@ const mapDispatchToProps = dispatch => dispatch ); -const placeholder = 'Search 8,000+ lessons, articles, and videos'; +const placeholder = 'Search 5,000+ tutorials'; class SearchBar extends Component { constructor(props) { @@ -85,7 +84,13 @@ class SearchBar extends Component { if (query) { updateSearchQuery(query); } - return navigate('/search'); + // For Learn search results page + // return navigate('/search'); + + // Temporary redirect to News search results page + return window.location.assign( + `https://freecodecamp.org/news/search/?query=${query}` + ); } render() { diff --git a/client/src/components/search/searchBar/SearchHits.js b/client/src/components/search/searchBar/SearchHits.js index a5adf82e35..bf7d3f52a4 100644 --- a/client/src/components/search/searchBar/SearchHits.js +++ b/client/src/components/search/searchBar/SearchHits.js @@ -4,16 +4,19 @@ import isEmpty from 'lodash/isEmpty'; import Suggestion from './SearchSuggestion'; const CustomHits = connectHits(({ hits, currentRefinement, handleSubmit }) => { + const shortenedHits = hits.filter((hit, i) => i < 8); const defaultHit = [ { objectID: `default-hit-${currentRefinement}`, query: currentRefinement, _highlightResult: { query: { - value: - 'Search for "' + - currentRefinement + - '"' + value: ` + See all results for + + ${currentRefinement} + + ` } } } @@ -21,7 +24,7 @@ const CustomHits = connectHits(({ hits, currentRefinement, handleSubmit }) => { return (
    - {defaultHit.concat(hits).map(hit => ( + {shortenedHits.concat(defaultHit).map(hit => (
  • { + const dropdownFooter = hit.objectID.includes('default-hit-'); return isEmpty(hit) || isEmpty(hit.objectID) ? null : ( handleSubmit(e, hit.query)} + className={ + dropdownFooter + ? 'fcc_suggestion_footer fcc_suggestion_item' + : 'fcc_suggestion_item' + } + href={hit.url} + onClick={e => (dropdownFooter ? handleSubmit(e, hit.query) : '')} > - {hit.objectID.includes('default-hit-') ? ( + {dropdownFooter ? ( ) : ( - + )} diff --git a/client/src/components/search/searchBar/searchbar-base.css b/client/src/components/search/searchBar/searchbar-base.css index 2bfeb40472..62e881e9a0 100644 --- a/client/src/components/search/searchBar/searchbar-base.css +++ b/client/src/components/search/searchBar/searchbar-base.css @@ -420,9 +420,6 @@ a[class^='ais-'] { margin-left: 1rem; padding: 1rem; width: calc(25% - 1rem); - border: 1px solid #c4c8d8; - -webkit-box-shadow: 0 2px 5px 0px #e3e5ec; - box-shadow: 0 2px 5px 0px #e3e5ec; } .ais-Panel-body .ais-InfiniteHits-item, .ais-Panel-body .ais-InfiniteResults-item, @@ -596,7 +593,6 @@ a[class^='ais-'] { -webkit-appearance: none; -moz-appearance: none; appearance: none; - padding: 0.3rem 1.7rem; width: 100%; position: relative; background-color: #fff; @@ -604,16 +600,16 @@ a[class^='ais-'] { border-radius: 0px; } .ais-SearchBox-input::-webkit-input-placeholder { - color: #a5aed1; + color: var(--gray-15); } .ais-SearchBox-input::-moz-placeholder { - color: #a5aed1; + color: var(--gray-15); } .ais-SearchBox-input:-ms-input-placeholder { - color: #a5aed1; + color: var(--gray-15); } .ais-SearchBox-input:-moz-placeholder { - color: #a5aed1; + color: var(--gray-15); } .ais-SearchBox-submit, .ais-SearchBox-reset, @@ -646,8 +642,9 @@ a[class^='ais-'] { transform: translateX(-50%) translateY(-50%); } .ais-SearchBox-submitIcon path, -.ais-SearchBox-resetIcon path { - fill: #495588; +.ais-SearchBox-resetIcon path, +.ais-SearchBox-loadingIndicator { + fill: var(--gray-15); } .ais-SearchBox-submitIcon { width: 14px; @@ -661,13 +658,8 @@ a[class^='ais-'] { width: 16px; height: 16px; } - -.ais-SearchBox-input { - padding-left: 25px; - font-size: 14px; -} .ais-SearchBox-submitIcon > path { - fill: #006400; + fill: var(--gray-15); } .ais-Hits { position: absolute; @@ -679,17 +671,12 @@ a[class^='ais-'] { margin: 0; padding: 0; border: 0; - -webkit-box-shadow: none; - box-shadow: none; } .ais-Hits-list { margin: 0; display: flex; flex-direction: column; align-items: center; - border: 1px solid #c4c8d8; - -webkit-box-shadow: 0 2px 5px 0px #e3e5ec; - box-shadow: 0 2px 5px 0px #e3e5ec; } strong.ais-Highlight-highlighted { background-color: transparent; diff --git a/client/src/components/search/searchBar/searchbar.css b/client/src/components/search/searchBar/searchbar.css index 6b0fbc203e..434323dc90 100644 --- a/client/src/components/search/searchBar/searchbar.css +++ b/client/src/components/search/searchBar/searchbar.css @@ -2,11 +2,28 @@ flex-grow: 1; padding: 0 10px; max-height: 33px; + font-family: 'Lato', sans-serif; +} + +.fcc_searchBar strong, +.fcc_searchBar a:hover { + color: var(--gray-00); +} + +.ais-SearchBox-submit, +.ais-SearchBox-reset { + display: none; +} + +.ais-SearchBox-input { + padding: 1px 10px; + font-size: 18px; } .fcc_searchBar .ais-SearchBox-input, .fcc_searchBar .ais-Hits { - background-color: var(--quaternary-background); + background-color: var(--gray-75); + color: var(--gray-00); } .fcc_searchBar .ais-SearchBox-form { @@ -49,26 +66,31 @@ font-weight: bold; } -.fcc_searchBar .fcc_suggestion_item { - padding: 10px; +.ais-Highlight-nonHighlighted { + font-weight: 300; } + .fcc_hits_wrapper { display: flex; justify-content: center; } + .fcc_suggestion_item { display: block; - padding: 1rem; - color: #333; + padding: 8px; + color: var(--gray-00); + text-decoration: none; } + .fcc_suggestion_item [class^='ais-'] { font-size: 17px; } + .fcc_suggestion_item:hover { - background-color: rgba(0, 100, 0, 0.4); - color: white; + background-color: var(--blue-dark); cursor: pointer; } + .fcc_sr_only { position: absolute; width: 1px; @@ -79,3 +101,29 @@ clip: rect(0, 0, 0, 0); border: 0; } + +/* Dropdown footer */ +.fcc_suggestion_footer { + border-top: 1.5px solid var(--gray-00); +} + +.fcc_suggestion_footer .hit-name .ais-Highlight .ais-Highlight-nonHighlighted { + font-weight: bold; +} + +/* Show only the first 5 hits on mobile */ +.ais-Hits-list .ais-Hits-item:nth-child(n + 6) { + display: none; +} + +/* Ensure the dropdown footer is always visible */ +.ais-Hits-list .ais-Hits-item:nth-child(9) { + display: block; +} + +@media (min-width: 767px) and (min-height: 768px) { + /* Show hits 6-8 on desktop and some tablets */ + .ais-Hits-list .ais-Hits-item:nth-child(n + 6) { + display: block; + } +} diff --git a/client/src/components/search/searchPage/SearchPageHits.js b/client/src/components/search/searchPage/SearchPageHits.js index 0f93834761..c86879043f 100644 --- a/client/src/components/search/searchPage/SearchPageHits.js +++ b/client/src/components/search/searchPage/SearchPageHits.js @@ -9,58 +9,29 @@ import { isEmpty } from 'lodash'; import EmptySearch from './EmptySearch'; import NoResults from './NoResults'; -import { homeLocation } from '../../../../config/env.json'; import './search-page-hits.css'; -const indexMap = { - challenges: { - title: 'Lesson', - url: `${homeLocation}/learn` - }, - guides: { - title: 'Guide', - url: `${homeLocation}/guide` - }, - youtube: { - title: 'YouTube', - url: 'https://www.youtube.com/watch?v=' - } -}; - -const buildUrl = (index, result) => - `${indexMap[index].url}${'videoId' in result ? result.videoId : result.url}`; - const AllHits = connectAutoComplete(({ hits, currentRefinement }) => { - if (hits.some(hit => isEmpty(hit.index))) { - return null; - } - const nonQuerySuggestionHits = hits.filter( - ({ index }) => index !== 'query_suggestions' - ); - const isHitsEmpty = nonQuerySuggestionHits.every(({ hits }) => !hits.length); + const isHitsEmpty = !hits.length; return currentRefinement && !isHitsEmpty ? (
    ) : ( diff --git a/client/src/pages/search.js b/client/src/pages/search.js index 7f6c642eab..81ad38cb2c 100644 --- a/client/src/pages/search.js +++ b/client/src/pages/search.js @@ -2,12 +2,11 @@ import React, { Fragment, Component } from 'react'; import PropTypes from 'prop-types'; import Helmet from 'react-helmet'; import { connect } from 'react-redux'; -import { Index, PoweredBy as PoweredByAlgolia } from 'react-instantsearch-dom'; +import { Index } from 'react-instantsearch-dom'; import { Grid, Row, Col } from '@freecodecamp/react-bootstrap'; import { updateSearchQuery } from '../components/search/redux'; import SearchPageHits from '../components/search/searchPage/SearchPageHits'; -import Spacer from '../components/helpers/Spacer'; import './search.css'; @@ -23,18 +22,13 @@ class SearchPage extends Component { return ( - - - +
    - - -