From 4c970c7f296d8dedb2ce2ea88131756e9f4e3d5e Mon Sep 17 00:00:00 2001 From: Zane Staggs Date: Sun, 13 Jul 2025 13:34:59 -0700 Subject: [PATCH] added loading skeleton to chat history --- .../components/sessions/SessionListView.tsx | 138 +++++++++++++----- 1 file changed, 100 insertions(+), 38 deletions(-) diff --git a/ui/desktop/src/components/sessions/SessionListView.tsx b/ui/desktop/src/components/sessions/SessionListView.tsx index 380a464b07..6a8112dec7 100644 --- a/ui/desktop/src/components/sessions/SessionListView.tsx +++ b/ui/desktop/src/components/sessions/SessionListView.tsx @@ -36,6 +36,7 @@ const SessionListView: React.FC = ({ onSelectSession }) => const [isLoading, setIsLoading] = useState(true); const [showSkeleton, setShowSkeleton] = useState(true); const [showContent, setShowContent] = useState(false); + const [isInitialLoad, setIsInitialLoad] = useState(true); const [error, setError] = useState(null); const [searchResults, setSearchResults] = useState<{ count: number; @@ -74,22 +75,27 @@ const SessionListView: React.FC = ({ onSelectSession }) => loadSessions(); }, []); - // Minimum loading time to prevent skeleton flash + // Improved loading time logic to prevent flash on initial load useEffect(() => { if (!isLoading && showSkeleton) { + // Ultra-fast timing - halved values for maximum responsiveness + const delay = isInitialLoad ? 150 : 75; const timer = setTimeout(() => { setShowSkeleton(false); - // Add a small delay before showing content for fade-in effect + // Virtually instant content show setTimeout(() => { setShowContent(true); - }, 50); - }, 300); // Show skeleton for at least 300ms + if (isInitialLoad) { + setIsInitialLoad(false); + } + }, 10); + }, delay); // eslint-disable-next-line no-undef return () => clearTimeout(timer); } return () => void 0; - }, [isLoading, showSkeleton]); + }, [isLoading, showSkeleton, isInitialLoad]); // Update date groups when filtered sessions change useEffect(() => { @@ -220,41 +226,45 @@ const SessionListView: React.FC = ({ onSelectSession }) => ); }); - // Render skeleton loader for session items - const SessionSkeleton = () => ( - -
- - - - -
-
-
- - -
-
-
- ); + // Render skeleton loader for session items with variations + const SessionSkeleton = React.memo(({ variant = 0 }: { variant?: number }) => { + const titleWidths = ['w-3/4', 'w-2/3', 'w-4/5', 'w-1/2']; + const pathWidths = ['w-32', 'w-28', 'w-36', 'w-24']; + const tokenWidths = ['w-12', 'w-10', 'w-14', 'w-8']; - const renderContent = () => { - if (isLoading || showSkeleton) { - return ( -
-
- -
- - - - + return ( + +
+ +
+ + +
+
+ + +
+
+ +
+
+
+ + +
+
+ +
- ); - } +
+ ); + }); + SessionSkeleton.displayName = 'SessionSkeleton'; + + const renderActualContent = () => { if (error) { return (
@@ -323,9 +333,10 @@ const SessionListView: React.FC = ({ onSelectSession }) =>
+ {/* Skeleton layer - always rendered but conditionally visible */}
= ({ onSelectSession }) => searchResults={searchResults} className="relative" > - {renderContent()} +
+ {/* Today section */} +
+ +
+ + + + + +
+
+ + {/* Yesterday section */} +
+ +
+ + + + + + +
+
+ + {/* Additional section */} +
+ +
+ + + +
+
+
+
+
+ + {/* Content layer - always rendered but conditionally visible */} +
+ + {renderActualContent()}