import "./LongFormText.css"; import { TaggedNostrEvent } from "@snort/system"; import classNames from "classnames"; import { CSSProperties, useCallback, useRef, useState } from "react"; import { FormattedMessage, FormattedNumber } from "react-intl"; import Text from "@/Components/Text/Text"; import ProfilePreview from "@/Components/User/ProfilePreview"; import useImgProxy from "@/Hooks/useImgProxy"; import { findTag } from "@/Utils"; import { Markdown } from "./Markdown"; import NoteFooter from "./Note/NoteFooter/NoteFooter"; import NoteTime from "./Note/NoteTime"; interface LongFormTextProps { ev: TaggedNostrEvent; isPreview: boolean; onClick?: () => void; truncate?: boolean; } const TEXT_TRUNCATE_LENGTH = 400; export function LongFormText(props: LongFormTextProps) { const title = findTag(props.ev, "title"); const summary = findTag(props.ev, "summary"); const image = findTag(props.ev, "image"); const { proxy } = useImgProxy(); const [reading, setReading] = useState(false); const [showMore, setShowMore] = useState(false); const ref = useRef(null); function previewText() { return ( ); } function readTime() { const wpm = 225; const words = props.ev.content.trim().split(/\s+/).length; return { words, wpm, mins: Math.ceil(words / wpm), }; } const readAsync = async (text: string) => { return await new Promise(resolve => { const ut = new SpeechSynthesisUtterance(text); ut.onend = () => { resolve(); }; window.speechSynthesis.speak(ut); }); }; const readArticle = useCallback(async () => { if (ref.current && !reading) { setReading(true); const paragraphs = ref.current.querySelectorAll("p,h1,h2,h3,h4,h5,h6"); for (const p of paragraphs) { if (p.textContent) { p.classList.add("reading"); await readAsync(p.textContent); p.classList.remove("reading"); } } setReading(false); } }, [ref, reading]); const stopReading = () => { setReading(false); if (ref.current) { const paragraphs = ref.current.querySelectorAll("p,h1,h2,h3,h4,h5,h6"); paragraphs.forEach(a => a.classList.remove("reading")); window.speechSynthesis.cancel(); } }; const ToggleShowMore = () => ( { e.preventDefault(); e.stopPropagation(); setShowMore(!showMore); }}> {showMore ? : } ); const shouldTruncate = props.truncate && props.ev.content.length > TEXT_TRUNCATE_LENGTH; const content = shouldTruncate && !showMore ? props.ev.content.slice(0, TEXT_TRUNCATE_LENGTH) : props.ev.content; function fullText() { return ( <>
, }} />
{!reading && (
readArticle()}>
)} {reading && (
stopReading()}>
)}

{shouldTruncate && showMore && } {shouldTruncate && !showMore && }
); } return (
} options={{ about: false, }} />

{title}

{summary} {image &&
} {props.isPreview ? previewText() : fullText()}
); }