diff --git a/surfsense_web/components/layout/ui/right-panel/RightPanel.tsx b/surfsense_web/components/layout/ui/right-panel/RightPanel.tsx index 98f14b247..aea9e2836 100644 --- a/surfsense_web/components/layout/ui/right-panel/RightPanel.tsx +++ b/surfsense_web/components/layout/ui/right-panel/RightPanel.tsx @@ -2,6 +2,7 @@ import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { PanelRight, PanelRightClose } from "lucide-react"; +import { AnimatePresence, motion } from "motion/react"; import { useEffect } from "react"; import { closeReportPanelAtom, reportPanelAtom } from "@/atoms/chat/report-panel.atom"; import { documentsSidebarOpenAtom } from "@/atoms/documents/ui.atoms"; @@ -66,6 +67,8 @@ export function RightPanelExpandButton() { ); } +const PANEL_WIDTHS = { sources: 420, report: 640 } as const; + export function RightPanel({ documentsPanel }: RightPanelProps) { const [activeTab] = useAtom(rightPanelTabAtom); const reportState = useAtomValue(reportPanelAtom); @@ -75,21 +78,16 @@ export function RightPanel({ documentsPanel }: RightPanelProps) { const documentsOpen = documentsPanel?.open ?? false; const reportOpen = reportState.isOpen && !!reportState.reportId; - // Close report on Escape key (works on Windows, macOS, and Linux) - // Must be called before early returns to satisfy Rules of Hooks. useEffect(() => { if (!reportOpen) return; const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === "Escape") { - closeReport(); - } + if (e.key === "Escape") closeReport(); }; document.addEventListener("keydown", handleKeyDown); return () => document.removeEventListener("keydown", handleKeyDown); }, [reportOpen, closeReport]); - if (!documentsOpen && !reportOpen) return null; - if (collapsed) return null; + const isVisible = (documentsOpen || reportOpen) && !collapsed; const effectiveTab = activeTab === "report" && !reportOpen @@ -98,32 +96,72 @@ export function RightPanel({ documentsPanel }: RightPanelProps) { ? "report" : activeTab; + const targetWidth = PANEL_WIDTHS[effectiveTab]; const collapseButton = setCollapsed(true)} />; - const panelWidth = effectiveTab === "sources" ? "w-[420px]" : "w-[640px]"; + const contentKey = + effectiveTab === "sources" && documentsOpen + ? "sources" + : effectiveTab === "report" && reportOpen + ? "report" + : null; return ( - + + )} + ); } diff --git a/surfsense_web/components/report-panel/report-panel.tsx b/surfsense_web/components/report-panel/report-panel.tsx index 46dfecde3..dd7b76548 100644 --- a/surfsense_web/components/report-panel/report-panel.tsx +++ b/surfsense_web/components/report-panel/report-panel.tsx @@ -294,32 +294,11 @@ export function ReportPanelContent({ } }, [activeReportId, currentMarkdown]); - // Show full-page skeleton only on initial load (no data loaded yet). - // Once we have versions/content from a prior fetch, keep the action bar visible. - const hasLoadedBefore = versions.length > 0 || reportContent !== null; - - if (isLoading && !hasLoadedBefore) { - return ( - <> - {/* Minimal top bar with close button even during initial load */} -
- {onClose && ( - - )} -
- - - ); - } - const activeVersionIndex = versions.findIndex((v) => v.id === activeReportId); return ( <> - {/* Action bar — always visible after initial load */} + {/* Action bar — always visible; buttons are disabled while loading */}
{/* Copy button */}