import React, { memo, useCallback, useEffect, useState } from "react"; import { motion } from "motion/react"; import { ViewProps, LoadingStatus, WordData } from "./logic/types"; // import { fetchWord } from "../logic/calls"; import { wordVariants, createHoverEffect } from "./animations"; import { useZoom } from "./hooks/useZoom"; import { NLP } from "sortug-ai"; interface Props extends ViewProps { word: NLP.Stanza.Word; } function Word({ rawText, context, idx, word }: Props) { const { viewState, handleElementClick } = useZoom(); const { level, wIndex } = viewState; const selected = wIndex === idx; const isFocused = level === "word" && selected; // State for word data const [loading, setLoading] = useState("pending"); const [wordData, setData] = useState(null); const [error, setError] = useState(null); // Fetch word details when selected const getMeaning = useCallback(() => { setLoading("loading"); // Try to fetch the word data // fetchWord(rawText, "en") // .then((res) => { // if ("error" in res) { // setError(`Error loading word data: ${res.error}`); // setLoading("error"); // } else { // setData(res.ok); // setLoading("success"); // } // }) // .catch((err) => { // setError(`Failed to fetch word data: ${err.message}`); // setLoading("error"); // }); }, [rawText]); // Load word data when the word is selected useEffect(() => { if (isFocused && !wordData && loading === "pending") { getMeaning(); } }, [isFocused, getMeaning, wordData, loading]); return ( <> {/* Overlay backdrop when word is selected */} {isFocused && } handleElementClick(e, idx)} whileHover={ level === "clause" ? createHoverEffect(level, "clause", "255, 200, 200") : {} } style={{ backgroundColor: isFocused ? "white" : undefined, boxShadow: isFocused ? "0 8px 32px rgba(0, 0, 0, 0.15)" : undefined, }} > {level === "clause" || !selected ? ( {rawText} ) : (
{loading === "loading" && (

Loading word information...

)} {loading === "error" && (

{error || "Failed to load word information"}

)} {loading === "success" && wordData && (

{wordData.spelling}

{/* Syllables section moved to header - for next level of zoom */}
{Array.from({ length: wordData.syllables || 1 }).map( (_, i) => { // Create a simple syllable division (not linguistically accurate) const syllableLength = Math.ceil( rawText.length / (wordData.syllables || 1), ); const start = i * syllableLength; const end = Math.min( start + syllableLength, rawText.length, ); const syllable = rawText.substring(start, end); return ( { e.stopPropagation(); handleElementClick(e, i); }} > {syllable} ); }, )}
{/* Pronunciation */} {wordData.ipa && wordData.ipa.length > 0 && (

Pronunciation

{wordData.ipa.map((pronunciation, i) => (
{pronunciation.ipa} {pronunciation.tags && pronunciation.tags.length > 0 && ( {pronunciation.tags.join(", ")} )}
))}
)} {/* Word Senses/Meanings */} {wordData.senses && wordData.senses.length > 0 && (

Meanings

{wordData.senses.map((sense, i) => (
{sense.pos && ( {sense.pos} )} {sense.etymology && ( {sense.etymology} )}
{sense.senses && sense.senses.length > 0 && (
    {sense.senses.map((subSense, j) => (
  • {subSense.glosses && subSense.glosses.length > 0 && (
    {subSense.glosses.join("; ")}
    )}
  • ))}
)}
))}
)}
)}
)} ); } export default memo(Word);