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