diff --git a/src/browser/components/RightSidebar/CodeReview/UntrackedStatus.tsx b/src/browser/components/RightSidebar/CodeReview/UntrackedStatus.tsx index 9ddae6998..c6c516970 100644 --- a/src/browser/components/RightSidebar/CodeReview/UntrackedStatus.tsx +++ b/src/browser/components/RightSidebar/CodeReview/UntrackedStatus.tsx @@ -2,7 +2,8 @@ * UntrackedStatus - Shows untracked files count with interactive tooltip */ -import React, { useState, useEffect, useRef } from "react"; +import React, { useState, useEffect, useRef, useLayoutEffect } from "react"; +import { createPortal } from "react-dom"; import { cn } from "@/common/lib/utils"; interface UntrackedStatusProps { @@ -22,10 +23,40 @@ export const UntrackedStatus: React.FC = ({ const [isLoading, setIsLoading] = useState(false); const [showTooltip, setShowTooltip] = useState(false); const [isTracking, setIsTracking] = useState(false); + const [popupPosition, setPopupPosition] = useState<{ top: number; right: number } | null>(null); const containerRef = useRef(null); + const popupRef = useRef(null); const hasLoadedOnce = useRef(false); const loadingRef = useRef(false); // Prevent concurrent loads + // Calculate popup position when shown + useLayoutEffect(() => { + if (!showTooltip || !containerRef.current) { + setPopupPosition(null); + return; + } + + const updatePosition = () => { + const container = containerRef.current; + if (!container) return; + + const rect = container.getBoundingClientRect(); + setPopupPosition({ + top: rect.bottom + 8, // 8px gap below anchor + right: window.innerWidth - rect.right, + }); + }; + + updatePosition(); + + window.addEventListener("resize", updatePosition); + window.addEventListener("scroll", updatePosition, true); + return () => { + window.removeEventListener("resize", updatePosition); + window.removeEventListener("scroll", updatePosition, true); + }; + }, [showTooltip]); + // Load untracked files useEffect(() => { let cancelled = false; @@ -78,7 +109,10 @@ export const UntrackedStatus: React.FC = ({ if (!showTooltip) return; const handleClickOutside = (e: MouseEvent) => { - if (containerRef.current && !containerRef.current.contains(e.target as Node)) { + const target = e.target as Node; + const clickedContainer = containerRef.current?.contains(target); + const clickedPopup = popupRef.current?.contains(target); + if (!clickedContainer && !clickedPopup) { setShowTooltip(false); } }; @@ -121,7 +155,7 @@ export const UntrackedStatus: React.FC = ({ const hasUntracked = count > 0; return ( -
+
= ({ {isLoading ? "..." : `${count} Untracked`}
- {showTooltip && hasUntracked && ( -
-
- Untracked Files ({count}) -
-
- {untrackedFiles.map((file) => ( -
- {file} -
- ))} -
- -
- )} +
+ Untracked Files ({count}) +
+
+ {untrackedFiles.map((file) => ( +
+ {file} +
+ ))} +
+ +
, + document.body + )}
); };