feat(sidebar): add grid loader indicator for active sessions (#158)

Replace the subtle pulse animation with a visible 3x3 grid loader
that appears before the session name when a session is actively
processing. This provides clearer visual feedback of session activity.

- Add new GridLoader component (pure CSS, no dependencies)
- Show loader in sidebar when session phase is 'busy' or 'cooldown'
This commit is contained in:
Nils
2026-01-16 18:48:57 +02:00
committed by GitHub
parent 93d7dec66b
commit 288f0ff29f
3 changed files with 55 additions and 6 deletions
@@ -27,6 +27,7 @@ import {
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
import { Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip';
import { GridLoader } from '@/components/ui/grid-loader';
import {
RiAddLine,
RiArrowDownSLine,
@@ -1117,12 +1118,10 @@ export const SessionSidebar: React.FC<SessionSidebarProps> = ({
>
{}
<div className="flex items-center gap-2 min-w-0 flex-1">
<span
className={cn(
'truncate typography-ui-label font-normal text-foreground',
isStreaming && 'animate-pulse [animation-duration:1.8s]'
)}
>
{isStreaming ? (
<GridLoader size="xs" className="text-primary flex-shrink-0" />
) : null}
<span className="truncate typography-ui-label font-normal text-foreground">
{sessionTitle}
</span>
@@ -0,0 +1,35 @@
import * as React from 'react';
import { cn } from '@/lib/utils';
interface GridLoaderProps {
className?: string;
size?: 'xs' | 'sm' | 'md' | 'lg';
}
const sizeConfig = {
xs: { container: 'gap-[1px]', dot: 'h-[3px] w-[3px]' },
sm: { container: 'gap-0.5', dot: 'h-1 w-1' },
md: { container: 'gap-1', dot: 'h-1.5 w-1.5' },
lg: { container: 'gap-1.5', dot: 'h-2 w-2' },
};
const GridLoader: React.FC<GridLoaderProps> = ({ className, size = 'md' }) => {
const config = sizeConfig[size];
return (
<div
className={cn('grid grid-cols-3', config.container, className)}
aria-label="Loading"
>
{Array.from({ length: 9 }, (_, i) => (
<div
key={i}
className={cn('rounded-full bg-current animate-grid-pulse', config.dot)}
style={{ animationDelay: `${((i % 3) + Math.floor(i / 3)) * 150}ms` }}
/>
))}
</div>
);
};
export { GridLoader };
+15
View File
@@ -1546,3 +1546,18 @@ html:not(.dark) .chat-scroll {
.fonts-loaded .terminal-viewport-container {
font-family: "JetBrainsMono Nerd Font", "FiraCode Nerd Font", "Fira Code", "JetBrains Mono", "SFMono-Regular", Menlo, Consolas, "Liberation Mono", "Courier New", monospace;
}
@keyframes grid-pulse {
0%, 100% {
opacity: 0.2;
transform: scale(0.8);
}
50% {
opacity: 1;
transform: scale(1);
}
}
.animate-grid-pulse {
animation: grid-pulse 1.2s ease-in-out infinite;
}