import * as React from 'react';
import { ThumbsDown, ThumbsUp } from 'lucide-react';
import { cn } from '@/lib/utils';
import { ResponseDocument } from './ResponseBlocks';
import OwliverAvatar from '@/components/krow/OwliverAvatar';
/**
* The thinking state, shown between sending and the first block arriving.
*
* Labelled as well as animated: three moving dots mean nothing to a screen
* reader, and the visually-hidden text is what tells one that a reply is coming.
*/
export function ThinkingIndicator() {
return (
{[0, 1, 2].map((i) => (
))}
Owliver is preparing a response
);
}
/**
* One turn.
*
* The user's words sit in a filled bubble; the assistant's reply runs the full
* width of the panel. That asymmetry is deliberate — these replies are reports
* with tables and KPI tiles, and a chat bubble would waste a third of a 380px
* column on padding around them.
*/
/**
* How this conversation was rated.
*
* Offered on the latest answer only, because a rating belongs to the
* conversation rather than to a paragraph of it — thumbs on every turn would
* ask a reader to score an answer out of the exchange that produced it, and
* each one would set the same value anyway.
*
* Hidden until the turn is hovered or focused, the way History's delete control
* already is: a thread of reports should not carry two permanent buttons under
* every answer.
*/
function FeedbackControls({ feedback, onFeedback }) {
const rate = (rating) => onFeedback(feedback?.rating === rating ? null : rating);
return (
}
{/* Only where a handler was passed — a turn nobody is collecting feedback
for renders exactly as it did before this existed. */}
{onFeedback && !streaming && (
)}
);
});
Message.displayName = 'Message';
/** A subtle divider between turns, so a long thread stays readable. */
export function TurnDivider() {
return ;
}
export { cn };