Skip to content

Commit 69990ab

Browse files
committed
[DASH-540] Nebula - Various UI improvements (#5777)
## Problem solved DASH-540 * on the chat page -> move the container 1 level down - so the chat can be scrolled from the corner of the page as well * reduce container max-width for the history page to 800px to match it with landing page * stop the auto scroll if user interacts with chat UI * custom 404 page for the nebula subdomain * remove the announcement banner from the 404 pages ( this affects entire dashboard) * fix empty title in chat history page * fix overflow in chat history page on mobile when there's a long text without a whitespace <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on enhancing the chat functionality and user experience in the `Nebula` application. It introduces auto-scrolling features, improves layout styling, and adds a new `404 Not Found` page. ### Detailed summary - Added auto-scrolling feature to `Chats` component. - Introduced `setEnableAutoScroll` function to manage scrolling behavior. - Enhanced styling in `ChatHistoryPage` and `SessionCard`. - Implemented a new `NebulaNotFound` component with a user-friendly 404 message. - Updated `ChatPageContent` to utilize the new auto-scroll functionality. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent d8b4e09 commit 69990ab

File tree

6 files changed

+252
-134
lines changed

6 files changed

+252
-134
lines changed

apps/dashboard/src/app/nebula-app/(app)/chat/history/ChatHistoryPage.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@ export function ChatHistoryPageUI(props: {
8181

8282
{filteredSessions.length > 0 && (
8383
<ScrollShadow
84-
className="container flex-1"
84+
className="container max-w-[800px] flex-1"
8585
scrollableClassName="max-h-full py-6"
8686
shadowColor="hsl(var(--background))"
8787
>
8888
{filteredSessions.length > 0 && (
89-
<div className="flex flex-col gap-4">
89+
<div className="flex flex-col gap-5">
9090
{filteredSessions.map((session) => (
9191
<SessionCard
9292
key={session.id + session.updated_at + session.created_at}
@@ -175,8 +175,10 @@ function SessionCard(props: {
175175
});
176176

177177
return (
178-
<div className="rounded-lg border bg-muted/50 p-4">
179-
<h3>{props.session.title}</h3>
178+
<div className="overflow-hidden rounded-lg border bg-muted/50 p-4">
179+
<h3 className="line-clamp-3 break-all">
180+
{props.session.title || "Untitled"}
181+
</h3>
180182
<div className="mt-4 flex items-center justify-between gap-6 border-t pt-3">
181183
<p className="text-muted-foreground text-sm">
182184
Updated{" "}

apps/dashboard/src/app/nebula-app/(app)/components/ChatPageContent.tsx

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
"use client";
2-
3-
/* eslint-disable no-restricted-syntax */
4-
import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
52
import { useThirdwebClient } from "@/constants/thirdweb.client";
63
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
74
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
@@ -111,18 +108,8 @@ export function ChatPageContent(props: {
111108
[props.type],
112109
);
113110

114-
const messagesEndRef = useRef<HTMLDivElement>(null);
115111
const [isChatStreaming, setIsChatStreaming] = useState(false);
116-
const [isUserSubmittedMessage, setIsUserSubmittedMessage] = useState(false);
117-
118-
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
119-
useEffect(() => {
120-
if (!isUserSubmittedMessage) {
121-
return;
122-
}
123-
124-
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
125-
}, [messages, isUserSubmittedMessage]);
112+
const [enableAutoScroll, setEnableAutoScroll] = useState(false);
126113

127114
const initSession = useCallback(async () => {
128115
const session = await createSession({
@@ -148,7 +135,7 @@ export function ChatPageContent(props: {
148135
]);
149136

150137
setIsChatStreaming(true);
151-
setIsUserSubmittedMessage(true);
138+
setEnableAutoScroll(true);
152139
const abortController = new AbortController();
153140

154141
try {
@@ -292,6 +279,7 @@ export function ChatPageContent(props: {
292279
});
293280
} finally {
294281
setIsChatStreaming(false);
282+
setEnableAutoScroll(false);
295283
}
296284
},
297285
[
@@ -305,6 +293,8 @@ export function ChatPageContent(props: {
305293
);
306294

307295
const hasDoneAutoPrompt = useRef(false);
296+
297+
// eslint-disable-next-line no-restricted-syntax
308298
useEffect(() => {
309299
if (
310300
props.initialPrompt &&
@@ -337,45 +327,40 @@ export function ChatPageContent(props: {
337327
}}
338328
/>
339329
</header>
340-
<div className="container relative flex max-w-[800px] grow flex-col overflow-hidden rounded-lg pb-6">
330+
<div className="relative flex grow flex-col overflow-hidden rounded-lg pb-6">
341331
{showEmptyState ? (
342-
<div className="fade-in-0 flex grow animate-in flex-col justify-center">
332+
<div className="fade-in-0 container flex max-w-[800px] grow animate-in flex-col justify-center">
343333
<EmptyStateChatPageContent sendMessage={handleSendMessage} />
344334
</div>
345335
) : (
346336
<div className="fade-in-0 relative z-[0] flex max-h-full flex-1 animate-in flex-col overflow-hidden">
347-
<ScrollShadow
348-
className="flex-1"
349-
scrollableClassName="max-h-full"
350-
shadowColor="hsl(var(--background))"
351-
shadowClassName="z-[1]"
352-
>
353-
<Chats
354-
messages={messages}
355-
isChatStreaming={isChatStreaming}
356-
authToken={props.authToken}
357-
sessionId={sessionId}
358-
className="min-w-0 pt-10 pb-32"
359-
twAccount={props.account}
360-
client={client}
361-
/>
362-
{/* Scroll anchor */}
363-
<div ref={messagesEndRef} />
364-
</ScrollShadow>
365-
366-
<Chatbar
367-
sendMessage={handleSendMessage}
337+
<Chats
338+
messages={messages}
368339
isChatStreaming={isChatStreaming}
369-
abortChatStream={() => {
370-
chatAbortController?.abort();
371-
setChatAbortController(undefined);
372-
setIsChatStreaming(false);
373-
// if last message is presence, remove it
374-
if (messages[messages.length - 1]?.type === "presence") {
375-
setMessages((prev) => prev.slice(0, -1));
376-
}
377-
}}
340+
authToken={props.authToken}
341+
sessionId={sessionId}
342+
className="min-w-0 pt-10 pb-32"
343+
twAccount={props.account}
344+
client={client}
345+
enableAutoScroll={enableAutoScroll}
346+
setEnableAutoScroll={setEnableAutoScroll}
378347
/>
348+
349+
<div className="container max-w-[800px]">
350+
<Chatbar
351+
sendMessage={handleSendMessage}
352+
isChatStreaming={isChatStreaming}
353+
abortChatStream={() => {
354+
chatAbortController?.abort();
355+
setChatAbortController(undefined);
356+
setIsChatStreaming(false);
357+
// if last message is presence, remove it
358+
if (messages[messages.length - 1]?.type === "presence") {
359+
setMessages((prev) => prev.slice(0, -1));
360+
}
361+
}}
362+
/>
363+
</div>
379364
</div>
380365
)}
381366

apps/dashboard/src/app/nebula-app/(app)/components/Chats.stories.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ function Story() {
157157
},
158158
]}
159159
client={getThirdwebClient()}
160+
enableAutoScroll={true}
161+
setEnableAutoScroll={() => {}}
160162
/>
161163
</BadgeContainer>
162164

@@ -167,6 +169,8 @@ function Story() {
167169
isChatStreaming={false}
168170
sessionId="xxxxx"
169171
twAccount={accountStub()}
172+
enableAutoScroll={true}
173+
setEnableAutoScroll={() => {}}
170174
messages={[
171175
{
172176
text: randomLorem(10),
@@ -182,6 +186,8 @@ function Story() {
182186

183187
<BadgeContainer label="User + Assistant responses">
184188
<Chats
189+
enableAutoScroll={true}
190+
setEnableAutoScroll={() => {}}
185191
client={getThirdwebClient()}
186192
authToken="xxxxx"
187193
isChatStreaming={false}

0 commit comments

Comments
 (0)