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/picker/Old.tsx | |
parent | 3d4b740e5a512db8fbdd934af2fbc9585fa00f0f (diff) |
m
Diffstat (limited to 'src/picker/Old.tsx')
-rw-r--r-- | src/picker/Old.tsx | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/src/picker/Old.tsx b/src/picker/Old.tsx new file mode 100644 index 0000000..f02e538 --- /dev/null +++ b/src/picker/Old.tsx @@ -0,0 +1,252 @@ +import React, { useState, useMemo, useCallback } from "react"; +import { + TextSelect, + Combine, + WholeWord, + Highlighter, + Atom, + Mic2, + ChevronRight, + CheckCircle2, +} from "lucide-react"; + +// Define granularity levels +const GRANULARITY_LEVELS = [ + { id: "text", name: "Text", icon: TextSelect }, + { id: "paragraph", name: "Paragraph", icon: Combine }, + { id: "sentence", name: "Sentence", icon: Highlighter }, + { id: "clause", name: "Clause", icon: Highlighter }, // Simplified + { id: "word", name: "Word", icon: WholeWord }, + { id: "syllable", name: "Syllable", icon: Mic2 }, // Conceptual + { id: "phoneme", name: "Phoneme", icon: Atom }, // Conceptual +] as const; + +type GranularityId = (typeof GRANULARITY_LEVELS)[number]["id"]; + +// Granularity Menu Component +interface GranularityMenuProps { + selectedGranularity: GranularityId; + onSelectGranularity: (granularity: GranularityId) => void; +} + +const GranularityMenu: React.FC<GranularityMenuProps> = ({ + selectedGranularity, + onSelectGranularity, +}) => { + return ( + <nav className="w-64 bg-slate-800 text-slate-100 p-4 space-y-2 rounded-lg shadow-lg"> + <h2 className="text-lg font-semibold text-sky-400 mb-4"> + Granularity Level + </h2> + {GRANULARITY_LEVELS.map((level) => { + const Icon = level.icon; + const isSelected = selectedGranularity === level.id; + return ( + <button + key={level.id} + onClick={() => onSelectGranularity(level.id)} + className={`w-full flex items-center space-x-3 p-3 rounded-md text-left transition-all duration-150 ease-in-out + ${ + isSelected + ? "bg-sky-500 text-white shadow-md scale-105" + : "hover:bg-slate-700 hover:text-sky-300" + }`} + > + <Icon + size={20} + className={`${isSelected ? "text-white" : "text-sky-400"}`} + /> + <span>{level.name}</span> + {isSelected && ( + <CheckCircle2 size={18} className="ml-auto text-white" /> + )} + </button> + ); + })} + </nav> + ); +}; + +// Text Viewer Component +interface TextViewerProps { + document: TextDocument; + granularity: GranularityId; + onElementSelect: (elementType: GranularityId, element: any) => void; // element type can be more specific +} + +const TextViewer: React.FC<TextViewerProps> = ({ + document, + granularity, + onElementSelect, +}) => { + const handleElementClick = (type: GranularityId, data: any) => { + // For syllable/phoneme, pass the parent word data for now + if ((type === "syllable" || type === "phoneme") && data.type === "word") { + onElementSelect(type, { ...data, originalClickType: type }); + } else { + onElementSelect(type, data); + } + }; + + const renderContent = () => { + if (granularity === "text") { + return ( + <div + className="p-4 rounded-md bg-white shadow hover:bg-sky-50 cursor-pointer transition-colors" + onClick={() => handleElementClick("text", document)} + > + {document.paragraphs.map((p) => ( + <p key={p.id} className="mb-4 leading-relaxed"> + {p.text} + </p> + ))} + </div> + ); + } + + return document.paragraphs.map((paragraph) => ( + <div + key={paragraph.id} + className={`p-3 mb-4 rounded-md transition-all duration-150 + ${granularity === "paragraph" ? "bg-white shadow hover:bg-sky-100 cursor-pointer" : "bg-transparent"}`} + onClick={ + granularity === "paragraph" + ? () => handleElementClick("paragraph", paragraph) + : undefined + } + > + {paragraph.sentences.map((sentence) => ( + <span // Sentences are inline for paragraph flow, but can be styled as blocks if needed + key={sentence.id} + className={`mr-1 transition-all duration-150 + ${granularity === "sentence" || granularity === "clause" ? "p-1 hover:bg-sky-200 bg-white shadow-sm rounded cursor-pointer" : ""} + ${granularity === "syllable" || granularity === "phoneme" ? "" : ""} + `} + onClick={ + granularity === "sentence" || granularity === "clause" + ? () => handleElementClick(granularity, sentence) + : undefined + } + > + {granularity === "word" || + granularity === "syllable" || + granularity === "phoneme" + ? sentence.words + .map((word, wordIndex) => ( + <span + key={word.id} + className="p-0.5 hover:bg-yellow-200 bg-white rounded cursor-pointer transition-colors" + onClick={() => handleElementClick(granularity, word)} // Syllable/Phoneme click conceptually targets word + > + {word.text} + </span> + )) + .reduce( + (prev, curr, idx) => ( + <> + {prev} + {idx > 0 && " "} + {curr} + </> + ), + <></>, + ) // Add spaces between words + : sentence.text} + </span> + ))} + </div> + )); + }; + + return ( + <div className="text-lg text-gray-800 leading-relaxed"> + {renderContent()} + </div> + ); +}; + +// Main Application Component +export default function TextAnalysisScreen() { + const [selectedGranularity, setSelectedGranularity] = + useState<GranularityId>("word"); + const [currentDocument, setCurrentDocument] = + useState<TextDocument>(sampleTextDocument); + const [selectedElementInfo, setSelectedElementInfo] = useState<string | null>( + null, + ); + + const handleGranularityChange = useCallback((granularity: GranularityId) => { + setSelectedGranularity(granularity); + setSelectedElementInfo(null); // Clear selection when granularity changes + }, []); + + const handleElementSelect = useCallback( + (elementType: GranularityId, elementData: any) => { + let info = `Selected: ${elementType.toUpperCase()}\n`; + if (elementData.text) { + info += `Text: "${elementData.text.substring(0, 100)}${elementData.text.length > 100 ? "..." : ""}"\n`; + } + info += `ID: ${elementData.id}`; + if ( + elementData.originalClickType && + elementData.originalClickType !== elementType + ) { + info += `\n(Clicked as ${elementData.originalClickType}, showing parent Word)`; + } + setSelectedElementInfo(info); + // Here you would typically navigate to a detail view or open a modal + // For example: router.push(`/details/${elementType}/${elementData.id}`); + console.log("Selected Element:", elementType, elementData); + }, + [], + ); + + return ( + <div className="min-h-screen bg-gradient-to-br from-slate-100 to-sky-100 p-4 sm:p-8 font-sans"> + <header className="mb-8 text-center"> + <h1 className="text-3xl sm:text-4xl font-bold text-slate-800"> + Text Analyzer + </h1> + </header> + + <div className="flex flex-col lg:flex-row gap-6 max-w-7xl mx-auto"> + {/* Sticky container for the menu */} + <div className="lg:w-72 lg:sticky lg:top-8 h-full"> + {" "} + {/* Ensure menu is sticky on larger screens */} + <GranularityMenu + selectedGranularity={selectedGranularity} + onSelectGranularity={handleGranularityChange} + /> + {selectedElementInfo && ( + <div className="mt-6 p-4 bg-white rounded-lg shadow-md text-sm text-slate-700"> + <h3 className="font-semibold text-sky-600 mb-2"> + Selection Details: + </h3> + <pre className="whitespace-pre-wrap break-all"> + {selectedElementInfo} + </pre> + </div> + )} + </div> + + <main className="flex-1 bg-slate-50 p-4 sm:p-6 rounded-xl shadow-xl min-w-0"> + {" "} + {/* min-w-0 for flex child */} + <TextViewer + document={currentDocument} + granularity={selectedGranularity} + onElementSelect={handleElementSelect} + /> + </main> + </div> + + <footer className="text-center mt-12 text-sm text-slate-500"> + <p> + © {new Date().getFullYear()} Advanced Text Analysis Tool. All + rights reserved. + </p> + </footer> + </div> + ); +} |