refactor: streamline streaming view logic in ThinkingBlock

Previously the component used an `isStreamingEmpty` flag to display a “thinking” placeholder when the block was loading but had no steps yet. The new implementation handles this case directly in the streaming block by checking `activeStep || N === 0`, removing the unused flag and simplifying the conditional rendering.
In addition, the click and button‑disable logic were clarified, and extraneous comments were removed for cleaner code. These changes improve readability and maintainability without altering external behavior.
This commit is contained in:
Akarshan 2025-10-29 23:20:12 +05:30
parent 0f7994e03b
commit 2a3de27cc9
No known key found for this signature in database
GPG Key ID: D75C9634A870665F

View File

@ -83,7 +83,7 @@ const ThinkingBlock = ({
const handleImageClick = (url: string, alt: string) => const handleImageClick = (url: string, alt: string) =>
setModalImage({ url, alt }) setModalImage({ url, alt })
// Actual loading state comes from prop, determined by whether final text started streaming (Req 2) // Actual loading state comes from prop, determined by whether final text started streaming
const loading = propLoading const loading = propLoading
// Set default expansion state: collapsed if done (not loading). // Set default expansion state: collapsed if done (not loading).
@ -98,15 +98,11 @@ const ThinkingBlock = ({
const N = stepsWithoutDone.length const N = stepsWithoutDone.length
// Determine the step to display in the condensed streaming view // Determine the step to display in the condensed streaming view
// When loading, we show the last available step (N-1), which is currently accumulating content.
const activeStep = useMemo(() => { const activeStep = useMemo(() => {
if (!loading || N === 0) return null if (!loading || N === 0) return null
return stepsWithoutDone[N - 1] return stepsWithoutDone[N - 1]
}, [loading, N, stepsWithoutDone]) }, [loading, N, stepsWithoutDone])
// Determine if the block is truly empty (streaming started but no content/steps yet)
const isStreamingEmpty = loading && N === 0
// If not loading, and there are no steps, hide the block entirely. // If not loading, and there are no steps, hide the block entirely.
const hasContent = steps.length > 0 const hasContent = steps.length > 0
if (!loading && !hasContent) return null if (!loading && !hasContent) return null
@ -277,7 +273,6 @@ const ThinkingBlock = ({
return ( return (
<div <div
className="mx-auto w-full break-words" className="mx-auto w-full break-words"
// Only set onClick handler if not loading AND we have content to expand
onClick={loading || !hasContent ? undefined : handleClick} onClick={loading || !hasContent ? undefined : handleClick}
> >
<div className="mb-4 rounded-lg bg-main-view-fg/4 p-2 transition-all duration-200"> <div className="mb-4 rounded-lg bg-main-view-fg/4 p-2 transition-all duration-200">
@ -287,12 +282,11 @@ const ThinkingBlock = ({
)} )}
<button <button
className="flex items-center gap-2 focus:outline-none" className="flex items-center gap-2 focus:outline-none"
// Button is disabled/non-expandable if loading OR if there's no content to show
disabled={loading || !hasContent} disabled={loading || !hasContent}
> >
{/* Display chevron only if not loading AND steps exist to expand */} {/* Display chevron only if not loading AND steps exist to expand */}
{!loading && {!loading &&
hasContent && // Use hasContent instead of steps.length > 0 hasContent &&
(isExpanded ? ( (isExpanded ? (
<ChevronUp className="size-4 text-main-view-fg/60 transition-transform duration-200" /> <ChevronUp className="size-4 text-main-view-fg/60 transition-transform duration-200" />
) : ( ) : (
@ -304,16 +298,9 @@ const ThinkingBlock = ({
</button> </button>
</div> </div>
{isStreamingEmpty && (
<div className="mt-2 pl-2 pr-4 text-main-view-fg/80">
<span className="font-medium text-main-view-fg/80">
{t('chat:thinking')}
</span>
</div>
)}
{/* Streaming/Condensed View - shows active step (N-1) */} {/* Streaming/Condensed View - shows active step (N-1) */}
{loading && activeStep && ( {/* This block handles both the N>0 case and the N=0 fallback, ensuring stability. */}
{loading && (activeStep || N === 0) && (
<div <div
key={`streaming-${N - 1}`} key={`streaming-${N - 1}`}
className={cn( className={cn(
@ -323,17 +310,20 @@ const ThinkingBlock = ({
)} )}
> >
<div className="relative border-main-view-fg/20"> <div className="relative border-main-view-fg/20">
<div className="relative pl-5"> {/* If N=0, just show the fallback text in the header and this area remains minimal. */}
{/* Bullet point/Icon position relative to line */} {activeStep && (
<div <div className="relative pl-5">
className={cn( {/* Bullet point/Icon position relative to line */}
'absolute left-[-2px] top-1.5 size-2 rounded-full bg-main-view-fg/60', <div
activeStep.type !== 'done' && 'animate-pulse' // Pulse if active/streaming className={cn(
)} 'absolute left-[-2px] top-1.5 size-2 rounded-full bg-main-view-fg/60',
/> activeStep.type !== 'done' && 'animate-pulse' // Pulse if active/streaming
{/* Active step content */} )}
{renderStepContent(activeStep, N - 1, handleImageClick, t)} />
</div> {/* Active step content */}
{renderStepContent(activeStep, N - 1, handleImageClick, t)}
</div>
)}
</div> </div>
</div> </div>
)} )}