mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
few more changes
This commit is contained in:
parent
6725f67b32
commit
497986524b
5 changed files with 103 additions and 83 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import type { Metadata } from "next";
|
||||
import { Inter, JetBrains_Mono } from "next/font/google";
|
||||
import { Inter, JetBrains_Mono, Space_Grotesk } from "next/font/google";
|
||||
import "../globals.css";
|
||||
import "@ui/globals.css";
|
||||
import { AuthProvider } from "@lib/auth-context";
|
||||
|
|
@ -25,6 +25,12 @@ const mono = JetBrains_Mono({
|
|||
variable: "--font-mono",
|
||||
});
|
||||
|
||||
const spaceGrotesk = Space_Grotesk({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-serif",
|
||||
});
|
||||
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL("https://app.supermemory.ai"),
|
||||
description: "Your memories, wherever you are",
|
||||
|
|
@ -39,7 +45,7 @@ export default function RootLayout({
|
|||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body
|
||||
className={`${sans.variable} ${mono.variable} antialiased`}
|
||||
className={`${sans.variable} ${mono.variable} ${spaceGrotesk.variable} antialiased`}
|
||||
>
|
||||
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem>
|
||||
<AutumnProvider
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ const MemoryAppPage = () => {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="font-sans">
|
||||
<AppHeader />
|
||||
|
||||
<MemoryListView
|
||||
|
|
|
|||
|
|
@ -44,34 +44,43 @@ export function ChatInline() {
|
|||
<div className="w-full max-w-4xl">
|
||||
<div className="text-start mb-6">
|
||||
<h2 className="text-xl font-medium text-foreground mb-2">
|
||||
Night owl, Mahesh
|
||||
Good evening, Mahesh
|
||||
</h2>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="flex flex-col border border-border rounded-lg shadow-sm hover:shadow-md transition-shadow min-h-24">
|
||||
<textarea
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="Ask your supermemory..."
|
||||
id="chat-inline-textarea"
|
||||
className="flex-1 bg-transparent text-foreground placeholder:text-muted-foreground focus:outline-none text-base resize-none px-4 py-3"
|
||||
rows={2}
|
||||
/>
|
||||
<div className="flex w-full rounded-b-lg justify-end">
|
||||
<button
|
||||
onClick={handleSend}
|
||||
disabled={!message.trim()}
|
||||
className="p-2 mr-1 rounded-lg disabled:text-muted-foreground disabled:cursor-not-allowed transition-colors flex-shrink-0"
|
||||
type="button"
|
||||
>
|
||||
<ArrowUp className="w-6 h-6 bg-black rounded-full p-1 text-white" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="bg-gradient-to-r from-blue-500 to-blue-600 p-[2px] rounded-3xl shadow-lg">
|
||||
<form
|
||||
className="flex flex-col items-end gap-3 bg-white rounded-[22px] p-3"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
if (!message.trim()) return
|
||||
handleSend()
|
||||
}}
|
||||
>
|
||||
<textarea
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="Yo, describe my fav destination..."
|
||||
className="w-full text-black placeholder-black/40 rounded-md outline-none resize-none text-base leading-relaxed"
|
||||
rows={2}
|
||||
/>
|
||||
<div className="flex items-center gap-2 w-full justify-between">
|
||||
<div className="flex items-center gap-2" />
|
||||
<button
|
||||
onClick={handleSend}
|
||||
disabled={!message.trim()}
|
||||
className="text-white border-0 rounded-lg size-10 flex items-center justify-center transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
type="button"
|
||||
>
|
||||
<img src="/icons/send.svg" alt="Send" className="w-8 h-8" />
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ const DocumentCard = memo(
|
|||
|
||||
return (
|
||||
<Card
|
||||
className="h-full mx-4 p-4 transition-all cursor-pointer group relative overflow-hidden bg-card gap-2 md:w-full"
|
||||
className="h-full mx-4 p-4 transition-all cursor-pointer group relative overflow-hidden bg-card shadow-lg gap-2 md:w-full hover:shadow-xl"
|
||||
onClick={() => {
|
||||
analytics.documentCardClicked();
|
||||
onOpenDetails(document);
|
||||
|
|
@ -61,7 +61,7 @@ const DocumentCard = memo(
|
|||
<CardHeader className="relative z-10 px-0">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-1">
|
||||
{getDocumentIcon(document.type, "w-4 h-4 flex-shrink-0")}
|
||||
{/*{getDocumentIcon(document.type, "w-4 h-4 flex-shrink-0")}*/}
|
||||
<p
|
||||
className={cn(
|
||||
"text-sm font-medium line-clamp-1",
|
||||
|
|
|
|||
|
|
@ -345,25 +345,26 @@ export function ChatMessages() {
|
|||
<div className="h-full mx-auto flex flex-col max-w-3xl">
|
||||
<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"
|
||||
className="flex flex-col gap-2 absolute inset-0 overflow-y-auto px-4 pt-4 pb-7 scroll-pb-7 custom-scrollbar"
|
||||
onScroll={onScroll}
|
||||
ref={scrollContainerRef}
|
||||
>
|
||||
{messages.map((message) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex",
|
||||
message.role === "user" ? "items-center gap-2" : "flex-col",
|
||||
"flex my-2",
|
||||
message.role === "user"
|
||||
? "items-center flex-row-reverse gap-2"
|
||||
: "flex-col",
|
||||
)}
|
||||
key={message.id}
|
||||
>
|
||||
{message.role === "user" && (
|
||||
<UserIcon className="size-4 text-muted-foreground" />
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col gap-2 max-w-4/5 rounded-full",
|
||||
message.role === "user" ? "bg-white/10 px-3 py-1.5" : "",
|
||||
"flex flex-col gap-2 max-w-4/5",
|
||||
message.role === "user"
|
||||
? "bg-white/10 px-3 py-1.5 border border-black/20 rounded-lg"
|
||||
: "",
|
||||
)}
|
||||
>
|
||||
{message.parts
|
||||
|
|
@ -372,14 +373,14 @@ export function ChatMessages() {
|
|||
part.type,
|
||||
),
|
||||
)
|
||||
.map((part) => {
|
||||
.map((part, index) => {
|
||||
switch (part.type) {
|
||||
case "text":
|
||||
return (
|
||||
<div key={message.id + part.type}>
|
||||
<div key={`${message.id}-${part.type}-${index}`}>
|
||||
<Streamdown>{part.text}</Streamdown>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
case "tool-searchMemories": {
|
||||
switch (part.state) {
|
||||
case "input-available":
|
||||
|
|
@ -387,46 +388,46 @@ export function ChatMessages() {
|
|||
return (
|
||||
<div
|
||||
className="text-sm flex items-center gap-2 text-muted-foreground"
|
||||
key={message.id + part.type}
|
||||
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}
|
||||
key={`${message.id}-${part.type}-${index}`}
|
||||
>
|
||||
<X className="size-4" /> Error recalling
|
||||
memories
|
||||
</div>
|
||||
);
|
||||
)
|
||||
case "output-available": {
|
||||
const output = part.output;
|
||||
const output = part.output
|
||||
const foundCount =
|
||||
typeof output === "object" &&
|
||||
output !== null &&
|
||||
"count" in output
|
||||
? Number(output.count) || 0
|
||||
: 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}
|
||||
key={`${message.id}-${part.type}-${index}`}
|
||||
results={results}
|
||||
/>
|
||||
);
|
||||
)
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
}
|
||||
case "tool-addMemory": {
|
||||
|
|
@ -435,44 +436,44 @@ export function ChatMessages() {
|
|||
return (
|
||||
<div
|
||||
className="text-sm flex items-center gap-2 text-muted-foreground"
|
||||
key={message.id + part.type}
|
||||
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}
|
||||
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}
|
||||
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}
|
||||
key={`${message.id}-${part.type}-${index}`}
|
||||
>
|
||||
<Spinner className="size-4" /> Adding memory...
|
||||
</div>
|
||||
);
|
||||
)
|
||||
default:
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
|
|
@ -486,8 +487,8 @@ export function ChatMessages() {
|
|||
.filter((p) => p.type === "text")
|
||||
?.map((p) => (p as any).text)
|
||||
.join("\n") ?? "",
|
||||
);
|
||||
toast.success("Copied to clipboard");
|
||||
)
|
||||
toast.success("Copied to clipboard")
|
||||
}}
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
|
|
@ -526,8 +527,8 @@ export function ChatMessages() {
|
|||
: "opacity-0 scale-95 pointer-events-none",
|
||||
)}
|
||||
onClick={() => {
|
||||
enableAutoScroll();
|
||||
scrollToBottom("smooth");
|
||||
enableAutoScroll()
|
||||
scrollToBottom("smooth")
|
||||
}}
|
||||
size="sm"
|
||||
type="button"
|
||||
|
|
@ -540,32 +541,32 @@ export function ChatMessages() {
|
|||
<div className="px-4 pb-4 pt-1 relative flex-shrink-0">
|
||||
<div className="bg-gradient-to-r from-blue-500 to-blue-600 p-[3px] rounded-3xl shadow-lg">
|
||||
<div className="flex p-2 gap-2">
|
||||
<div className="backdrop-blur-md bg-white/10 border border-white/20 rounded-xl px-4 py-2 text-white text-sm hover:bg-white/15 transition-all duration-200 cursor-pointer shadow-lg">
|
||||
<div className="backdrop-blur-md bg-white/10 border border-white/20 rounded-lg p-2 text-white text-xs hover:bg-white/15 transition-all duration-200 cursor-pointer shadow-lg">
|
||||
Suggest me best hotels in Liechtenstein
|
||||
</div>
|
||||
<div className="backdrop-blur-md bg-white/10 border border-white/20 rounded-xl px-4 py-2 text-white/90 text-sm hover:bg-white/15 transition-all duration-200 cursor-pointer shadow-lg">
|
||||
<div className="backdrop-blur-md bg-white/10 border border-white/20 rounded-lg p-2 text-white/90 text-xs hover:bg-white/15 transition-all duration-200 cursor-pointer shadow-lg">
|
||||
Prepare a full itinerary to Liechtenstein
|
||||
</div>
|
||||
</div>
|
||||
<form
|
||||
className="flex flex-col items-end gap-3 bg-white rounded-[22px] p-2"
|
||||
className="flex flex-col items-end gap-3 bg-white rounded-[22px] p-3"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
if (status === "submitted") return;
|
||||
e.preventDefault()
|
||||
if (status === "submitted") return
|
||||
if (status === "streaming") {
|
||||
stop();
|
||||
return;
|
||||
stop()
|
||||
return
|
||||
}
|
||||
if (input.trim()) {
|
||||
enableAutoScroll();
|
||||
scrollToBottom("auto");
|
||||
sendMessage({ text: input });
|
||||
setInput("");
|
||||
enableAutoScroll()
|
||||
scrollToBottom("auto")
|
||||
sendMessage({ text: input })
|
||||
setInput("")
|
||||
}
|
||||
}}
|
||||
>
|
||||
<textarea
|
||||
className="w-full text-black placeholder-black/40 rounded-md outline-none resize-none text-base leading-relaxed p-2"
|
||||
className="w-full text-black placeholder-black/40 rounded-md outline-none resize-none text-base leading-relaxed"
|
||||
disabled={status === "submitted"}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="Yo, describe my fav destination..."
|
||||
|
|
@ -573,12 +574,12 @@ export function ChatMessages() {
|
|||
value={input}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
if (input.trim() && status !== "submitted") {
|
||||
enableAutoScroll();
|
||||
scrollToBottom("auto");
|
||||
sendMessage({ text: input });
|
||||
setInput("");
|
||||
enableAutoScroll()
|
||||
scrollToBottom("auto")
|
||||
sendMessage({ text: input })
|
||||
setInput("")
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
|
@ -592,14 +593,18 @@ export function ChatMessages() {
|
|||
type="button"
|
||||
variant="outline"
|
||||
>
|
||||
<img src="/icons/attach.svg" alt="Attach" className="w-5 h-5" />
|
||||
<img
|
||||
src="/icons/attach.svg"
|
||||
alt="Attach"
|
||||
className="w-5 h-5"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-white/20 hover:bg-white/30 text-black border-[#EBEBEB] rounded-lg px-4 py-2 h-10"
|
||||
type="button"
|
||||
variant="outline"
|
||||
>
|
||||
<Plus className="size-4 mr-2" />
|
||||
<Plus className="size-4" />
|
||||
Link Project
|
||||
</Button>
|
||||
</div>
|
||||
|
|
@ -612,7 +617,7 @@ export function ChatMessages() {
|
|||
variant="ghost"
|
||||
>
|
||||
{status === "ready" ? (
|
||||
<img src="/icons/send.svg" alt="Send" className="w-7 h-7" />
|
||||
<img src="/icons/send.svg" alt="Send" className="w-8 h-8" />
|
||||
) : status === "submitted" ? (
|
||||
<Spinner className="size-5" />
|
||||
) : (
|
||||
|
|
@ -624,5 +629,5 @@ export function ChatMessages() {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue