4/11/2022 ∙ 3 minuty czytania
Czas i postęp czytania ⏱
Wiele stron zawiera funkcjonalność estymującą czas czytania tekstu oraz pokazuje, ile tekstu zdążyliśmy już przeczytać. Dzisiaj zaimplementujemy obie te funkcjonalności.
Estymacja tego, ile zajmie czytanie
Aby prawidłowo określić, ile czasu zajmuje czytanie tekstu przykładowo w minutach, wystarczy określić, jaki jest średni czas czytania tekstu na minutę, a następnie podzielić ilość słów w tekście przez tę wartość. Możemy napisać własną funkcję, która się tym zajmuje, ale jest kilka dodatkowych elementów o których należy pamiętać jak np.:
- nie można brać pod uwagę znaczników kodu
- kod czyta się inaczej niż zwykły tekst
- trzy osobno zapisane litery to nie 3 osobne słowa. Słowo należy traktować jako minimalną określona ilość znaków
dlatego skorzystamy z gotowej paczki:
reading-time
do której przekazujemy
tekst. W wyniku działania funkcji zostanie zwrócony obiekt o następującym typie:
type ReadingTimeResults = {
minutes: number
time: number
words: WordCountStats
}
z obiektu wyciągamy minuty, a następnie pokazujemy w tekście ile czasu zajmuje czytanie.
Postęp czytania
Na niektórych stronach można zobaczyć cienki pasek postępu czytania na samej górze strony reagujący na wydarzenie przewijania tekstu na stronie. Możemy w prosty sposób skopiować dane zachowanie pisząc następujący fragment kodu:
// components/Progress.tsx
import { Indicator as RawIndicator, Root } from '@radix-ui/react-progress'
import { motion, useTransform, useViewportScroll } from 'framer-motion'
import { useEffect, useState } from 'react'
const Indicator = motion(RawIndicator)
export const Progress = () => {
const [progress, setProgress] = useState(0)
const { scrollYProgress } = useViewportScroll()
const y = useTransform(scrollYProgress, [0, 1], [0, 100])
useEffect(() => {
const unsubscribe = y.onChange(setProgress)
return unsubscribe
}, [y])
return (
<Root className="fixed top-0 right-0 left-0" value={progress}>
<Indicator
className="h-2 bg-indigo-500"
style={{ width: `${progress}%` }}
/>
</Root>
)
}
Rozbijmy kod na czynniki pierwsze i przeanalizujmy co się tutaj właściwie dzieje:
Importy
import { Indicator as RawIndicator, Root } from '@radix-ui/react-progress'
import { motion, useTransform, useViewportScroll } from 'framer-motion'
@radix-ui/react-progress
- to bardzo prosta paczka, która wyświetla pasek postępu. Po co taka paczka, skoro mamy komponent<progress>
? Otóż radix to zbiór gotowych komponentów, w których twórcy zadbali o bardzo istotne szczegóły dotyczące wielu popularnych elementów, które możemy zobaczyć w aplikacjach internetowych. W przypadku komponentuprogress
, będzie to zapewnienie kontekstu dlatechnologii wspomagającej
do odczytywania postępu zadania na przykład dla osób z niepełnosprawnością.framer-motion
- z tej paczki mieliśmy okazję korzystać w poście na temat podstawowych animacji.
Wiązanie przewijania tekstu z postępem czytania
const [progress, setProgress] = useState(0)
const { scrollYProgress } = useViewportScroll()
const y = useTransform(scrollYProgress, [0, 1], [0, 100])
useEffect(() => {
const unsubscribe = y.onChange(setProgress)
return unsubscribe
}, [y])
useViewportScroll
- to hook, który nasłuchuje na wydarzenie przewijania tekstuuseTransform
- interpoluje wartość zwracaną z poprzedniego hooka z [0, 1] do [0, 100].y
- wartość typuMotionValue<number>
, którą trzeba odwrapować za pomocą kolejnego hooka (useEffect
)
Komponent postępu czytania
<Root className="fixed top-0 right-0 left-0" value={progress}>
<Indicator className="h-2 bg-indigo-500" style={{ width: `${progress}%` }} />
</Root>
Root
- każdy z komponentów / prymitywów bibliotekiradix-ui
ma komponentRoot
, który jest kontenerem na pozostałe komponenty / fragmenty danego prymitywuIndicator
- właściwy komponent progresu
W drzewie DOM możemy zobaczyć, że dzięki zastosowaniu ww. komponentów
wyrenderowane zostały atrybuty aria
oraz data
przydatne dla technologi
wspomagających.
exit
Poniżej znajdziesz więcej postów, które mogą Cię zainteresować.