mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-09 22:31:10 +00:00
few more updates
This commit is contained in:
parent
238685a70e
commit
b880f7edf9
19 changed files with 311 additions and 176 deletions
|
|
@ -39,8 +39,8 @@ export default function RootLayout({
|
|||
>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
defaultTheme="dark"
|
||||
enableSystem={false}
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<AutumnProvider
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import { Header } from "@/components/new/header"
|
|||
import { ChatSidebar } from "@/components/chat"
|
||||
import { AnimatePresence } from "motion/react"
|
||||
import { MemoriesGrid } from "@/components/new/memories-grid"
|
||||
import { AnimatedGradientBackground } from "@/app/onboarding/setup/page"
|
||||
import { AnimatedGradientBackground } from "@/components/new/animated-gradient-background"
|
||||
|
||||
export default function NewPage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-black">
|
||||
<div className="h-screen overflow-hidden bg-black">
|
||||
<AnimatedGradientBackground topPosition="15%" />
|
||||
<Header />
|
||||
<AnimatedGradientBackground />
|
||||
<main className="relative">
|
||||
<div className="relative z-10">
|
||||
<div className="flex flex-row h-[calc(100vh-90px)] relative">
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { SetupHeader } from "./setup/header"
|
|||
import { ChatSidebar } from "./setup/chat-sidebar"
|
||||
import { Logo } from "@ui/assets/Logo"
|
||||
import NovaOrb from "@/components/nova/nova-orb"
|
||||
import { AnimatedGradientBackground } from "./setup/page"
|
||||
import { AnimatedGradientBackground } from "@/components/new/animated-gradient-background"
|
||||
|
||||
function UserSupermemory({ name }: { name: string }) {
|
||||
return (
|
||||
|
|
@ -33,7 +33,9 @@ function UserSupermemory({ name }: { name: string }) {
|
|||
>
|
||||
<Logo className="h-14 text-white" />
|
||||
<div className="flex flex-col items-start justify-center ml-4">
|
||||
<p className="text-white text-xs font-medium leading-none">{name}'s</p>
|
||||
<p className="text-white text-xs font-medium leading-none">
|
||||
{name.split(" ")[0]}'s
|
||||
</p>
|
||||
<p className="text-white font-bold text-4xl leading-none -mt-2">
|
||||
supermemory
|
||||
</p>
|
||||
|
|
@ -57,6 +59,7 @@ export default function OnboardingPage() {
|
|||
description: string
|
||||
otherLinks: string[]
|
||||
} | null>(null)
|
||||
const [showWelcomeContent, setShowWelcomeContent] = useState(false)
|
||||
|
||||
const currentFlow = flow || "welcome"
|
||||
const currentStep = step || "input"
|
||||
|
|
@ -68,6 +71,16 @@ export default function OnboardingPage() {
|
|||
}
|
||||
}, [user?.name])
|
||||
|
||||
useEffect(() => {
|
||||
if (currentFlow === "welcome" && currentStep === "input") {
|
||||
setShowWelcomeContent(false)
|
||||
const timer = setTimeout(() => {
|
||||
setShowWelcomeContent(true)
|
||||
}, 1250)
|
||||
return () => clearTimeout(timer)
|
||||
}
|
||||
}, [currentFlow, currentStep])
|
||||
|
||||
useEffect(() => {
|
||||
if (currentFlow !== "welcome") return
|
||||
|
||||
|
|
@ -179,10 +192,14 @@ export default function OnboardingPage() {
|
|||
|
||||
{isSetupFlow && <AnimatedGradientBackground />}
|
||||
|
||||
{isWelcomeFlow && (
|
||||
<div className="flex flex-col items-center justify-start h-[calc(100vh-86px)] overflow-y-auto relative">
|
||||
{isWelcomeFlow && currentStep === "input" && (
|
||||
<AnimatedGradientBackground animateFromBottom={true} />
|
||||
)}
|
||||
|
||||
{isWelcomeFlow && showWelcomeContent && (
|
||||
<div className="fixed inset-0 flex flex-col items-center justify-center overflow-y-auto">
|
||||
<motion.div
|
||||
className="fixed inset-0 bg-[url('/bg-rectangle.png')] bg-cover bg-center bg-no-repeat pointer-events-none"
|
||||
className="absolute inset-0 bg-[url('/bg-rectangle.png')] bg-cover bg-center bg-no-repeat pointer-events-none"
|
||||
transition={{ duration: 0.75, ease: "easeOut", bounce: 0 }}
|
||||
style={{
|
||||
mixBlendMode: "soft-light",
|
||||
|
|
@ -191,8 +208,7 @@ export default function OnboardingPage() {
|
|||
/>
|
||||
<motion.div
|
||||
className={cn(
|
||||
"relative z-10 flex flex-col items-center justify-center",
|
||||
minimizeNovaOrb ? "mt-0" : "mt-16",
|
||||
"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-10 flex flex-col items-center justify-center",
|
||||
)}
|
||||
animate={{
|
||||
gap: minimizeNovaOrb ? 0 : 16,
|
||||
|
|
@ -201,12 +217,9 @@ export default function OnboardingPage() {
|
|||
duration: 0.6,
|
||||
ease: "easeOut",
|
||||
}}
|
||||
layout
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale:
|
||||
currentStep === "features"
|
||||
? 0.7
|
||||
|
|
@ -220,7 +233,6 @@ export default function OnboardingPage() {
|
|||
ease: "easeOut",
|
||||
delay: 0.2,
|
||||
}}
|
||||
layout
|
||||
className="relative"
|
||||
>
|
||||
<NovaOrb size={novaSize} />
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ export function SetupHeader() {
|
|||
setName(storedName)
|
||||
}, [])
|
||||
|
||||
const userName = name ? `${name.split(" ")[0]}'s` : "My"
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className="flex p-6 justify-between items-center"
|
||||
|
|
@ -25,7 +27,9 @@ export function SetupHeader() {
|
|||
<Logo className="h-7" />
|
||||
{name && (
|
||||
<div className="flex flex-col items-start justify-center ml-2">
|
||||
<p className="text-[#8B8B8B] text-xs leading-tight">{name}'s</p>
|
||||
<p className="text-[#8B8B8B] text-xs leading-tight">
|
||||
{userName}
|
||||
</p>
|
||||
<p className="text-white font-bold text-xl leading-none -mt-1">
|
||||
supermemory
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
import { motion } from "motion/react"
|
||||
|
||||
export function AnimatedGradientBackground() {
|
||||
return (
|
||||
<div className="fixed inset-0 z-0 overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute top-[40%] left-0 right-0 bottom-0 bg-[url('/onboarding/bg-gradient-0.png')] bg-[length:150%_auto] bg-top bg-no-repeat"
|
||||
initial={{ y: "100%" }}
|
||||
animate={{
|
||||
y: 0,
|
||||
opacity: [1, 0, 1],
|
||||
}}
|
||||
transition={{
|
||||
y: { duration: 0.75, ease: "easeOut" },
|
||||
opacity: {
|
||||
duration: 8,
|
||||
repeat: Number.POSITIVE_INFINITY,
|
||||
ease: "easeInOut",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="absolute top-[40%] left-0 right-0 bottom-0 bg-[url('/onboarding/bg-gradient-1.png')] bg-[length:150%_auto] bg-top bg-no-repeat"
|
||||
initial={{ y: "100%" }}
|
||||
animate={{
|
||||
y: 0,
|
||||
opacity: [0, 1, 0],
|
||||
}}
|
||||
transition={{
|
||||
y: { duration: 0.75, ease: "easeOut" },
|
||||
opacity: {
|
||||
duration: 8,
|
||||
repeat: Number.POSITIVE_INFINITY,
|
||||
ease: "easeInOut",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="absolute top-20 left-0 right-0 bottom-0 bg-[url('/bg-rectangle.png')] bg-cover bg-center bg-no-repeat"
|
||||
initial={{ y: "100%" }}
|
||||
animate={{ y: 0 }}
|
||||
transition={{ duration: 0.75, ease: "easeOut", bounce: 0 }}
|
||||
style={{
|
||||
mixBlendMode: "soft-light",
|
||||
opacity: 0.6,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { motion } from "motion/react"
|
||||
import { motion, AnimatePresence } from "motion/react"
|
||||
import { Button } from "@ui/components/button"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { cn } from "@lib/utils"
|
||||
|
|
@ -62,48 +62,71 @@ export function RelatableQuestion() {
|
|||
)}
|
||||
>
|
||||
{relatableOptions.map((option, index) => (
|
||||
<button
|
||||
<div
|
||||
key={option.text}
|
||||
className={`
|
||||
group relative rounded-lg p-2 cursor-pointer transition-all duration-300 hover:border-[#4C608B66] border border-[#0D121A] max-w-[140px] min-h-[159px]
|
||||
${
|
||||
className={cn(
|
||||
"rounded-lg max-w-[140px] min-h-[159px] transition-all duration-300",
|
||||
selectedOptions.includes(index)
|
||||
? "border-[#3374FF] border bg-[url('/onboarding/bg-gradient-1.png')] bg-size-[350%_auto] bg-top bg-no-repeat"
|
||||
: "bg-[#080B0F] hover:bg-no-repeat"
|
||||
}
|
||||
? "p-px bg-linear-to-b from-[#3374FF] to-[#1A63FF00]"
|
||||
: "p-0 border border-[#0D121A] hover:border-[#4C608B66]",
|
||||
)}
|
||||
>
|
||||
<button
|
||||
className={`
|
||||
group relative w-full h-full rounded-lg p-2 cursor-pointer transition-all duration-300 overflow-hidden
|
||||
bg-[#080B0F] hover:bg-no-repeat
|
||||
`}
|
||||
onClick={() => {
|
||||
setSelectedOptions((prev) =>
|
||||
prev.includes(index)
|
||||
? prev.filter((i) => i !== index)
|
||||
: [...prev, index],
|
||||
)
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault()
|
||||
onClick={() => {
|
||||
setSelectedOptions((prev) =>
|
||||
prev.includes(index)
|
||||
? prev.filter((i) => i !== index)
|
||||
: [...prev, index],
|
||||
)
|
||||
}
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<div className="flex flex-col items-start justify-between h-full">
|
||||
<span className="text-2xl">{option.emoji}</span>
|
||||
<p
|
||||
className={`text-white text-sm leading-[135%] align-bottom text-left transition-opacity duration-300 ${
|
||||
selectedOptions.includes(index)
|
||||
? "opacity-100"
|
||||
: "opacity-50 group-hover:opacity-100"
|
||||
}`}
|
||||
>
|
||||
{option.text}
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault()
|
||||
setSelectedOptions((prev) =>
|
||||
prev.includes(index)
|
||||
? prev.filter((i) => i !== index)
|
||||
: [...prev, index],
|
||||
)
|
||||
}
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<AnimatePresence>
|
||||
{selectedOptions.includes(index) && (
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-[url('/onboarding/bg-gradient-1.png')] bg-size-[550%_auto] bg-top bg-no-repeat"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
<div className="relative flex flex-col items-start justify-between h-full">
|
||||
<span
|
||||
className={`text-2xl ${
|
||||
selectedOptions.includes(index)
|
||||
? "opacity-100"
|
||||
: "opacity-70 group-hover:opacity-100"
|
||||
}`}
|
||||
>
|
||||
{option.emoji}
|
||||
</span>
|
||||
<p
|
||||
className={`text-white text-sm leading-[135%] align-bottom text-left transition-opacity duration-300 ${
|
||||
selectedOptions.includes(index)
|
||||
? "opacity-100"
|
||||
: "opacity-50 group-hover:opacity-100"
|
||||
}`}
|
||||
>
|
||||
{option.text}
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex gap-4 my-8">
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
|
|||
Let's add your memories
|
||||
</h2>
|
||||
|
||||
<div className="space-y-4 max-w-[329px] mx-auto overflow-visible">
|
||||
<div className="space-y-4 max-w-[329px] mx-auto overflow-visible gap-4">
|
||||
<div className="text-left gap-[6px] flex flex-col" id="x-twitter-field">
|
||||
<label
|
||||
htmlFor="twitter-handle"
|
||||
|
|
@ -143,11 +143,14 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
|
|||
/>
|
||||
{errors.twitter && (
|
||||
<div className="absolute left-full ml-3">
|
||||
<div className="relative shrink-0 px-3 py-2 bg-red-500/20 rounded-xl">
|
||||
<div className="absolute left-0 top-1/2 -translate-x-full -translate-y-1/2 w-0 h-0 border-t-[6px] border-b-[6px] border-r-8 border-t-transparent border-b-transparent border-r-red-500/20" />
|
||||
<p className="text-red-500 text-xs whitespace-nowrap">
|
||||
{errors.twitter}
|
||||
</p>
|
||||
<div
|
||||
className={cn(
|
||||
"relative shrink-0 px-3 py-2 bg-[#290F0A] text-[#C73B1B] rounded-xl",
|
||||
dmSansClassName(),
|
||||
)}
|
||||
>
|
||||
<div className="absolute left-0.5 top-1/2 -translate-x-full -translate-y-1/2 w-0 h-0 border-t-[6px] border-b-[6px] border-r-8 border-t-transparent border-b-transparent border-[#290F0A]" />
|
||||
<p className="text-xs whitespace-nowrap">{errors.twitter}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -184,12 +187,12 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
|
|||
<div className="absolute left-full ml-3">
|
||||
<div
|
||||
className={cn(
|
||||
"relative shrink-0 px-3 py-2 bg-red-500/20 rounded-xl",
|
||||
"relative shrink-0 px-3 py-2 bg-[#290F0A] text-[#C73B1B] rounded-xl",
|
||||
dmSansClassName(),
|
||||
)}
|
||||
>
|
||||
<div className="absolute left-0 top-1/2 -translate-x-full -translate-y-1/2 w-0 h-0 border-t-[6px] border-b-[6px] border-r-8 border-t-transparent border-b-transparent border-r-red-500/20" />
|
||||
<p className="text-red-500 text-xs whitespace-nowrap">
|
||||
<div className="absolute left-0.5 top-1/2 -translate-x-full -translate-y-1/2 w-0 h-0 border-t-[6px] border-b-[6px] border-r-8 border-t-transparent border-b-transparent border-[#290F0A]" />
|
||||
<p className="text-xs whitespace-nowrap">
|
||||
{errors.linkedin}
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -211,34 +214,36 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
|
|||
</label>
|
||||
<span className="text-onboarding text-[10px]">Upto 3</span>
|
||||
</div>
|
||||
{otherLinks.map((link, index) => (
|
||||
<div
|
||||
key={`other-link-${index}`}
|
||||
className="flex items-center mb-2 relative"
|
||||
>
|
||||
<input
|
||||
id={`other-links-${index}`}
|
||||
type="text"
|
||||
placeholder="Add your website, GitHub, Notion..."
|
||||
value={link}
|
||||
onChange={(e) => updateOtherLink(index, e.target.value)}
|
||||
className="flex-1 px-4 py-2 bg-[#070E1B] border border-onboarding/20 rounded-xl text-white placeholder-onboarding focus:outline-none focus:border-[#4A4A4A] transition-colors h-[40px]"
|
||||
/>
|
||||
{index === otherLinks.length - 1 && otherLinks.length < 3 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
addOtherLink()
|
||||
}}
|
||||
className="size-8 m-1 absolute right-0 top-0 bg-black border border-[#161F2C] rounded-lg flex items-center justify-center text-white hover:bg-[#161F2C] transition-colors text-xl"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className="flex flex-col gap-1.5">
|
||||
{otherLinks.map((link, index) => (
|
||||
<div
|
||||
key={`other-link-${index}`}
|
||||
className="flex items-center relative"
|
||||
>
|
||||
<input
|
||||
id={`other-links-${index}`}
|
||||
type="text"
|
||||
placeholder="Add your website, GitHub, Notion..."
|
||||
value={link}
|
||||
onChange={(e) => updateOtherLink(index, e.target.value)}
|
||||
className="flex-1 px-4 py-2 bg-[#070E1B] border border-onboarding/20 rounded-xl text-white placeholder-onboarding focus:outline-none focus:border-[#4A4A4A] transition-colors h-[40px]"
|
||||
/>
|
||||
{index === otherLinks.length - 1 && otherLinks.length < 3 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
addOtherLink()
|
||||
}}
|
||||
className="size-8 m-1 absolute right-0 top-0 bg-black border border-[#161F2C] rounded-lg flex items-center justify-center text-white hover:bg-[#161F2C] transition-colors text-xl"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
|
@ -269,7 +274,7 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
|
|||
}}
|
||||
transition={{ duration: 1, ease: "easeOut", delay: 1 }}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
className="mt-[24px] pb-8"
|
||||
className="mt-[24px] pb-30"
|
||||
>
|
||||
<Button
|
||||
className="rounded-xl px-6 py-3 border border-onboarding/20 max-w-48 text-white disabled:opacity-50 disabled:cursor-not-allowed h-[40px] cursor-pointer"
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ export function ChatSidebar() {
|
|||
background: "linear-gradient(180deg, #0A0E14 0%, #05070A 100%)",
|
||||
}}
|
||||
>
|
||||
<NovaOrb size={24} className="!blur-none z-10" />
|
||||
<NovaOrb size={24} className="blur-[0.6px]! z-10" />
|
||||
Chat with Nova
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
|
|
@ -268,7 +268,7 @@ export function ChatSidebar() {
|
|||
exit={{ x: "100px", opacity: 0 }}
|
||||
transition={{ duration: 0.3, ease: "easeOut", bounce: 0 }}
|
||||
>
|
||||
<div className="flex items-center justify-between pt-4 px-6 pb-3 shadow-[0_8px_16px_-4px_rgba(0,0,0,0.4)]">
|
||||
<div className="flex items-center justify-between pt-4 px-4 pb-3 shadow-[0_8px_16px_-4px_rgba(0,0,0,0.4)]">
|
||||
<ChatModelSelector
|
||||
selectedModel={selectedModel}
|
||||
onModelChange={setSelectedModel}
|
||||
|
|
@ -276,7 +276,7 @@ export function ChatSidebar() {
|
|||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="headers"
|
||||
className="rounded-full text-base gap-2 !h-10 border-[#73737333] bg-[#0D121A]"
|
||||
className="rounded-full text-base gap-2 h-10! border-[#73737333] bg-[#0D121A]"
|
||||
style={{
|
||||
boxShadow: "1.5px 1.5px 4.5px 0 rgba(0, 0, 0, 0.70) inset",
|
||||
}}
|
||||
|
|
@ -285,7 +285,7 @@ export function ChatSidebar() {
|
|||
</Button>
|
||||
<Button
|
||||
variant="headers"
|
||||
className="rounded-full text-base gap-3 !h-10 border-[#73737333] bg-[#0D121A] cursor-pointer"
|
||||
className="rounded-full text-base gap-3 h-10! border-[#73737333] bg-[#0D121A] cursor-pointer"
|
||||
style={{
|
||||
boxShadow: "1.5px 1.5px 4.5px 0 rgba(0, 0, 0, 0.70) inset",
|
||||
}}
|
||||
|
|
@ -427,9 +427,9 @@ function ChatEmptyStatePlaceholder() {
|
|||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-full">
|
||||
<div className="relative">
|
||||
<GradientLogo className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" />
|
||||
<LogoBgGradient className="" />
|
||||
<div className="relative w-32 h-32">
|
||||
<GradientLogo className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-16 h-16" />
|
||||
<LogoBgGradient className="w-full h-full" />
|
||||
</div>
|
||||
<div className="gap-3 flex flex-col items-center justify-center">
|
||||
<p>Ask me anything about your memories...</p>
|
||||
|
|
@ -443,7 +443,7 @@ function ChatEmptyStatePlaceholder() {
|
|||
<Button
|
||||
key={suggestion}
|
||||
variant="default"
|
||||
className="rounded-full text-base gap-1 !h-10 border-[#2261CA33] bg-[#0D121A] border w-fit"
|
||||
className="rounded-full text-base gap-1 h-10! border-[#2261CA33] bg-[#041127] border w-fit py-[4px] pl-[8px] pr-[12px]"
|
||||
>
|
||||
<SearchIcon className="size-4 text-[#267BF1]" />
|
||||
<span className="text-[#267BF1] text-[12px]">{suggestion}</span>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { cn } from "@lib/utils"
|
||||
import { ArrowUpIcon, SquareIcon } from "lucide-react"
|
||||
import { SquareIcon } from "lucide-react"
|
||||
|
||||
export function SendButton({
|
||||
onClick,
|
||||
|
|
@ -14,13 +14,25 @@ export function SendButton({
|
|||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
"bg-[#000000] border-[#161F2C] border p-2 rounded-lg flex-shrink-0 transition-opacity",
|
||||
"bg-[#000000] border-[#161F2C] border p-2 rounded-lg shrink-0 transition-opacity",
|
||||
disabled
|
||||
? "opacity-50 cursor-not-allowed"
|
||||
: "cursor-pointer hover:bg-[#161F2C]",
|
||||
)}
|
||||
>
|
||||
<ArrowUpIcon className="size-5 text-white" />
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 12 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>Send Icon</title>
|
||||
<path
|
||||
d="M12 6L10.55 7.4L7 3.85L7 16L5 16L5 3.85L1.45 7.4L-4.37114e-07 6L6 -2.62268e-07L12 6Z"
|
||||
fill="#FAFAFA"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
|
@ -30,7 +42,7 @@ export function StopButton({ onClick }: { onClick: () => void }) {
|
|||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className="bg-[#000000] border-[#161F2C] border p-2 rounded-lg flex-shrink-0 cursor-pointer hover:bg-[#161F2C] transition-opacity"
|
||||
className="bg-[#000000] border-[#161F2C] border p-2 rounded-lg shrink-0 cursor-pointer hover:bg-[#161F2C] transition-opacity"
|
||||
>
|
||||
<SquareIcon className="size-4 text-white fill-white" />
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export default function ChatInput({
|
|||
className={cn("bg-[#01173C] relative")}
|
||||
animate={{
|
||||
padding: isExpanded ? "0.5rem" : "0",
|
||||
margin: isExpanded ? "0" : "0.5rem",
|
||||
margin: isExpanded ? "0" : "16px",
|
||||
borderRadius: isExpanded ? "0 0 12px 12px" : "12px",
|
||||
}}
|
||||
transition={{
|
||||
|
|
@ -71,7 +71,7 @@ export default function ChatInput({
|
|||
}}
|
||||
>
|
||||
{isExpanded && (
|
||||
<div className="absolute top-0 left-0 right-0 h-10 bg-gradient-to-b from-[#01173C] via-[#01173C]/50 to-transparent pointer-events-none z-10" />
|
||||
<div className="absolute top-0 left-0 right-0 h-10 bg-linear-to-b from-[#01173C] via-[#01173C]/50 to-transparent pointer-events-none z-10" />
|
||||
)}
|
||||
{chainOfThoughtComponent}
|
||||
</div>
|
||||
|
|
@ -85,8 +85,8 @@ export default function ChatInput({
|
|||
setIsExpanded(!isExpanded)
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<NovaOrb size={24} className="!blur-none z-10" />
|
||||
<div className="flex items-center gap-3">
|
||||
<NovaOrb size={24} className="blur-[1px]! z-10" />
|
||||
<p className={cn("text-[#525D6E]", dmSansClassName())}>
|
||||
{activeStatus || "Waiting for input..."}
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export function RelatedMemories({
|
|||
)}
|
||||
</div>
|
||||
{result.score && (
|
||||
<div className="flex justify-center p-1">
|
||||
<div className="flex justify-center p-[4px]">
|
||||
<div
|
||||
className={cn(
|
||||
"text-[10px] inline-block bg-clip-text text-transparent font-medium",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export function UserMessage({
|
|||
|
||||
return (
|
||||
<div className="flex flex-col items-end w-full">
|
||||
<div className="bg-[#1B1F24] rounded-lg p-3 px-[14px] max-w-[80%]">
|
||||
<div className="bg-[#1B1F24] rounded-[12px] p-3 px-[14px] max-w-[80%]">
|
||||
<p className="text-sm text-white">{text}</p>
|
||||
</div>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -8,13 +8,14 @@ export function InitialHeader({
|
|||
showUserSupermemory?: boolean
|
||||
name?: string
|
||||
}) {
|
||||
const userName = name ? `${name.split(" ")[0]}'s` : "My"
|
||||
return (
|
||||
<div className="flex p-6 justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center z-10!">
|
||||
<Logo className="h-7" />
|
||||
{showUserSupermemory && (
|
||||
<div className="flex flex-col items-start justify-center ml-2">
|
||||
<p className="text-[#8B8B8B] text-sm leading-tight">{name}'s</p>
|
||||
<p className="text-[#8B8B8B] text-sm leading-tight">{userName}</p>
|
||||
<p className="text-white font-bold text-xl leading-none -mt-1">
|
||||
supermemory
|
||||
</p>
|
||||
|
|
@ -23,7 +24,7 @@ export function InitialHeader({
|
|||
</div>
|
||||
<Button
|
||||
variant="newDefault"
|
||||
className="rounded-2xl text-base gap-1 h-11! z-10"
|
||||
className="rounded-2xl text-base gap-1 h-11! z-10!"
|
||||
size={"lg"}
|
||||
>
|
||||
Memory API <span className="text-xs mt-[4px]">↗</span>
|
||||
|
|
|
|||
68
apps/web/components/new/animated-gradient-background.tsx
Normal file
68
apps/web/components/new/animated-gradient-background.tsx
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import { motion } from "motion/react"
|
||||
|
||||
export function AnimatedGradientBackground({
|
||||
topPosition = "40%",
|
||||
animateFromBottom = true,
|
||||
}: {
|
||||
topPosition?: string
|
||||
animateFromBottom?: boolean
|
||||
}) {
|
||||
return (
|
||||
<div className="fixed inset-0 z-0 overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute top-0 left-0 right-0 bottom-0 bg-[url('/onboarding/bg-gradient-0.png')] bg-size-[150%_auto] bg-top bg-no-repeat"
|
||||
style={{ top: animateFromBottom ? undefined : topPosition }}
|
||||
initial={{ y: "100%" }}
|
||||
animate={{
|
||||
y: 0,
|
||||
opacity: animateFromBottom ? 0 : [1, 0, 1],
|
||||
top: animateFromBottom ? "0%" : topPosition,
|
||||
}}
|
||||
transition={{
|
||||
y: { duration: 0.75, ease: "easeOut" },
|
||||
opacity: animateFromBottom
|
||||
? { duration: 2, ease: "easeOut" }
|
||||
: {
|
||||
duration: 8,
|
||||
repeat: Number.POSITIVE_INFINITY,
|
||||
ease: "easeInOut",
|
||||
},
|
||||
top: animateFromBottom
|
||||
? { duration: 0.75, ease: "easeOut" }
|
||||
: undefined,
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="absolute top-0 left-0 right-0 bottom-0 bg-[url('/onboarding/bg-gradient-1.png')] bg-size-[150%_auto] bg-top bg-no-repeat"
|
||||
style={{ top: animateFromBottom ? undefined : topPosition }}
|
||||
initial={{ y: "100%" }}
|
||||
animate={{
|
||||
y: 0,
|
||||
opacity: animateFromBottom ? 0 : [0, 1, 0],
|
||||
top: animateFromBottom ? "0%" : topPosition,
|
||||
}}
|
||||
transition={{
|
||||
y: { duration: 0.75, ease: "easeOut" },
|
||||
opacity: animateFromBottom
|
||||
? { duration: 2, ease: "easeOut" }
|
||||
: {
|
||||
duration: 8,
|
||||
repeat: Number.POSITIVE_INFINITY,
|
||||
ease: "easeInOut",
|
||||
},
|
||||
top: animateFromBottom
|
||||
? { duration: 0.75, ease: "easeOut" }
|
||||
: undefined,
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="absolute top-0 left-0 right-0 bottom-0 bg-[url('/bg-rectangle.png')] bg-cover bg-center bg-no-repeat"
|
||||
transition={{ duration: 0.75, ease: "easeOut", bounce: 0 }}
|
||||
style={{
|
||||
mixBlendMode: "soft-light",
|
||||
opacity: 0.4,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -11,6 +11,63 @@ import { FileText, Image, Video } from "lucide-react"
|
|||
type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>
|
||||
type DocumentWithMemories = DocumentsResponse["documents"][0]
|
||||
|
||||
function PDFIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="8"
|
||||
height="10"
|
||||
viewBox="0 0 8 10"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>PDF Icon</title>
|
||||
<g filter="url(#filter0_i_719_6586)">
|
||||
<path
|
||||
d="M1 10C0.725 10 0.489583 9.90208 0.29375 9.70625C0.0979167 9.51042 0 9.275 0 9V1C0 0.725 0.0979167 0.489583 0.29375 0.29375C0.489583 0.0979167 0.725 0 1 0H5L8 3V9C8 9.275 7.90208 9.51042 7.70625 9.70625C7.51042 9.90208 7.275 10 7 10H1ZM4.5 3.5V1H1V9H7V3.5H4.5Z"
|
||||
fill="#FF7673"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_i_719_6586"
|
||||
x="0"
|
||||
y="0"
|
||||
width="8.25216"
|
||||
height="10.2522"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dx="0.252163" dy="0.252163" />
|
||||
<feGaussianBlur stdDeviation="0.504325" />
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0.0431373 0 0 0 0 0.0588235 0 0 0 0 0.0823529 0 0 0 0.4 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="shape"
|
||||
result="effect1_innerShadow_719_6586"
|
||||
/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function getFileTypeInfo(document: DocumentWithMemories): {
|
||||
icon: React.ReactNode
|
||||
extension: string
|
||||
|
|
@ -22,9 +79,9 @@ function getFileTypeInfo(document: DocumentWithMemories): {
|
|||
if (mimeType) {
|
||||
if (mimeType === "application/pdf") {
|
||||
return {
|
||||
icon: <PDF className="w-4 h-4 text-[#DC2626]" />,
|
||||
icon: <PDFIcon />,
|
||||
extension: ".pdf",
|
||||
color: "#DC2626",
|
||||
color: "#FF7673",
|
||||
}
|
||||
}
|
||||
if (mimeType.startsWith("image/")) {
|
||||
|
|
@ -113,7 +170,7 @@ export function FilePreview({ document }: { document: DocumentWithMemories }) {
|
|||
<div className="flex items-center gap-1 mb-2">
|
||||
{icon}
|
||||
<p
|
||||
className={cn(dmSansClassName(), "text-[12px] font-semibold")}
|
||||
className={cn(dmSansClassName(), "text-[10px] font-semibold")}
|
||||
style={{ color: color }}
|
||||
>
|
||||
{extension}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export function McpPreview({ document }: { document: DocumentWithMemories }) {
|
|||
</p>
|
||||
<MCPIcon className="size-6" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="space-y-[6px]">
|
||||
{document.title && (
|
||||
<p className={cn(dmSansClassName(), "text-[12px] font-semibold")}>
|
||||
{document.title}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ export function Header() {
|
|||
localStorage.getItem("username") || localStorage.getItem("userName") || ""
|
||||
setName(storedName)
|
||||
}, [])
|
||||
|
||||
const userName = name ? `${name.split(" ")[0]}'s` : "My"
|
||||
return (
|
||||
<div className="flex p-4 justify-between items-center">
|
||||
<div className="flex items-center justify-center gap-4">
|
||||
|
|
@ -70,14 +72,14 @@ export function Header() {
|
|||
<Logo className="h-7" />
|
||||
{name && (
|
||||
<div className="flex flex-col items-start justify-center ml-2">
|
||||
<p className="text-[#8B8B8B] text-sm leading-tight">{name}'s</p>
|
||||
<p className="text-[#8B8B8B] text-sm leading-tight">{userName}</p>
|
||||
<p className="text-white font-bold text-xl leading-none -mt-1">
|
||||
supermemory
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="self-stretch w-[1px] bg-[#FFFFFF33]" />
|
||||
<div className="self-stretch w-px bg-[#FFFFFF33]" />
|
||||
<div className="flex items-center gap-2">
|
||||
<p>📁 {projectName}</p>
|
||||
<DropdownMenu>
|
||||
|
|
@ -121,7 +123,7 @@ export function Header() {
|
|||
</div>
|
||||
</div>
|
||||
<Tabs defaultValue="grid">
|
||||
<TabsList className="rounded-full border border-[#161F2C] !h-11">
|
||||
<TabsList className="rounded-full border border-[#161F2C] h-11!">
|
||||
<TabsTrigger
|
||||
value="grid"
|
||||
className={cn(
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function NovaOrb({ size = 200, className = "" }: NovaOrbProps) {
|
|||
style={{ width: `${size}px`, height: `${size}px` }}
|
||||
>
|
||||
<div
|
||||
className="rounded-full relative overflow-hidden border-[black] border-[1px]"
|
||||
className="rounded-full relative overflow-hidden"
|
||||
style={{
|
||||
width: size,
|
||||
height: size,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ function AnimatedGradientBackground() {
|
|||
return (
|
||||
<div className="fixed inset-0 z-0 overflow-hidden">
|
||||
<motion.div
|
||||
className="absolute top-[40%] left-0 right-0 bottom-0 bg-[url('/onboarding/bg-gradient-0.png')] bg-size-[150%_auto] bg-top bg-no-repeat"
|
||||
className="absolute top-[20%] left-0 right-0 bottom-0 bg-[url('/onboarding/bg-gradient-0.png')] bg-size-[150%_auto] bg-top bg-no-repeat"
|
||||
initial={{ y: "100%" }}
|
||||
animate={{
|
||||
y: 0,
|
||||
|
|
@ -34,7 +34,7 @@ function AnimatedGradientBackground() {
|
|||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="absolute top-[40%] left-0 right-0 bottom-0 bg-[url('/onboarding/bg-gradient-1.png')] bg-size-[150%_auto] bg-top bg-no-repeat"
|
||||
className="absolute top-[20%] left-0 right-0 bottom-0 bg-[url('/onboarding/bg-gradient-1.png')] bg-size-[150%_auto] bg-top bg-no-repeat"
|
||||
initial={{ y: "100%" }}
|
||||
animate={{
|
||||
y: 0,
|
||||
|
|
@ -47,8 +47,6 @@ function AnimatedGradientBackground() {
|
|||
/>
|
||||
<motion.div
|
||||
className="absolute top-0 left-0 right-0 bottom-0 bg-[url('/bg-rectangle.png')] bg-cover bg-center bg-no-repeat"
|
||||
initial={{ y: "100%" }}
|
||||
animate={{ y: 0 }}
|
||||
transition={{ duration: 0.75, ease: "easeOut", bounce: 0 }}
|
||||
style={{
|
||||
mixBlendMode: "soft-light",
|
||||
|
|
@ -62,7 +60,7 @@ function AnimatedGradientBackground() {
|
|||
function LoginCard({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<motion.div
|
||||
className="flex max-w-[360px] p-8 flex-col items-start gap-2 rounded-[22px] bg-linear-to-b from-[#06101F] to-[#030912] shadow-[1.5px_1.5px_20px_0_rgba(0,0,0,0.65),1px_1.5px_2px_0_rgba(128,189,255,0.07)_inset,-0.5px_-1.5px_4px_0_rgba(0,35,73,0.40)_inset]"
|
||||
className="flex py-8 px-11 flex-col items-start gap-2 rounded-[22px] bg-linear-to-b from-[#06101F] to-[#030912] shadow-[1.5px_1.5px_20px_0_rgba(0,0,0,0.65),1px_1.5px_2px_0_rgba(128,189,255,0.07)_inset,-0.5px_-1.5px_4px_0_rgba(0,35,73,0.40)_inset]"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.75, ease: "easeOut" }}
|
||||
|
|
@ -225,7 +223,7 @@ export function LoginPage() {
|
|||
</div>
|
||||
{submittedEmail ? (
|
||||
<LoginCard>
|
||||
<div className="w-full flex flex-col gap-4 lg:gap-6 min-h-2/3">
|
||||
<div className="w-[360px] flex flex-col gap-4 lg:gap-6 min-h-2/3">
|
||||
<div className="flex flex-col gap-2 text-center lg:text-left">
|
||||
<Title1Bold className="text-foreground">
|
||||
Almost there!
|
||||
|
|
@ -262,7 +260,10 @@ export function LoginPage() {
|
|||
</LoginCard>
|
||||
) : (
|
||||
<LoginCard>
|
||||
<div className="w-full flex flex-col" style={{ gap: "12px" }}>
|
||||
<div
|
||||
className="w-[360px] flex flex-col"
|
||||
style={{ gap: "12px" }}
|
||||
>
|
||||
{params.get("error") && (
|
||||
<div className="text-red-500">
|
||||
Error: {params.get("error")}. Please try again!
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue