From bdcddeb65a8e96e0d6b2615ad723c9ecc5967022 Mon Sep 17 00:00:00 2001 From: Maggie Appleton <5599295+MaggieAppleton@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:24:22 +0100 Subject: [PATCH] Phase 5: graph + claims views Adds ArgumentGraph (ReactFlow), ClaimsView, and ClaimCard components. Extends EditorContext with structural commands (appendHighlight, updateHighlightText, removeHighlight, addHighlightAtSelection) so all three analysis tabs share a single Remirror source of truth. Co-Authored-By: Claude Sonnet 4.6 --- src/components/ArgumentGraph.tsx | 344 ++++++++++++++++++++++++++++ src/components/ClaimCard.tsx | 155 +++++++++++++ src/components/ClaimsView.tsx | 90 ++++++++ src/components/HighlightToolbar.tsx | 13 +- src/contexts/EditorContext.tsx | 89 ++++++- src/pages/AnalysisPage.tsx | 14 +- 6 files changed, 687 insertions(+), 18 deletions(-) create mode 100644 src/components/ArgumentGraph.tsx create mode 100644 src/components/ClaimCard.tsx create mode 100644 src/components/ClaimsView.tsx diff --git a/src/components/ArgumentGraph.tsx b/src/components/ArgumentGraph.tsx new file mode 100644 index 0000000..5a91719 --- /dev/null +++ b/src/components/ArgumentGraph.tsx @@ -0,0 +1,344 @@ +import { useCallback, useEffect, useMemo, useState } from "react"; +import ReactFlow, { + Background, + Controls, + Handle, + MiniMap, + Position, + applyEdgeChanges, + applyNodeChanges, + type Connection, + type Edge, + type EdgeChange, + type Node, + type NodeChange, + type NodeProps, + type XYPosition, +} from "reactflow"; +import "reactflow/dist/style.css"; +import { useEditorContext } from "../contexts/EditorContext"; +import { useSession } from "../contexts/SessionContext"; +import { LABEL_CONFIGS } from "../types/labels"; +import type { Highlight, Relationship } from "../types"; + +interface HighlightNodeData { + highlight: Highlight; + color: string; + onEditText: (id: string, newText: string) => void; + onDelete: (id: string) => void; +} + +function HighlightNode({ data }: NodeProps) { + const { highlight, color, onEditText, onDelete } = data; + const [isEditing, setIsEditing] = useState(false); + const [draft, setDraft] = useState(highlight.text); + + const commit = () => { + setIsEditing(false); + const next = draft.trim(); + if (next && next !== highlight.text) onEditText(highlight.id, next); + else setDraft(highlight.text); + }; + + return ( +
+ +
+ + {highlight.labelType} + +
+ + +
+
+ {isEditing ? ( +