aboutsummaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMahesh Sanikommu <[email protected]>2025-10-29 15:35:57 -0700
committerGitHub <[email protected]>2025-10-29 15:35:57 -0700
commit399f7beeeb8ded52ed1e000df056e08e79dba1d4 (patch)
treebf2776ae000c11e8fd904f77769ac9904e476641 /apps
parentchore: remove unused files (#540) (diff)
downloadsupermemory-399f7beeeb8ded52ed1e000df056e08e79dba1d4.tar.xz
supermemory-399f7beeeb8ded52ed1e000df056e08e79dba1d4.zip
fix: chat messages scroll effect (#544)
Diffstat (limited to 'apps')
-rw-r--r--apps/web/app/(navigation)/chat/[id]/page.tsx10
-rw-r--r--apps/web/app/(navigation)/layout.tsx4
-rw-r--r--apps/web/components/views/chat/chat-messages.tsx326
3 files changed, 170 insertions, 170 deletions
diff --git a/apps/web/app/(navigation)/chat/[id]/page.tsx b/apps/web/app/(navigation)/chat/[id]/page.tsx
index da64a79d..0f429595 100644
--- a/apps/web/app/(navigation)/chat/[id]/page.tsx
+++ b/apps/web/app/(navigation)/chat/[id]/page.tsx
@@ -18,14 +18,8 @@ export default function ChatPage() {
}, [chatId, setCurrentChatId])
return (
- <div className="flex flex-col w-full">
- <div className="flex flex-col h-[93vh]">
- <div className="flex-1 flex justify-center min-h-0 w-full md:px-4">
- <div className="flex flex-col min-h-0 w-full max-w-4xl">
- <ChatMessages />
- </div>
- </div>
- </div>
+ <div className="h-full overflow-hidden">
+ <ChatMessages />
</div>
)
}
diff --git a/apps/web/app/(navigation)/layout.tsx b/apps/web/app/(navigation)/layout.tsx
index 4c37c10e..7b7628bb 100644
--- a/apps/web/app/(navigation)/layout.tsx
+++ b/apps/web/app/(navigation)/layout.tsx
@@ -42,11 +42,11 @@ export default function NavigationLayout({
}
}, [])
return (
- <div className="relative min-h-screen">
+ <div className="relative h-screen flex flex-col">
<div className="sticky top-0 z-50 bg-background/80 backdrop-blur-md border-b border-white/10">
<Header onAddMemory={() => setShowAddMemoryView(true)} />
</div>
- {children}
+ <div className="flex-1">{children}</div>
{showAddMemoryView && (
<AddMemoryView
initialTab="note"
diff --git a/apps/web/components/views/chat/chat-messages.tsx b/apps/web/components/views/chat/chat-messages.tsx
index 05e8afdf..22bc8a2a 100644
--- a/apps/web/components/views/chat/chat-messages.tsx
+++ b/apps/web/components/views/chat/chat-messages.tsx
@@ -412,177 +412,183 @@ export function ChatMessages() {
<div className="h-full flex flex-col w-full">
<div className="flex-1 relative">
<div
- className="flex flex-col gap-2 absolute inset-0 overflow-y-auto px-4 pt-4 pb-7 scroll-pb-7 custom-scrollbar"
+ className="absolute inset-0 overflow-y-auto custom-scrollbar"
onScroll={onScroll}
ref={scrollContainerRef}
>
- {messages.map((message) => (
- <div
- className={cn(
- "flex my-2",
- message.role === "user"
- ? "items-center flex-row-reverse gap-2"
- : "flex-col",
- )}
- key={message.id}
- >
+ <div className="flex flex-col gap-2 max-w-4xl mx-auto px-4 md:px-2 pt-4 pb-7 scroll-pb-7">
+ {messages.map((message) => (
<div
className={cn(
- "flex flex-col gap-2 md:max-w-4/5",
+ "flex my-2",
message.role === "user"
- ? "bg-accent/50 px-3 py-1.5 border border-border rounded-lg"
- : "",
+ ? "items-center flex-row-reverse gap-2"
+ : "flex-col",
)}
+ key={message.id}
>
- {message.parts
- .filter((part) =>
- ["text", "tool-searchMemories", "tool-addMemory"].includes(
- part.type,
- ),
- )
- .map((part, index) => {
- switch (part.type) {
- case "text":
- return (
- <div key={`${message.id}-${part.type}-${index}`}>
- <Streamdown>{part.text}</Streamdown>
- </div>
- )
- case "tool-searchMemories": {
- switch (part.state) {
- case "input-available":
- case "input-streaming":
- return (
- <div
- className="text-sm flex items-center gap-2 text-muted-foreground"
- key={`${message.id}-${part.type}-${index}`}
- >
- <Spinner className="size-4" /> Searching
- memories...
- </div>
- )
- case "output-error":
- return (
- <div
- className="text-sm flex items-center gap-2 text-muted-foreground"
- key={`${message.id}-${part.type}-${index}`}
- >
- <X className="size-4" /> Error recalling
- memories
- </div>
- )
- case "output-available": {
- const output = part.output
- const foundCount =
- typeof output === "object" &&
- output !== null &&
- "count" in output
- ? Number(output.count) || 0
- : 0
- // @ts-expect-error
- const results = Array.isArray(output?.results)
- ? // @ts-expect-error
- output.results
- : []
-
- return (
- <ExpandableMemories
- foundCount={foundCount}
- key={`${message.id}-${part.type}-${index}`}
- results={results}
- />
- )
+ <div
+ className={cn(
+ "flex flex-col gap-2 ",
+ message.role === "user"
+ ? "bg-accent/50 px-3 py-1.5 border border-border rounded-lg"
+ : "",
+ )}
+ >
+ {message.parts
+ .filter((part) =>
+ [
+ "text",
+ "tool-searchMemories",
+ "tool-addMemory",
+ ].includes(part.type),
+ )
+ .map((part, index) => {
+ switch (part.type) {
+ case "text":
+ return (
+ <div key={`${message.id}-${part.type}-${index}`}>
+ <Streamdown>{part.text}</Streamdown>
+ </div>
+ )
+ case "tool-searchMemories": {
+ switch (part.state) {
+ case "input-available":
+ case "input-streaming":
+ return (
+ <div
+ className="text-sm flex items-center gap-2 text-muted-foreground"
+ key={`${message.id}-${part.type}-${index}`}
+ >
+ <Spinner className="size-4" /> Searching
+ memories...
+ </div>
+ )
+ case "output-error":
+ return (
+ <div
+ className="text-sm flex items-center gap-2 text-muted-foreground"
+ key={`${message.id}-${part.type}-${index}`}
+ >
+ <X className="size-4" /> Error recalling
+ memories
+ </div>
+ )
+ case "output-available": {
+ const output = part.output
+ const foundCount =
+ typeof output === "object" &&
+ output !== null &&
+ "count" in output
+ ? Number(output.count) || 0
+ : 0
+ // @ts-expect-error
+ const results = Array.isArray(output?.results)
+ ? // @ts-expect-error
+ output.results
+ : []
+
+ return (
+ <ExpandableMemories
+ foundCount={foundCount}
+ key={`${message.id}-${part.type}-${index}`}
+ results={results}
+ />
+ )
+ }
+ default:
+ return null
}
- default:
- return null
}
- }
- case "tool-addMemory": {
- switch (part.state) {
- case "input-available":
- return (
- <div
- className="text-sm flex items-center gap-2 text-muted-foreground"
- key={`${message.id}-${part.type}-${index}`}
- >
- <Spinner className="size-4" /> Adding memory...
- </div>
- )
- case "output-error":
- return (
- <div
- className="text-sm flex items-center gap-2 text-muted-foreground"
- key={`${message.id}-${part.type}-${index}`}
- >
- <X className="size-4" /> Error adding memory
- </div>
- )
- case "output-available":
- return (
- <div
- className="text-sm flex items-center gap-2 text-muted-foreground"
- key={`${message.id}-${part.type}-${index}`}
- >
- <Check className="size-4" /> Memory added
- </div>
- )
- case "input-streaming":
- return (
- <div
- className="text-sm flex items-center gap-2 text-muted-foreground"
- key={`${message.id}-${part.type}-${index}`}
- >
- <Spinner className="size-4" /> Adding memory...
- </div>
- )
- default:
- return null
+ case "tool-addMemory": {
+ switch (part.state) {
+ case "input-available":
+ return (
+ <div
+ className="text-sm flex items-center gap-2 text-muted-foreground"
+ key={`${message.id}-${part.type}-${index}`}
+ >
+ <Spinner className="size-4" /> Adding
+ memory...
+ </div>
+ )
+ case "output-error":
+ return (
+ <div
+ className="text-sm flex items-center gap-2 text-muted-foreground"
+ key={`${message.id}-${part.type}-${index}`}
+ >
+ <X className="size-4" /> Error adding memory
+ </div>
+ )
+ case "output-available":
+ return (
+ <div
+ className="text-sm flex items-center gap-2 text-muted-foreground"
+ key={`${message.id}-${part.type}-${index}`}
+ >
+ <Check className="size-4" /> Memory added
+ </div>
+ )
+ case "input-streaming":
+ return (
+ <div
+ className="text-sm flex items-center gap-2 text-muted-foreground"
+ key={`${message.id}-${part.type}-${index}`}
+ >
+ <Spinner className="size-4" /> Adding
+ memory...
+ </div>
+ )
+ default:
+ return null
+ }
}
+ default:
+ return null
}
- default:
- return null
- }
- })}
- </div>
- {message.role === "assistant" && (
- <div className="flex items-center gap-0.5 mt-0.5">
- <Button
- className="size-7 text-muted-foreground hover:text-foreground"
- onClick={() => {
- navigator.clipboard.writeText(
- message.parts
- .filter((p) => p.type === "text")
- ?.map((p) => (p as MessagePart).text ?? "")
- .join("\n") ?? "",
- )
- toast.success("Copied to clipboard")
- }}
- size="icon"
- variant="ghost"
- >
- <Copy className="size-3.5" />
- </Button>
- <Button
- className="size-6 text-muted-foreground hover:text-foreground"
- onClick={() => regenerate({ messageId: message.id })}
- size="icon"
- variant="ghost"
- >
- <RotateCcw className="size-3.5" />
- </Button>
+ })}
</div>
- )}
- </div>
- ))}
- {status === "submitted" && (
- <div className="flex text-muted-foreground justify-start gap-2 px-4 py-3 items-center w-full">
- <Spinner className="size-4" />
- <TextShimmer className="text-sm" duration={1.5}>
- Thinking...
- </TextShimmer>
- </div>
- )}
- <div ref={bottomRef} />
+ {message.role === "assistant" && (
+ <div className="flex items-center gap-0.5 mt-0.5">
+ <Button
+ className="size-7 text-muted-foreground hover:text-foreground"
+ onClick={() => {
+ navigator.clipboard.writeText(
+ message.parts
+ .filter((p) => p.type === "text")
+ ?.map((p) => (p as MessagePart).text ?? "")
+ .join("\n") ?? "",
+ )
+ toast.success("Copied to clipboard")
+ }}
+ size="icon"
+ variant="ghost"
+ >
+ <Copy className="size-3.5" />
+ </Button>
+ <Button
+ className="size-6 text-muted-foreground hover:text-foreground"
+ onClick={() => regenerate({ messageId: message.id })}
+ size="icon"
+ variant="ghost"
+ >
+ <RotateCcw className="size-3.5" />
+ </Button>
+ </div>
+ )}
+ </div>
+ ))}
+ {status === "submitted" && (
+ <div className="flex text-muted-foreground justify-start gap-2 px-4 py-3 items-center w-full">
+ <Spinner className="size-4" />
+ <TextShimmer className="text-sm" duration={1.5}>
+ Thinking...
+ </TextShimmer>
+ </div>
+ )}
+ <div ref={bottomRef} />
+ </div>
</div>
<Button
@@ -605,9 +611,9 @@ export function ChatMessages() {
</Button>
</div>
- <div className="px-4 pb-4 pt-1 relative flex-shrink-0">
+ <div className="pb-4 px-4 md:px-2 max-w-4xl mx-auto w-full">
<form
- className="flex flex-col items-end gap-3 bg-card border border-border rounded-[22px] p-3 relative shadow-lg dark:shadow-2xl"
+ className="flex flex-col items-end gap-3 border border-border rounded-[22px] p-3 relative shadow-lg dark:shadow-2xl"
onSubmit={(e) => {
e.preventDefault()
if (status === "submitted") return