UI overhaul: fonts, colors, scrollable message boxes, animated text generation status updates

master
Avraham Sakal 4 weeks ago
parent ebfbb22525
commit 6668361f05

@ -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;

@ -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>
);
}
);

Loading…
Cancel
Save