UI overhaul: fonts, colors, scrollable message boxes, animated text generation status updates
This commit is contained in:
+79
-13
@@ -5,12 +5,16 @@ import {
|
||||
HoverCard,
|
||||
JsonInput,
|
||||
List,
|
||||
ScrollArea,
|
||||
Stack,
|
||||
Tabs,
|
||||
Text,
|
||||
Textarea,
|
||||
TextInput,
|
||||
Transition,
|
||||
useMantineTheme,
|
||||
} from "@mantine/core";
|
||||
import { useEffect, useState } from "react";
|
||||
import { memo, useEffect, useState } from "react";
|
||||
import {
|
||||
defaultParameters,
|
||||
defaultSystemPrompt,
|
||||
@@ -23,6 +27,7 @@ import type {
|
||||
CommittedMessage,
|
||||
DraftMessage,
|
||||
OtherParameters,
|
||||
SendMessageStatus,
|
||||
} from "../../../types";
|
||||
import Markdown from "react-markdown";
|
||||
import {
|
||||
@@ -351,6 +356,8 @@ export default function ChatPage() {
|
||||
const setSendMessageStatus = useStore((state) => state.setSendMessageStatus);
|
||||
const setIsSendingMessage = useStore((state) => state.setIsSendingMessage);
|
||||
|
||||
const theme = useMantineTheme();
|
||||
|
||||
// Function to send message using subscription
|
||||
const sendSubscriptionMessage = async ({
|
||||
conversationId,
|
||||
@@ -489,11 +496,11 @@ export default function ChatPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<span>Conversation #{conversationId} - </span>
|
||||
<input
|
||||
type="text"
|
||||
<Box>
|
||||
<Group justify="flex-start" gap={"sm"}>
|
||||
<TextInput
|
||||
inputSize="50"
|
||||
description={`Conversation #${conversationId}`}
|
||||
defaultValue={conversationTitle || ""}
|
||||
// onChange={(e) => {
|
||||
// setConversationTitle(e.target.value);
|
||||
@@ -504,10 +511,27 @@ export default function ChatPage() {
|
||||
title: e.target.value,
|
||||
});
|
||||
}}
|
||||
variant="unstyled"
|
||||
styles={{
|
||||
input: {
|
||||
// backgroundColor: "transparent",
|
||||
// border: "none",
|
||||
// padding: 0,
|
||||
// margin: 0,
|
||||
fontFamily: theme.headings.fontFamily,
|
||||
fontSize: theme.fontSizes.lg,
|
||||
lineHeight: theme.lineHeights["4xl"],
|
||||
},
|
||||
wrapper: {
|
||||
marginTop: 0,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{isSendingMessage && <IconLoaderQuarter size={16} stroke={1.5} />}
|
||||
{sendMessageStatus && <span>{sendMessageStatus.message}</span>}
|
||||
</div>
|
||||
{sendMessageStatus && (
|
||||
<StatusMessage sendMessageStatus={sendMessageStatus} />
|
||||
)}
|
||||
</Group>
|
||||
<Tabs defaultValue="message">
|
||||
<Tabs.List>
|
||||
<Tabs.Tab value="message">Message</Tabs.Tab>
|
||||
@@ -690,7 +714,7 @@ export default function ChatPage() {
|
||||
</List>
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
||||
</>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -792,15 +816,16 @@ function Messages() {
|
||||
position={message.role === "user" ? "left" : "right"}
|
||||
>
|
||||
<HoverCard.Target>
|
||||
<Box
|
||||
<ScrollArea
|
||||
scrollbars="x"
|
||||
w="75%"
|
||||
p="md"
|
||||
bdrs="md"
|
||||
bg={
|
||||
message.role === "user"
|
||||
? theme.colors.gray[2]
|
||||
: theme.colors.blue[2]
|
||||
}
|
||||
p="md"
|
||||
bdrs="md"
|
||||
>
|
||||
<Markdown>
|
||||
{message.parts
|
||||
@@ -808,7 +833,7 @@ function Messages() {
|
||||
.map((p) => p.text)
|
||||
.join("\n")}
|
||||
</Markdown>
|
||||
</Box>
|
||||
</ScrollArea>
|
||||
</HoverCard.Target>
|
||||
<HoverCard.Dropdown>
|
||||
<ActionIcon.Group>
|
||||
@@ -840,3 +865,44 @@ function Messages() {
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
const StatusMessage = memo(
|
||||
({ sendMessageStatus }: { sendMessageStatus: SendMessageStatus | null }) => {
|
||||
const [displayMessage, setDisplayMessage] = useState(sendMessageStatus);
|
||||
const [isVisible, setIsVisible] = useState(sendMessageStatus !== null);
|
||||
|
||||
useEffect(() => {
|
||||
if (sendMessageStatus === null) {
|
||||
setIsVisible(false);
|
||||
setTimeout(() => setDisplayMessage(null), 250);
|
||||
} else if (displayMessage === null) {
|
||||
setDisplayMessage(sendMessageStatus);
|
||||
setIsVisible(true);
|
||||
} else if (displayMessage.message !== sendMessageStatus.message) {
|
||||
setIsVisible(false);
|
||||
setTimeout(() => {
|
||||
setDisplayMessage(sendMessageStatus);
|
||||
setIsVisible(true);
|
||||
}, 250);
|
||||
}
|
||||
}, [sendMessageStatus, displayMessage]);
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
{/* This is a hack to make this component take up the space it would take up once the transition is complete. Useful for when this component is in a flexbox with a particular alignment/justification, which we want to be calculated against its eventual size. */}
|
||||
<span style={{ visibility: "hidden" }}>{displayMessage?.message}</span>
|
||||
<Transition
|
||||
transition="pop"
|
||||
duration={500}
|
||||
mounted={isVisible && displayMessage !== null}
|
||||
>
|
||||
{(styles) => (
|
||||
<span style={{ ...styles, position: "absolute", top: 0, left: 0 }}>
|
||||
{displayMessage?.message}
|
||||
</span>
|
||||
)}
|
||||
</Transition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user