Add Gutenberg search
This commit is contained in:
		
							parent
							
								
									6cc58a70bd
								
							
						
					
					
						commit
						3bec754ae8
					
				@ -1,7 +1,13 @@
 | 
				
			|||||||
import React from 'react'
 | 
					import React from 'react'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { RsvpReader } from './components/RsvpReader'
 | 
					import { RsvpReader } from './components/RsvpReader'
 | 
				
			||||||
 | 
					import { GutenbergSearch } from './components/GutenbergSearch'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const App = () => {
 | 
					export const App = () => {
 | 
				
			||||||
  return <RsvpReader></RsvpReader>
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <RsvpReader></RsvpReader>
 | 
				
			||||||
 | 
					      <GutenbergSearch></GutenbergSearch>
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										82
									
								
								src/components/GutenbergSearch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/components/GutenbergSearch.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					import React, { useState, useEffect, useCallback } from 'react'
 | 
				
			||||||
 | 
					import axios from 'axios'
 | 
				
			||||||
 | 
					import { useDispatch } from 'react-redux'
 | 
				
			||||||
 | 
					import { debounce } from 'debounce'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { setText } from '../store/actions.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function search(searchTerm) {
 | 
				
			||||||
 | 
					  const regex = new RegExp(searchTerm, 'i')
 | 
				
			||||||
 | 
					  const result = []
 | 
				
			||||||
 | 
					  const data = await import('../../data/gutenberg.json').then(
 | 
				
			||||||
 | 
					    module => module.default
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					  for (let entry of data) {
 | 
				
			||||||
 | 
					    if (regex.test(entry.title[0]) || regex.test(entry.author[0])) {
 | 
				
			||||||
 | 
					      result.push(entry)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (result.length >= 20) break
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Book = ({ entry }) => {
 | 
				
			||||||
 | 
					  const dispatch = useDispatch()
 | 
				
			||||||
 | 
					  const { author, language, rights, subject, title, id } = entry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleClick = async () => {
 | 
				
			||||||
 | 
					    const url = `https://gutenberg.muperfredi.de/texts/${id}/stripped-body`
 | 
				
			||||||
 | 
					    const text = await axios.get(url).then(res => res.data.body)
 | 
				
			||||||
 | 
					    dispatch(setText(text))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        {id} {title.join(' - ')}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div>{author[0]}</div>
 | 
				
			||||||
 | 
					      <div>{language.join(' - ')}</div>
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        <button onClick={handleClick}>Load</button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <br></br>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const GutenbergSearch = () => {
 | 
				
			||||||
 | 
					  const [searchTerm, setSearchTerm] = useState('')
 | 
				
			||||||
 | 
					  const [result, setResult] = useState([])
 | 
				
			||||||
 | 
					  const [loading, setLoading] = useState(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const debouncedSearch = useCallback(
 | 
				
			||||||
 | 
					    debounce(async term => {
 | 
				
			||||||
 | 
					      setLoading(true)
 | 
				
			||||||
 | 
					      await search(term).then(setResult)
 | 
				
			||||||
 | 
					      setLoading(false)
 | 
				
			||||||
 | 
					    }, 500),
 | 
				
			||||||
 | 
					    []
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (searchTerm.length > 0) {
 | 
				
			||||||
 | 
					      debouncedSearch(searchTerm)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [searchTerm, debouncedSearch])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <h2>Search for books in the Gutenberg Project</h2>
 | 
				
			||||||
 | 
					      <input
 | 
				
			||||||
 | 
					        value={searchTerm}
 | 
				
			||||||
 | 
					        onChange={e => setSearchTerm(e.target.value)}
 | 
				
			||||||
 | 
					      ></input>
 | 
				
			||||||
 | 
					      {loading && 'loading...'}
 | 
				
			||||||
 | 
					      {result.map(entry => (
 | 
				
			||||||
 | 
					        <Book key={entry.id} entry={entry} />
 | 
				
			||||||
 | 
					      ))}
 | 
				
			||||||
 | 
					      {result.length === 0 && <div>'no results to display'</div>}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -7,7 +7,7 @@ import { Options } from './Options'
 | 
				
			|||||||
import { PlayerControl } from './PlayerControl'
 | 
					import { PlayerControl } from './PlayerControl'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import styles from './RsvpReader.css'
 | 
					import styles from './RsvpReader.css'
 | 
				
			||||||
import { PipeMarker, BorderMarker } from './PivotMarker'
 | 
					import { BorderMarker } from './PivotMarker'
 | 
				
			||||||
import { Progress } from './Progress'
 | 
					import { Progress } from './Progress'
 | 
				
			||||||
import { TimeCalc } from './TimeCalc'
 | 
					import { TimeCalc } from './TimeCalc'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -30,9 +30,7 @@ export const RsvpReader = () => {
 | 
				
			|||||||
        <Options></Options>
 | 
					        <Options></Options>
 | 
				
			||||||
        <TimeCalc />
 | 
					        <TimeCalc />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div className={styles.item}>
 | 
					      <div className={styles.item}>{/* <TextOutput /> */}</div>
 | 
				
			||||||
        <TextOutput />
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					import 'regenerator-runtime/runtime'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import React from 'react'
 | 
					import React from 'react'
 | 
				
			||||||
import ReactDOM from 'react-dom'
 | 
					import ReactDOM from 'react-dom'
 | 
				
			||||||
import { Provider } from 'react-redux'
 | 
					import { Provider } from 'react-redux'
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user