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…
Reference in New Issue
Block a user