Enhance the UI/UX design for displaying the JSON payload. The primary focus remains on the 'content' field, with effective presentation of metadata. Implement text selection within the 'content' field, enabling users to highlight text, mark it as important, and add annotations. Upon text selection, include a question mark icon next to the selected text. Clicking the question mark icon should trigger an AI chat interface, pre-populated with the selected text as context. The AI chat should be capable of answering questions and providing insights based on the selected text. Ensure the design is visually appealing, intuitive, and responsive across various devices.
This is a great evolution of the feature! We'll enhance the UI to allow users to highlight text, mark it as important, add annotations, and then trigger an AI chat with the selected text as context.
Here's the refined approach:
Selection Popover: When text is selected within the content, a small popover menu will appear near the selection. This menu will provide actions:
Visual Feedback for Highlights/Importance:
<span> with appropriate styling. This provides immediate visual feedback.data.content, these DOM-based highlights might be lost unless the content itself is managed as rich HTML. For this iteration, we'll focus on the immediate visual effect.Annotations:
PostDisplayComponent will manage states for the popover, selected range, and the list of annotations.AIChatSheet and the API route /api/chat will function as before, triggered by the "Ask AI" action.Let's implement these enhancements.
Key Enhancements and How They Work:
PostDisplayComponent Updates:
selectedDOMRange, showActionPopover, popoverPosition, annotations, showAnnotationDialog, etc.handleTextSelection: Detects text selection within contentRef. If a selection exists, it stores the Range object and displays a small ActionPopover near the selected text.Action Popover: This inline popover (a div styled to look like one) contains buttons for:
Highlighter icon): Calls applyStyleToSelection('bg-yellow-300 ...').Star icon): Calls applyStyleToSelection('bg-pink-300 ...').MessageSquarePlus icon): Opens a Dialog to input an annotation note. The selected text and note are stored in the annotations state.MessageCircleQuestion icon): Calls the onAskAI prop (passed from HomePage) with the selected text, which then opens the AIChatSheet.applyStyleToSelection: This function attempts to wrap the selected DOM range with a <span> and a CSS class for visual styling. This is a direct DOM manipulation.
data.content prop itself changes and causes a re-render of the content div from the original string, these DOM-based highlights will be lost. For persistent highlights that survive re-renders, the content would need to be managed as rich HTML, and the highlighting logic would need to update this HTML string state, which is significantly more complex (akin to building a mini rich-text editor).Card below the main content, showing the annotated text and the note.dangerouslySetInnerHTML: Used for rendering data.content. This is necessary to allow the DOM manipulations (wrapping selections in <span>) to persist visually until the next full content re-render. If data.content is always plain text, this is less of a security concern, but if it can contain user-supplied HTML, ensure it's sanitized.AnnotationDialog: A simple shadcn/ui Dialog for users to type their notes for the selected text.lib/types.ts: Added Annotation interface.app/page.tsx: Updated to pass the onAskAI handler to PostDisplayComponent.User Experience Flow:
This solution provides a much richer interaction model, allowing users to actively engage with the content. The direct DOM manipulation for highlights offers immediate visual feedback, while annotations are stored more robustly in React state.
You're right, my apologies! The method canSurroundContents is not a standard part of the Range API. That was an oversight. The surroundContents method itself will throw an error if the operation is not possible (e.g., if the range spans across elements in a way that a single <span> cannot legally wrap them).
We should remove the canSurroundContents check and rely on a try...catch block around surroundContents.
Here's the revised components/post-display.tsx with the fix:
Key changes in applyStyleToSelection:
if (selectedDOMRange.canSurroundContents(...)) check.selectedDOMRange.surroundContents(span) call is now directly within the try block.surroundContents fails (e.g., due to a complex selection that cannot be wrapped by a single span), the catch block will log an error and a warning. The highlighting will not be applied in such cases to prevent breaking the page.useCallback to clearSelection and handleTextSelection for minor optimization and to ensure stable references for useEffect dependencies.useEffect for handleClickOutside to be more specific about when to clearSelection, and added an ID to the popover div for more reliable checking.window.getSelection() is called again inside applyStyleToSelection if needed to clear the browser's visual selection after the DOM modification.This revision directly addresses the canSurroundContents is not a function error by removing the non-standard method call and relying on the standard behavior and error handling of surroundContents. Highlighting should now work for simple text selections, and for more complex ones where surroundContents would fail, it will gracefully avoid applying the style and log a message.