Add Gutenberg search
This commit is contained in:
		
							parent
							
								
									6cc58a70bd
								
							
						
					
					
						commit
						3bec754ae8
					
				@ -1,7 +1,13 @@
 | 
			
		||||
import React from 'react'
 | 
			
		||||
 | 
			
		||||
import { RsvpReader } from './components/RsvpReader'
 | 
			
		||||
import { GutenbergSearch } from './components/GutenbergSearch'
 | 
			
		||||
 | 
			
		||||
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 styles from './RsvpReader.css'
 | 
			
		||||
import { PipeMarker, BorderMarker } from './PivotMarker'
 | 
			
		||||
import { BorderMarker } from './PivotMarker'
 | 
			
		||||
import { Progress } from './Progress'
 | 
			
		||||
import { TimeCalc } from './TimeCalc'
 | 
			
		||||
 | 
			
		||||
@ -30,9 +30,7 @@ export const RsvpReader = () => {
 | 
			
		||||
        <Options></Options>
 | 
			
		||||
        <TimeCalc />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div className={styles.item}>
 | 
			
		||||
        <TextOutput />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div className={styles.item}>{/* <TextOutput /> */}</div>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,5 @@
 | 
			
		||||
import 'regenerator-runtime/runtime'
 | 
			
		||||
 | 
			
		||||
import React from 'react'
 | 
			
		||||
import ReactDOM from 'react-dom'
 | 
			
		||||
import { Provider } from 'react-redux'
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user