search.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import fuse from 'fuse.js'
  2. import theme from '../styles/theme'
  3. const dummyResults = [
  4. {
  5. title: 'good :-)',
  6. text: 'a good text.',
  7. link: 'good'
  8. },
  9. {
  10. title: 'bad :-(',
  11. text: 'a bad text.',
  12. link: 'bad'
  13. }
  14. ]
  15. class Search extends React.Component {
  16. state = {
  17. active: false,
  18. query: '',
  19. results: []
  20. }
  21. focus = ev => {
  22. this.setState({ active: true })
  23. }
  24. blur = ev => {
  25. this.setState({ active: false })
  26. }
  27. change = ev => {
  28. const { value } = ev.target
  29. this.setState({ query: ev.target.value })
  30. const fuseOptions = {
  31. shouldSort: true,
  32. includeMatches: true,
  33. threshold: 0.3,
  34. location: true,
  35. keys: ['title', 'text', 'link']
  36. }
  37. const fuseInst = new fuse(dummyResults, fuseOptions)
  38. const searchResults = fuseInst.search(value)
  39. console.log(dummyResults, searchResults)
  40. if (value) {
  41. this.setState({
  42. results: searchResults
  43. })
  44. } else {
  45. this.setState({ results: [] })
  46. }
  47. }
  48. clear = ev => {
  49. this.setState({ query: '' })
  50. }
  51. render () {
  52. return (
  53. <>
  54. <div id='searchbar'>
  55. <input
  56. type='text'
  57. placeholder='Search..'
  58. onFocus={this.focus}
  59. onBlur={this.blur}
  60. onChange={this.change}
  61. value={this.state.query}
  62. />
  63. <button
  64. style={{ display: this.state.query ? 'block' : 'none' }}
  65. onClick={this.clear}
  66. >
  67. x
  68. </button>
  69. <button type='submit' disabled={!this.state.query}>
  70. <span>Search</span>
  71. </button>
  72. {this.state.active &&
  73. this.state.query &&
  74. (this.state.results ? (
  75. <ul id='searchresults'>
  76. {this.state.results.map(result => (
  77. <Result key={result.title} {...result} />
  78. ))}
  79. </ul>
  80. ) : (
  81. <p>Nothing found.</p>
  82. ))}
  83. </div>
  84. <style jsx>
  85. {`
  86. #searchbar {
  87. display: grid;
  88. grid-template-columns: 1fr 1em 2em;
  89. border: 1px solid ${theme.colors.lightgrey};
  90. padding: 0.3em 2em;
  91. }
  92. input[type='text'] {
  93. border: none;
  94. width: 60%;
  95. }
  96. button {
  97. font-weight: 900;
  98. background: transparent;
  99. color: ${theme.colors.darkgrey};
  100. border: none;
  101. cursor: pointer;
  102. box-shadow: none;
  103. }
  104. button[type='submit'] {
  105. content: '';
  106. }
  107. button > span {
  108. display: none;
  109. }
  110. #searchresults {
  111. position: absolute;
  112. background: ${theme.colors.lightgrey};
  113. top: 2em;
  114. }
  115. `}
  116. </style>
  117. </>
  118. )
  119. }
  120. }
  121. const Result = props => {
  122. const { item, matches } = props
  123. return (
  124. <li>
  125. <a href={item.link}>
  126. <h3>{item.title}</h3>
  127. <p>{item.text}</p>
  128. </a>
  129. </li>
  130. )
  131. }
  132. export default Search