loading indicator, growing message box
This commit is contained in:
@@ -272,6 +272,14 @@ export default function App() {
|
|||||||
const searchRunCounterRef = useRef(0);
|
const searchRunCounterRef = useRef(0);
|
||||||
const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
|
const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof document === "undefined") return;
|
||||||
|
const textarea = document.getElementById("composer-input") as HTMLTextAreaElement | null;
|
||||||
|
if (!textarea) return;
|
||||||
|
textarea.style.height = "0px";
|
||||||
|
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||||
|
}, [composer]);
|
||||||
|
|
||||||
const sidebarItems = useMemo(() => buildSidebarItems(chats, searches), [chats, searches]);
|
const sidebarItems = useMemo(() => buildSidebarItems(chats, searches), [chats, searches]);
|
||||||
|
|
||||||
const resetWorkspaceState = () => {
|
const resetWorkspaceState = () => {
|
||||||
@@ -916,9 +924,15 @@ export default function App() {
|
|||||||
<footer className="border-t p-3 md:p-4">
|
<footer className="border-t p-3 md:p-4">
|
||||||
<div className="mx-auto max-w-3xl rounded-xl border bg-background p-2 shadow-sm">
|
<div className="mx-auto max-w-3xl rounded-xl border bg-background p-2 shadow-sm">
|
||||||
<Textarea
|
<Textarea
|
||||||
rows={3}
|
id="composer-input"
|
||||||
|
rows={1}
|
||||||
value={composer}
|
value={composer}
|
||||||
onInput={(event) => setComposer(event.currentTarget.value)}
|
onInput={(event) => {
|
||||||
|
const textarea = event.currentTarget;
|
||||||
|
textarea.style.height = "0px";
|
||||||
|
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||||
|
setComposer(textarea.value);
|
||||||
|
}}
|
||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => {
|
||||||
if (event.key === "Enter" && !event.shiftKey) {
|
if (event.key === "Enter" && !event.shiftKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -926,11 +940,11 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
placeholder={isSearchMode ? "Search the web" : "Message Sybil"}
|
placeholder={isSearchMode ? "Search the web" : "Message Sybil"}
|
||||||
className="resize-none border-0 shadow-none focus-visible:ring-0"
|
className="max-h-40 min-h-0 resize-none overflow-y-auto border-0 shadow-none focus-visible:ring-0"
|
||||||
disabled={isSending}
|
disabled={isSending}
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center justify-between px-2 pb-1">
|
<div className={cn("flex items-center px-2 pb-1", error ? "justify-between" : "justify-end")}>
|
||||||
{error ? <p className="text-xs text-red-600">{error}</p> : <span className="text-xs text-muted-foreground">{isSearchMode ? "Enter to search" : "Enter to send"}</span>}
|
{error ? <p className="text-xs text-red-600">{error}</p> : null}
|
||||||
<Button onClick={() => void handleSend()} size="icon" disabled={isSending || !composer.trim()}>
|
<Button onClick={() => void handleSend()} size="icon" disabled={isSending || !composer.trim()}>
|
||||||
{isSearchMode ? <Search className="h-4 w-4" /> : <SendHorizontal className="h-4 w-4" />}
|
{isSearchMode ? <Search className="h-4 w-4" /> : <SendHorizontal className="h-4 w-4" />}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function ChatMessagesPanel({ messages, isLoading, isSending }: Props) {
|
export function ChatMessagesPanel({ messages, isLoading, isSending }: Props) {
|
||||||
|
const hasPendingAssistant = messages.some((message) => message.id.startsWith("temp-assistant-"));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLoading && messages.length === 0 ? <p className="text-sm text-muted-foreground">Loading messages...</p> : null}
|
{isLoading && messages.length === 0 ? <p className="text-sm text-muted-foreground">Loading messages...</p> : null}
|
||||||
@@ -26,9 +28,9 @@ export function ChatMessagesPanel({ messages, isLoading, isSending }: Props) {
|
|||||||
>
|
>
|
||||||
{isPendingAssistant ? (
|
{isPendingAssistant ? (
|
||||||
<span className="inline-flex items-center gap-1" aria-label="Assistant is typing" role="status">
|
<span className="inline-flex items-center gap-1" aria-label="Assistant is typing" role="status">
|
||||||
<span className="inline-block h-1.5 w-1.5 animate-bounce rounded-full bg-white [animation-delay:0ms]" />
|
<span className="inline-block h-1.5 w-1.5 animate-bounce rounded-full bg-muted-foreground [animation-delay:0ms]" />
|
||||||
<span className="inline-block h-1.5 w-1.5 animate-bounce rounded-full bg-white [animation-delay:140ms]" />
|
<span className="inline-block h-1.5 w-1.5 animate-bounce rounded-full bg-muted-foreground [animation-delay:140ms]" />
|
||||||
<span className="inline-block h-1.5 w-1.5 animate-bounce rounded-full bg-white [animation-delay:280ms]" />
|
<span className="inline-block h-1.5 w-1.5 animate-bounce rounded-full bg-muted-foreground [animation-delay:280ms]" />
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<MarkdownContent
|
<MarkdownContent
|
||||||
@@ -40,6 +42,17 @@ export function ChatMessagesPanel({ messages, isLoading, isSending }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
{isSending && !hasPendingAssistant ? (
|
||||||
|
<div className="flex justify-start">
|
||||||
|
<div className="max-w-[85%] text-base leading-7 text-fuchsia-100">
|
||||||
|
<span className="inline-flex items-center gap-1" aria-label="Assistant is typing" role="status">
|
||||||
|
<span className="inline-block h-1.5 w-1.5 animate-bounce rounded-full bg-muted-foreground [animation-delay:0ms]" />
|
||||||
|
<span className="inline-block h-1.5 w-1.5 animate-bounce rounded-full bg-muted-foreground [animation-delay:140ms]" />
|
||||||
|
<span className="inline-block h-1.5 w-1.5 animate-bounce rounded-full bg-muted-foreground [animation-delay:280ms]" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user