From 5eb99e35c1500fb2277e22f1cd1c436c8b7ff6ab Mon Sep 17 00:00:00 2001 From: chihlasm Date: Tue, 24 Mar 2026 23:26:20 +0000 Subject: [PATCH] feat: branch hover card pops out in front with backdrop dim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On hover, the card: - Grows slightly wider and floats directly over the base card - Shows detail content (tried, result, reason, steps) - Dims everything behind it with a fixed black/30 scrim - Heavy drop shadow for depth (0 8px 32px rgba(0,0,0,0.5)) - Status-colored border maintained Active branch still shows detail inline (no hover needed). Cards below don't shift — the expanded version is position: absolute. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/components/session/BranchNode.tsx | 110 +++++++++++------- 1 file changed, 67 insertions(+), 43 deletions(-) diff --git a/frontend/src/components/session/BranchNode.tsx b/frontend/src/components/session/BranchNode.tsx index 5e5ee607..dd2aa093 100644 --- a/frontend/src/components/session/BranchNode.tsx +++ b/frontend/src/components/session/BranchNode.tsx @@ -1,4 +1,4 @@ -import { useState, useRef } from 'react' +import { useState } from 'react' import { CircleDot, CheckCircle2, XCircle, Circle, RotateCcw } from 'lucide-react' import { cn } from '@/lib/utils' import type { BranchResponse } from '@/types/branching' @@ -60,22 +60,20 @@ interface BranchNodeProps { export function BranchNode({ branch, depth, isActive, onClick }: BranchNodeProps) { const [isHovered, setIsHovered] = useState(false) - const cardRef = useRef(null) const config = STATUS_CONFIG[branch.status] const Icon = config.icon const hasDetail = branch.context_summary || branch.status_reason - const showPopover = isHovered && hasDetail && !isActive + const showExpanded = isHovered && hasDetail && !isActive return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > - {/* Card */} + {/* Base card — always visible */} - {/* Floating popover for HOVERED non-active branches */} - {showPopover && ( -
-
- - {branch.label} + {/* Expanded card — floats directly on top of the base card */} + {showExpanded && ( + <> + {/* Scrim behind to dim everything */} +
+ + {/* Expanded card positioned over the original */} +
+ +
+ +
- -
+ )}
) } -/** Shared detail content used by both inline (active) and popover (hover) */ +/** Card header row — shared between base and expanded states */ +function CardHeader({ + icon: Icon, + config, + branch, + isActive, +}: { + icon: React.ElementType + config: StatusConfig + branch: BranchResponse + isActive: boolean +}) { + return ( +
+ + + {branch.label} + + + {config.label} + +
+ ) +} + +/** Detail content — shared between inline (active) and expanded (hover) */ function BranchDetail({ branch }: { branch: BranchResponse }) { return ( <>