Focus input on submission and fix scroll (#441)
This commit is contained in:
parent
23660c5ad1
commit
2705d83d6c
5 changed files with 61 additions and 8 deletions
|
|
@ -40,15 +40,16 @@ export function Chat({
|
||||||
>
|
>
|
||||||
{messages.length === 0 && <Overview />}
|
{messages.length === 0 && <Overview />}
|
||||||
|
|
||||||
{messages.map((message, index) => (
|
{messages.map((message) => (
|
||||||
<PreviewMessage
|
<PreviewMessage
|
||||||
key={`${id}-${index}`}
|
key={message.id}
|
||||||
role={message.role}
|
role={message.role}
|
||||||
content={message.content}
|
content={message.content}
|
||||||
attachments={message.experimental_attachments}
|
attachments={message.experimental_attachments}
|
||||||
toolInvocations={message.toolInvocations}
|
toolInvocations={message.toolInvocations}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
ref={messagesEndRef}
|
ref={messagesEndRef}
|
||||||
className="shrink-0 min-w-[24px] min-h-[24px]"
|
className="shrink-0 min-w-[24px] min-h-[24px]"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import { toast } from "sonner";
|
||||||
|
|
||||||
import { ArrowUpIcon, PaperclipIcon, StopIcon } from "./icons";
|
import { ArrowUpIcon, PaperclipIcon, StopIcon } from "./icons";
|
||||||
import { PreviewAttachment } from "./preview-attachment";
|
import { PreviewAttachment } from "./preview-attachment";
|
||||||
|
import useWindowSize from "./use-window-size";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { Textarea } from "../ui/textarea";
|
import { Textarea } from "../ui/textarea";
|
||||||
|
|
||||||
|
|
@ -22,7 +23,7 @@ const suggestedActions = [
|
||||||
{
|
{
|
||||||
title: "What is the weather",
|
title: "What is the weather",
|
||||||
label: "in San Francisco?",
|
label: "in San Francisco?",
|
||||||
action: "what is the weather in San Francisco?",
|
action: "What is the weather in San Francisco?",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Answer like I'm 5,",
|
title: "Answer like I'm 5,",
|
||||||
|
|
@ -61,6 +62,7 @@ export function MultimodalInput({
|
||||||
) => void;
|
) => void;
|
||||||
}) {
|
}) {
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
const { width } = useWindowSize();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (textareaRef.current) {
|
if (textareaRef.current) {
|
||||||
|
|
@ -89,7 +91,11 @@ export function MultimodalInput({
|
||||||
});
|
});
|
||||||
|
|
||||||
setAttachments([]);
|
setAttachments([]);
|
||||||
}, [attachments, handleSubmit, setAttachments]);
|
|
||||||
|
if (width && width > 768) {
|
||||||
|
textareaRef.current?.focus();
|
||||||
|
}
|
||||||
|
}, [attachments, handleSubmit, setAttachments, width]);
|
||||||
|
|
||||||
const uploadFile = async (file: File) => {
|
const uploadFile = async (file: File) => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
@ -242,7 +248,8 @@ export function MultimodalInput({
|
||||||
<Button
|
<Button
|
||||||
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5"
|
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
handleSubmit(event);
|
event.preventDefault();
|
||||||
|
submitForm();
|
||||||
}}
|
}}
|
||||||
disabled={input.length === 0 || uploadQueue.length > 0}
|
disabled={input.length === 0 || uploadQueue.length > 0}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ export function useScrollToBottom<T extends HTMLElement>(): [
|
||||||
observer.observe(container, {
|
observer.observe(container, {
|
||||||
childList: true,
|
childList: true,
|
||||||
subtree: true,
|
subtree: true,
|
||||||
|
attributes: true,
|
||||||
|
characterData: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => observer.disconnect();
|
return () => observer.disconnect();
|
||||||
|
|
|
||||||
39
components/custom/use-window-size.tsx
Normal file
39
components/custom/use-window-size.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
interface WindowSize {
|
||||||
|
width: number | undefined;
|
||||||
|
height: number | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useWindowSize(): WindowSize {
|
||||||
|
const [windowSize, setWindowSize] = useState<WindowSize>({
|
||||||
|
width: undefined,
|
||||||
|
height: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Handler to call on window resize
|
||||||
|
function handleResize() {
|
||||||
|
// Set window width/height to state
|
||||||
|
setWindowSize({
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listener
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
|
||||||
|
// Call handler right away so state gets updated with initial window size
|
||||||
|
handleResize();
|
||||||
|
|
||||||
|
// Remove event listener on cleanup
|
||||||
|
return () => window.removeEventListener("resize", handleResize);
|
||||||
|
}, []); // Empty array ensures that effect is only run on mount and unmount
|
||||||
|
|
||||||
|
return windowSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useWindowSize;
|
||||||
|
|
@ -197,6 +197,10 @@ const SAMPLE = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function n(num: number): number {
|
||||||
|
return Math.ceil(num);
|
||||||
|
}
|
||||||
|
|
||||||
export function Weather({
|
export function Weather({
|
||||||
weatherAtLocation = SAMPLE,
|
weatherAtLocation = SAMPLE,
|
||||||
}: {
|
}: {
|
||||||
|
|
@ -270,12 +274,12 @@ export function Weather({
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div className="text-4xl font-medium text-blue-50">
|
<div className="text-4xl font-medium text-blue-50">
|
||||||
{weatherAtLocation.current.temperature_2m}
|
{n(weatherAtLocation.current.temperature_2m)}
|
||||||
{weatherAtLocation.current_units.temperature_2m}
|
{weatherAtLocation.current_units.temperature_2m}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-blue-50">{`H:${currentHigh}° L:${currentLow}°`}</div>
|
<div className="text-blue-50">{`H:${n(currentHigh)}° L:${n(currentLow)}°`}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between">
|
||||||
|
|
@ -296,7 +300,7 @@ export function Weather({
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div className="text-blue-50 text-sm">
|
<div className="text-blue-50 text-sm">
|
||||||
{displayTemperatures[index]}
|
{n(displayTemperatures[index])}
|
||||||
{weatherAtLocation.hourly_units.temperature_2m}
|
{weatherAtLocation.hourly_units.temperature_2m}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue