diff options
author | polwex <polwex@sortug.com> | 2025-05-15 20:32:25 +0700 |
---|---|---|
committer | polwex <polwex@sortug.com> | 2025-05-15 20:32:25 +0700 |
commit | fd86dc15734f3b7126d88f0130897c597100e30a (patch) | |
tree | 253890a5f0bde7bc460904ce1743581f53a23d5b /src/zoom/SpacyClause.tsx | |
parent | 3d4b740e5a512db8fbdd934af2fbc9585fa00f0f (diff) |
m
Diffstat (limited to 'src/zoom/SpacyClause.tsx')
-rw-r--r-- | src/zoom/SpacyClause.tsx | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/zoom/SpacyClause.tsx b/src/zoom/SpacyClause.tsx new file mode 100644 index 0000000..6b6f178 --- /dev/null +++ b/src/zoom/SpacyClause.tsx @@ -0,0 +1,125 @@ +import React, { memo, useState } from "react"; +import { motion } from "motion/react"; +import "./spacy.css"; +import { NLP } from "sortug-ai"; +// import { clauseVariants, createHoverEffect } from "./animations"; +// import { useZoom } from "./hooks/useZoom"; + +function Grammar({ sentence }: { sentence: NLP.Spacy.Sentence }) { + const [hoveredClause, setHoveredClause] = useState<number | null>(null); + + // Ref to manage the timeout for debouncing mouse leave + return ( + <div className="clause-container"> + {sentence.words.map((w, idx) => { + const isRoot = + w.ancestors.length === 0 || w.dep.toLowerCase() === "root"; + const isSubj = NLP.Spacy.isChild(w, sentence.subj.id); + const isPred = !isSubj && !isRoot; + const predClass = isPred ? "pred" : ""; + const relClass = isRoot ? "root" : `rel-${w.dep}`; + const ownClass = isRoot + ? "" + : isSubj + ? "subj" + : w.children.length === 0 + ? "" + : `clause-${w.id}`; + const clase = w.ancestors.reduce((acc, item) => { + if (item === sentence.subj.id || item === sentence.root.id) + return acc; + else return `${acc} clause-${item}`; + }, ``); + const className = `suword ${relClass} ${ownClass} ${clase} ${predClass}`; + const isHovering = + !isRoot && + !!hoveredClause && + (w.id === hoveredClause || w.ancestors.includes(hoveredClause)); + function handleClick(w: NLP.Spacy.Word) { + console.log("show the whole clause and all that", w); + } + return ( + <ClauseSpan + word={w} + key={w.id} + className={className} + hovering={isHovering} + setHovering={setHoveredClause} + onClick={handleClick} + /> + ); + })} + </div> + ); +} + +const spanVariants: any = { + initial: { + // Base style + backgroundColor: "rgba(0, 0, 0, 0)", // Transparent background initially + fontWeight: "normal", + scale: 1, + zIndex: 0, // Default stacking + position: "relative", // Needed for zIndex to work reliably + // Add other base styles if needed + }, + hovered: { + // Style when this span's group is hovered + backgroundColor: "rgba(255, 255, 0, 0.5)", // Yellow highlight + scale: 1.05, + zIndex: 1, // Bring hovered spans slightly forward + boxShadow: "0px 2px 5px rgba(0,0,0,0.2)", + // Add other hover effects + }, +}; + +// Define the transition +const spanTransition = { + type: "spring", + stiffness: 500, + damping: 30, + // duration: 0.1 // Or use duration for non-spring types +}; + +function ClauseSpan({ + word, + className, + hovering, + setHovering, + onClick, +}: { + word: NLP.Spacy.Word; + className: string; + hovering: boolean; + setHovering: (n: number | null) => void; + onClick: (w: NLP.Spacy.Word) => void; +}) { + function handleMouseOver() { + setHovering(word.id); + // if (word.children.length > 0) setHovering(word.id); + // else setHovering(word.head); + } + function handleMouseLeave() { + setHovering(null); + } + function handleClick(e: React.MouseEvent) { + e.stopPropagation(); + onClick(word); + } + return ( + <motion.span + className={className} + variants={spanVariants} + initial="initial" + animate={hovering ? "hovered" : "initial"} + transition={spanTransition} + onMouseOver={handleMouseOver} + onMouseLeave={handleMouseLeave} + onClick={handleClick} + > + {word.text} + </motion.span> + ); +} + +export default memo(Grammar); |