Skip to content

Commit 8ba460b

Browse files
committed
[NEB-77] Nebula: Various UI updates (#6060)
1 parent 1e61a9e commit 8ba460b

File tree

6 files changed

+193
-108
lines changed

6 files changed

+193
-108
lines changed

apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ type Option = { label: string; value: string };
1616
export function MultiNetworkSelector(props: {
1717
selectedChainIds: number[];
1818
onChange: (chainIds: number[]) => void;
19+
disableChainId?: boolean;
20+
className?: string;
1921
}) {
2022
const { allChains, idToChain } = useAllChainsData();
2123

@@ -53,16 +55,24 @@ export function MultiNetworkSelector(props: {
5355
return (
5456
<div className="flex justify-between gap-4">
5557
<span className="flex grow gap-2 truncate text-left">
58+
<ChainIcon
59+
className="size-5"
60+
ipfsSrc={chain.icon?.url}
61+
loading="lazy"
62+
/>
5663
{cleanChainName(chain.name)}
5764
</span>
58-
<Badge variant="outline" className="gap-2">
59-
<span className="text-muted-foreground">Chain ID</span>
60-
{chain.chainId}
61-
</Badge>
65+
66+
{!props.disableChainId && (
67+
<Badge variant="outline" className="gap-2">
68+
<span className="text-muted-foreground">Chain ID</span>
69+
{chain.chainId}
70+
</Badge>
71+
)}
6272
</div>
6373
);
6474
},
65-
[idToChain],
75+
[idToChain, props.disableChainId],
6676
);
6777

6878
return (
@@ -79,6 +89,7 @@ export function MultiNetworkSelector(props: {
7989
disabled={allChains.length === 0}
8090
overrideSearchFn={searchFn}
8191
renderOption={renderOption}
92+
className={props.className}
8293
/>
8394
);
8495
}
@@ -143,7 +154,7 @@ export function SingleNetworkSelector(props: {
143154
ipfsSrc={chain.icon?.url}
144155
loading="lazy"
145156
/>
146-
{chain.name}
157+
{cleanChainName(chain.name)}
147158
</span>
148159

149160
{!props.disableChainId && (

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ function SessionCard(props: {
181181
<Link
182182
className="before:absolute before:inset-0"
183183
href={`/chat/${props.session.id}`}
184+
prefetch={false}
184185
>
185186
{props.session.title || "Untitled"}
186187
</Link>

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

Lines changed: 72 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import type { ExecuteConfig, SessionInfo } from "../api/types";
2020
import { newChatPageUrlStore, newSessionsStore } from "../stores";
2121
import { ChatBar } from "./ChatBar";
2222
import { type ChatMessage, Chats } from "./Chats";
23-
import ContextFiltersButton from "./ContextFilters";
23+
import ContextFiltersButton, { ContextFiltersForm } from "./ContextFilters";
2424
import { EmptyStateChatPageContent } from "./EmptyStateChatPageContent";
2525

2626
export function ChatPageContent(props: {
@@ -362,69 +362,92 @@ export function ChatPageContent(props: {
362362

363363
const showEmptyState = !userHasSubmittedMessage && messages.length === 0;
364364

365+
const handleUpdateContextFilters = async (
366+
values: ContextFilters | undefined,
367+
) => {
368+
// if session is not yet created, don't need to update sessions - starting a chat will create a session with the context filters
369+
if (sessionId) {
370+
await updateSession({
371+
authToken: props.authToken,
372+
config,
373+
sessionId,
374+
contextFilters: values,
375+
});
376+
}
377+
};
378+
365379
return (
366380
<div className="flex grow flex-col overflow-hidden">
367381
<WalletDisconnectedDialog
368382
open={showConnectModal}
369383
onOpenChange={setShowConnectModal}
370384
/>
371-
<header className="flex justify-start border-b bg-background p-4">
385+
<header className="flex justify-between border-b bg-background p-4 xl:hidden">
372386
<ContextFiltersButton
373387
contextFilters={contextFilters}
374388
setContextFilters={setContextFilters}
375-
updateContextFilters={async (values) => {
376-
// if session is not yet created, don't need to update sessions - starting a chat will create a session with the context filters
377-
if (sessionId) {
378-
await updateSession({
379-
authToken: props.authToken,
380-
config,
381-
sessionId,
382-
contextFilters: values,
383-
});
384-
}
385-
}}
389+
updateContextFilters={handleUpdateContextFilters}
386390
/>
387391
</header>
388-
<div className="relative flex grow flex-col overflow-hidden rounded-lg pb-6">
389-
{showEmptyState ? (
390-
<div className="fade-in-0 container flex max-w-[800px] grow animate-in flex-col justify-center">
391-
<EmptyStateChatPageContent sendMessage={handleSendMessage} />
392-
</div>
393-
) : (
394-
<div className="fade-in-0 relative z-[0] flex max-h-full flex-1 animate-in flex-col overflow-hidden">
395-
<Chats
396-
messages={messages}
397-
isChatStreaming={isChatStreaming}
398-
authToken={props.authToken}
399-
sessionId={sessionId}
400-
className="min-w-0 pt-6 pb-32"
401-
twAccount={props.account}
402-
client={client}
403-
enableAutoScroll={enableAutoScroll}
404-
setEnableAutoScroll={setEnableAutoScroll}
405-
/>
406-
407-
<div className="container max-w-[800px]">
408-
<ChatBar
409-
sendMessage={handleSendMessage}
392+
393+
<div className="flex grow overflow-hidden">
394+
<div className="relative flex grow flex-col overflow-hidden rounded-lg pb-6">
395+
{showEmptyState ? (
396+
<div className="fade-in-0 container flex max-w-[800px] grow animate-in flex-col justify-center">
397+
<EmptyStateChatPageContent sendMessage={handleSendMessage} />
398+
</div>
399+
) : (
400+
<div className="fade-in-0 relative z-[0] flex max-h-full flex-1 animate-in flex-col overflow-hidden">
401+
<Chats
402+
messages={messages}
410403
isChatStreaming={isChatStreaming}
411-
abortChatStream={() => {
412-
chatAbortController?.abort();
413-
setChatAbortController(undefined);
414-
setIsChatStreaming(false);
415-
// if last message is presence, remove it
416-
if (messages[messages.length - 1]?.type === "presence") {
417-
setMessages((prev) => prev.slice(0, -1));
418-
}
419-
}}
404+
authToken={props.authToken}
405+
sessionId={sessionId}
406+
className="min-w-0 pt-6 pb-32"
407+
twAccount={props.account}
408+
client={client}
409+
enableAutoScroll={enableAutoScroll}
410+
setEnableAutoScroll={setEnableAutoScroll}
420411
/>
412+
413+
<div className="container max-w-[800px]">
414+
<ChatBar
415+
sendMessage={handleSendMessage}
416+
isChatStreaming={isChatStreaming}
417+
abortChatStream={() => {
418+
chatAbortController?.abort();
419+
setChatAbortController(undefined);
420+
setIsChatStreaming(false);
421+
// if last message is presence, remove it
422+
if (messages[messages.length - 1]?.type === "presence") {
423+
setMessages((prev) => prev.slice(0, -1));
424+
}
425+
}}
426+
/>
427+
</div>
421428
</div>
422-
</div>
423-
)}
429+
)}
424430

425-
<p className="mt-4 text-center text-muted-foreground text-xs opacity-75 lg:text-sm">
426-
Nebula may make mistakes. Please use with discretion
427-
</p>
431+
<p className="mt-4 text-center text-muted-foreground text-xs opacity-75 lg:text-sm">
432+
Nebula may make mistakes. Please use with discretion
433+
</p>
434+
</div>
435+
<aside className="hidden w-[360px] flex-col border-l bg-card pt-4 xl:flex">
436+
<div className="px-4">
437+
<h3 className="font-semibold text-lg tracking-tight">Context</h3>
438+
<p className="mb-5 text-muted-foreground text-sm">
439+
Provide context to Nebula for your prompts
440+
</p>
441+
</div>
442+
<ContextFiltersForm
443+
contextFilters={contextFilters}
444+
setContextFilters={setContextFilters}
445+
modal={undefined}
446+
updateContextFilters={handleUpdateContextFilters}
447+
formBodyClassName="px-4"
448+
formActionContainerClassName="px-4 border-t-0 pt-0 bg-transparent"
449+
/>
450+
</aside>
428451
</div>
429452
</div>
430453
);

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

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { Badge } from "@/components/ui/badge";
44
import { Button } from "@/components/ui/button";
55
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
66
import {
7+
FileCode2Icon,
8+
MessageSquareShareIcon,
79
MessagesSquareIcon,
810
SquareDashedBottomCodeIcon,
911
TextIcon,
@@ -29,8 +31,11 @@ export function ChatSidebar(props: {
2931
return (
3032
<div className="flex h-full flex-col p-2">
3133
<div className="flex items-center justify-start gap-3 p-2 lg:justify-between">
32-
<Link href="/">
33-
<NebulaIcon className="size-8 text-foreground" />
34+
<Link href="/" className="flex items-center gap-2">
35+
<NebulaIcon className="size-8 text-foreground" aria-label="Nebula" />
36+
<span className="font-semibold text-lg tracking-tight">
37+
Playground
38+
</span>
3439
</Link>
3540

3641
<Badge variant="secondary" className="gap-1 py-1">
@@ -48,6 +53,13 @@ export function ChatSidebar(props: {
4853

4954
<div className="h-3" />
5055

56+
<SidebarIconLink
57+
href="https://portal.thirdweb.com/nebula/api-reference"
58+
icon={FileCode2Icon}
59+
label="API Reference"
60+
target="_blank"
61+
/>
62+
5163
<SidebarIconLink
5264
href="/chat/history"
5365
icon={MessagesSquareIcon}
@@ -79,7 +91,14 @@ export function ChatSidebar(props: {
7991
</ScrollShadow>
8092
)}
8193

82-
<div className="mb-3 border-b border-dashed pt-2 pb-3">
94+
<div className="mb-3 border-y border-dashed py-3">
95+
<SidebarIconLink
96+
href="https://docs.google.com/forms/d/e/1FAIpQLSeM3fJRyywihRZUF1fiTNKEpJ_AzAcohRwXPpLr_3zxQ6W-tg/viewform?usp=sharing"
97+
icon={MessageSquareShareIcon}
98+
label="Take our quick survey!"
99+
target="_blank"
100+
/>
101+
83102
<SidebarIconLink
84103
href="https://portal.thirdweb.com/changelog"
85104
icon={TextIcon}
@@ -116,6 +135,7 @@ function SidebarIconLink(props: {
116135
href={props.href}
117136
target={props.target}
118137
className="!justify-start !px-3 w-full gap-2.5 rounded-lg text-left"
138+
prefetch={false}
119139
>
120140
<props.icon className="size-4" />
121141
{props.label}

0 commit comments

Comments
 (0)