summaryrefslogtreecommitdiff
path: root/src/zoom/SpacyClause.tsx
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-05-15 20:32:25 +0700
committerpolwex <polwex@sortug.com>2025-05-15 20:32:25 +0700
commitfd86dc15734f3b7126d88f0130897c597100e30a (patch)
tree253890a5f0bde7bc460904ce1743581f53a23d5b /src/zoom/SpacyClause.tsx
parent3d4b740e5a512db8fbdd934af2fbc9585fa00f0f (diff)
m
Diffstat (limited to 'src/zoom/SpacyClause.tsx')
-rw-r--r--src/zoom/SpacyClause.tsx125
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);