A Pen by Vincent Voyer on CodePen.
Created
July 21, 2016 07:37
-
-
Save vvo/6eab06c20aa2620f038292ebc1f84350 to your computer and use it in GitHub Desktop.
Algolia + React
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<h1>algoliasearch-helper-js + react-algoliasearch-helper + React</h1> | |
<div id="root"></div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const client = algoliasearch('latency', '6be0576ff61c053d5f9a3225e2a90f76'); | |
const helper = algoliasearchHelper(client, 'movies', { | |
disjunctiveFacets: ['genre'] | |
}); | |
const Provider = reactAlgoliaSearchHelper.Provider; | |
const connect = reactAlgoliaSearchHelper.connect; | |
const SearchBox = connect()( | |
({helper}) => | |
<div className="search-box"> | |
<div className="search-box__button"> | |
<i className="fa fa-search"></i> | |
</div> | |
<div className="search-box__input-container"> | |
<input | |
type="text" | |
className="search-box__input" | |
placeholder="Search here" | |
onChange={e => helper.setQuery(e.target.value).search()} | |
/> | |
</div> | |
</div> | |
); | |
const getHighlighted = s => ({__html: s}); | |
const Rating = ({rating}) => { | |
const bem = block('rating'); | |
const stars = []; | |
for (var i = 1; i <= 5; ++i) { | |
stars.push(i <= rating); | |
} | |
stars.reverse(); | |
return <div className={bem()}> | |
{stars.map( | |
(active, starIndex) => <span key={starIndex} className={bem("star")({active})}>☆</span> | |
)} | |
</div> | |
} | |
const Hit = ({ | |
_highlightResult: { | |
title: { | |
value: title | |
} | |
}, | |
year, | |
image, | |
rating, | |
genre: genres | |
}) => | |
<article className="movie"> | |
<img className="movie__image" src={image} /> | |
<div className="movie__meta"> | |
<div className="movie__title"> | |
<span dangerouslySetInnerHTML={getHighlighted(title)} /> | |
<span className="movie__year">{year}</span> | |
</div> | |
<div className="movie__rating"><Rating rating={rating} /></div> | |
<div className="movie__genres"> | |
{genres.map(genre => <div key={genre} className="movie__genre">{genre}</div>)} | |
</div> | |
</div> | |
</article> | |
const Hits = connect( | |
state => ({results: state.searchResults}) | |
)( | |
({results}) => { | |
if (!results) return <div className="hits__empty">Search for something</div>; | |
if (results.hits.length === 0) return <div className="hits__empty">No results</div>; | |
return <div className="hits"> | |
{results.hits.map(hit => <div className="movie__container" key={hit.objectID}><Hit {...hit}/></div>)} | |
</div>; | |
} | |
); | |
const Genres = connect( | |
state => ({genres: state.searchResults && state.searchResults.getFacetValues('genre') || []}) | |
)( | |
({genres, helper}) => | |
<div> | |
{genres.map( | |
({name, count, isRefined}) => | |
<div key={name} onClick={e => helper.toggleRefine('genre', name).search()} className={`facet__item facet__item${isRefined ? '_active': ''}`}> | |
<div className="facet__item-label">{name} <div className="facet__item-count">{count}</div></div> | |
</div> | |
)} | |
</div> | |
); | |
const Pagination = connect( | |
({searchResults}) => (searchResults === null ? {page: 0, nbPages: 0} : {page: searchResults.page, nbPages: searchResults.nbPages}) | |
)( | |
({page, nbPages, helper}) => | |
<div className="pagination"> | |
<button className="pagination__button" onClick={e => helper.setPage(page - 1).search()} disabled={page === 0}>Previous</button> | |
<span className="pagination__page">{page + 1}</span> | |
<button className="pagination__button" onClick={e => helper.setPage(page + 1).search()} disabled={page + 1 >= nbPages}>Next</button> | |
</div> | |
); | |
const App = () => | |
<Provider helper={helper}> | |
<div className="container"> | |
<SearchBox/> | |
<div className="content"> | |
<div className="facets"> | |
<div className="facet"> | |
<div className="facet__title">Genre</div> | |
<Genres/> | |
</div> | |
</div> | |
<div className="canvas"> | |
<Hits/> | |
<Pagination/> | |
</div> | |
</div> | |
</div> | |
</Provider>; | |
ReactDOM.render(<App/>, document.querySelector('#root')); | |
helper.search(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://npmcdn.com/react@15.0.1/dist/react.js"></script> | |
<script src="https://npmcdn.com/react-dom@15.0.1/dist/react-dom.js"></script> | |
<script src="https://npmcdn.com/react-algoliasearch-helper@1/umd/reactAlgoliaSearchHelper.js"></script> | |
<script src="https://npmcdn.com/algoliasearch@3/dist/algoliasearchLite.js"></script> | |
<script src="https://npmcdn.com/algoliasearch-helper@2/dist/algoliasearch.helper.js"></script> | |
<script src="https://npmcdn.com/bem-cn@2"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.rating { | |
unicode-bidi: bidi-override; | |
direction: rtl; | |
text-align: left; | |
} | |
.rating__star { | |
display: inline-block; | |
position: relative; | |
width: 1.1em; | |
height: 1.1em; | |
color: #cccccc; | |
} | |
.rating__star_active, | |
.rating__star_active ~ .rating__star { | |
color: transparent; | |
} | |
.rating__star_active:before { | |
content: "\2605"; | |
position: absolute; | |
left: 0; | |
color: gold; | |
} | |
* { | |
box-sizing: border-box; | |
} | |
body { | |
font-family: arial, sans-serif; | |
font-size: 20px; | |
margin: 0; | |
padding: 20px; | |
} | |
.container { | |
display: flex; | |
flex-direction: column; | |
} | |
.search-box { | |
position: relative; | |
display: flex; | |
} | |
.search-box__button { | |
align-self: stretch; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
width: 2.4em; | |
font-size: 1.6em; | |
background-color: lighten(#0074D9, 5%); | |
color: white; | |
cursor: pointer; | |
text-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); | |
box-shadow: inset 0 -6px 12px -8px rgba(0, 0, 0, 0.2), inset 0 6px 12px -8px rgba(255, 255, 255, 0.2); | |
&:hover { | |
background-color: lighten(#0074D9, 10%); | |
} | |
&:active { | |
background-color: darken(#0074D9, 5%); | |
box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.2); | |
} | |
} | |
.search-box__input-container { | |
position: relative; | |
flex: 1; | |
} | |
.search-box__input { | |
width: 100%; | |
font-size: inherit; | |
border: 1px solid rgba(0, 0, 0, 0.3); | |
border-left: none; | |
box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.1); | |
outline: none; | |
padding: 0.8em 1em; | |
font-size: 1.2em; | |
&:focus { | |
box-shadow: inset 0 2px 6px rgba(0, 100, 220, 0.15); | |
border-color: rgba(0, 100, 220, 0.6); | |
} | |
} | |
.content { | |
display: flex; | |
margin-top: 1rem; | |
border: 1px solid rgba(0, 0, 0, 0.3); | |
} | |
.canvas { | |
flex: 1; | |
display: flex; | |
flex-direction: column; | |
position: relative; | |
padding: 10px; | |
background-color: rgba(0, 0, 0, 0.1); | |
box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.1); | |
} | |
.hits { | |
display: flex; | |
flex-wrap: wrap; | |
flex: 1; | |
} | |
.hits__empty { | |
height: 100%; | |
justify-content: center; | |
align-items: center; | |
font-size: 1.6em; | |
color: rgba(0, 0, 0, 0.4); | |
} | |
.movie__container { | |
flex: 1 0 25%; | |
min-width: 380px; | |
} | |
.movie { | |
position: relative; | |
display: flex; | |
margin: 10px; | |
border: 1px solid rgba(0, 0, 0, 0.4); | |
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); | |
background-color: white; | |
padding: 0.2em; | |
} | |
.movie__image { | |
flex-shrink: 0; | |
height: 231px; | |
width: 154px; | |
background-color: rgba(0, 0, 0, 0.1); | |
} | |
.movie__meta { | |
display: flex; | |
flex-direction: column; | |
justify-content: center; | |
margin-left: 1em; | |
} | |
.movie__title { | |
align-items: center; | |
font-size: 1.1em; | |
font-weight: bold; | |
em { | |
color: rgb(0, 150, 230); | |
background: rgba(0, 160, 220, 0.2); | |
} | |
} | |
.movie__year { | |
font-size: 0.8em; | |
font-weight: normal; | |
color: rgba(0, 0, 0, 0.6); | |
padding-left: .5em; | |
} | |
.movie__rating { | |
margin-top: 0.2em; | |
} | |
.movie__genres { | |
display: flex; | |
flex-wrap: wrap; | |
font-size: 0.8em; | |
margin-top: 0.7em; | |
margin-right: -0.4em; | |
margin-bottom: -0.4em; | |
} | |
.movie__genre { | |
color: rgba(0, 0, 0, 0.7); | |
padding: 0.4em 0.6em; | |
background-color: rgba(0, 0, 0, 0.1); | |
margin-right: 0.4em; | |
margin-bottom: 0.4em; | |
} | |
.pagination { | |
margin: 10px 0; | |
text-align: center; | |
} | |
.pagination > * { | |
margin: 0 .5em; | |
} | |
.pagination__button { | |
font-size: 110%; | |
} | |
.facets { | |
width: 20%; | |
min-width: 270px; | |
border-right: 1px solid rgba(0, 0, 0, 0.3); | |
} | |
.facet { | |
padding: 1em 0; | |
border-bottom: 2px solid rgba(0, 0, 0, 0.1); | |
} | |
.facet__title { | |
padding: 0 1em; | |
font-size: 1.1em; | |
margin-bottom: 0.6em; | |
} | |
.facet__item { | |
padding: 0 1em; | |
cursor: pointer; | |
color: rgba(0, 0, 0, 0.7); | |
&:hover { | |
color: black; | |
background-color: rgba(0, 0, 0, 0.04); | |
} | |
} | |
.facet__item_active { | |
background-color: rgba(0, 0, 0, 0.08); | |
font-weight: bold; | |
color: black; | |
} | |
.facet__item-label { | |
position: relative; | |
display: flex; | |
line-height: 1.4em; | |
cursor: inherit; | |
} | |
.facet__item-count{ | |
top: 0; | |
position: absolute; | |
right: 0; | |
font-size: 0.8em; | |
color: rgba(0, 0, 0, 0.4); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment