UI overhaul: fonts, colors, scrollable message boxes, animated text generation status updates
This commit is contained in:
@@ -100,7 +100,7 @@ export default function LayoutDefault({
|
||||
<TRPCProvider trpcClient={trpc} queryClient={queryClient}>
|
||||
<MantineProvider theme={theme}>
|
||||
<AppShell
|
||||
header={{ height: 60 }}
|
||||
header={{ height: 80 }}
|
||||
navbar={{
|
||||
width: 300,
|
||||
breakpoint: "sm",
|
||||
@@ -109,7 +109,7 @@ export default function LayoutDefault({
|
||||
padding="lg"
|
||||
>
|
||||
<AppShell.Header>
|
||||
<Group h="100%" px="md">
|
||||
<Group px="md" wrap="nowrap">
|
||||
<Burger
|
||||
opened={opened}
|
||||
onClick={toggle}
|
||||
@@ -120,7 +120,17 @@ export default function LayoutDefault({
|
||||
{" "}
|
||||
<Image h={50} fit="contain" src={logoUrl} />{" "}
|
||||
</a>
|
||||
<Title>Token-Efficient Context Engineering</Title>
|
||||
<Title
|
||||
textWrap="balance"
|
||||
lineClamp={1}
|
||||
styles={{
|
||||
root: {
|
||||
lineHeight: theme?.lineHeights?.["6xl"],
|
||||
},
|
||||
}}
|
||||
>
|
||||
Token-Efficient Context Engineering
|
||||
</Title>
|
||||
</Group>
|
||||
</AppShell.Header>
|
||||
<AppShell.Navbar p="md">
|
||||
|
||||
@@ -110,6 +110,18 @@ const theme: MantineThemeOverride = createTheme({
|
||||
"3xl": "2.25rem",
|
||||
"4xl": "3rem",
|
||||
},
|
||||
lineHeights: {
|
||||
xs: "1.25rem",
|
||||
sm: "1.375rem",
|
||||
md: "1.5rem",
|
||||
lg: "1.75rem",
|
||||
xl: "2rem",
|
||||
"2xl": "2.25rem",
|
||||
"3xl": "2.625rem",
|
||||
"4xl": "3rem",
|
||||
"5xl": "3.75rem",
|
||||
"6xl": "4.5rem",
|
||||
},
|
||||
});
|
||||
|
||||
export default theme;
|
||||
|
||||
+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