From 5f1b96ccafb9a7a48ef0ff569557dd17f722a38e Mon Sep 17 00:00:00 2001
From: Chaim
Date: Mon, 8 Jun 2026 04:56:01 +0000
Subject: [PATCH] =?UTF-8?q?feat(graph):=20navigation=20&=20UX=20=E2=80=94?=
=?UTF-8?q?=20deep-link,=20depth,=20PNG,=20rich=20panel=20(PR=20D)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Final corpus-graph PR. Connects the graph to the chair's workflow and rounds
out the Obsidian-grade interactions.
Backend (web/graph_api.py): neighborhood depth cap 2 → 3 (still bounded by
NODE_CAP_MAX).
Frontend:
- URL deep-link: /graph?focus=cl: is read on mount and written on focus
change (router.replace, scroll:false). GraphView wrapped in per
Next 16's useSearchParams requirement.
- "הצג בגרף" button on the precedent detail page → /graph?focus=cl:.
- Depth slider (1–3) in the focused overlay → useNodeNeighborhood(id, depth).
- Export PNG: grabs the rendered
-
+
+ טוען גרף…
+
+ }
+ >
+
+
);
diff --git a/web-ui/src/app/precedents/[id]/page.tsx b/web-ui/src/app/precedents/[id]/page.tsx
index 55f1b51..a5110fb 100644
--- a/web-ui/src/app/precedents/[id]/page.tsx
+++ b/web-ui/src/app/precedents/[id]/page.tsx
@@ -2,7 +2,7 @@
import { use, useState } from "react";
import Link from "next/link";
-import { Pencil, Check, X } from "lucide-react";
+import { Pencil, Check, X, Share2 } from "lucide-react";
import { toast } from "sonner";
import { AppShell } from "@/components/app-shell";
import { Card, CardContent } from "@/components/ui/card";
@@ -88,9 +88,16 @@ export default function PrecedentDetailPage({
{data.case_number}
-
+
+
+
+
{/* Citation per Israeli unified citation rules. The LLM
diff --git a/web-ui/src/components/graph/graph-node-panel.tsx b/web-ui/src/components/graph/graph-node-panel.tsx
index 9aa786b..4efe982 100644
--- a/web-ui/src/components/graph/graph-node-panel.tsx
+++ b/web-ui/src/components/graph/graph-node-panel.tsx
@@ -12,7 +12,9 @@ import { ExternalLink, X } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
+import { Skeleton } from "@/components/ui/skeleton";
import type { GraphNode } from "@/lib/api/graph";
+import { usePrecedent } from "@/lib/api/precedent-library";
const TYPE_LABELS: Record = {
precedent: "פסיקה",
@@ -54,6 +56,9 @@ export function GraphNodePanel({
const isPrecedentLike = node.type === "precedent" || node.type === "halacha";
const isGap = node.type === "gap";
const isDigest = node.type === "digest";
+ // Rich detail (summary/headnote) for precedents — reuses the library hook.
+ const detailId = node.type === "precedent" ? node.case_law_id : null;
+ const detail = usePrecedent(detailId);
return (
@@ -119,6 +124,25 @@ export function GraphNodePanel({
)}
+ {detailId && (
+