diff options
| -rw-r--r-- | apps/web/app/(navigation)/chat/[id]/page.tsx | 10 | ||||
| -rw-r--r-- | apps/web/app/onboarding/mcp-form.tsx | 4 | ||||
| -rw-r--r-- | apps/web/app/onboarding/onboarding-background.tsx | 1 | ||||
| -rw-r--r-- | apps/web/components/chat-input.tsx | 2 | ||||
| -rw-r--r-- | apps/web/components/create-project-dialog.tsx | 61 | ||||
| -rw-r--r-- | apps/web/components/header.tsx | 67 | ||||
| -rw-r--r-- | apps/web/components/project-selector.tsx | 169 | ||||
| -rw-r--r-- | apps/web/components/views/add-memory/index.tsx | 1 | ||||
| -rw-r--r-- | packages/ui/assets/Logo.tsx | 2 | ||||
| -rw-r--r-- | packages/ui/globals.css | 4 |
10 files changed, 86 insertions, 235 deletions
diff --git a/apps/web/app/(navigation)/chat/[id]/page.tsx b/apps/web/app/(navigation)/chat/[id]/page.tsx index 9bb2038b..b3812998 100644 --- a/apps/web/app/(navigation)/chat/[id]/page.tsx +++ b/apps/web/app/(navigation)/chat/[id]/page.tsx @@ -7,7 +7,7 @@ import { ChatMessages } from "@/components/views/chat/chat-messages" export default function ChatPage() { const params = useParams() - const { setCurrentChatId, getCurrentChat } = usePersistentChat() + const { setCurrentChatId } = usePersistentChat() const chatId = params.id as string @@ -17,17 +17,9 @@ export default function ChatPage() { } }, [chatId, setCurrentChatId]) - const currentChat = getCurrentChat() - return ( <div className="flex flex-col w-full"> <div className="flex flex-col h-[93vh]"> - <div className="flex justify-center w-full"> - <h1 className="text-lg font-semibold flex-1 truncate text-center"> - {currentChat?.title || "New Chat"} - </h1> - </div> - <div className="flex-1 flex justify-center min-h-0 w-full px-4"> <div className="flex flex-col min-h-0 w-full max-w-4xl"> <ChatMessages /> diff --git a/apps/web/app/onboarding/mcp-form.tsx b/apps/web/app/onboarding/mcp-form.tsx index f8561a09..d3152e42 100644 --- a/apps/web/app/onboarding/mcp-form.tsx +++ b/apps/web/app/onboarding/mcp-form.tsx @@ -220,7 +220,7 @@ export function MCPForm() { <Button variant="link" size="lg" - className="text-black/40 font-medium! text-lg underline w-fit px-0! cursor-pointer" + className="text-white not-odd:font-medium! text-lg underline w-fit px-0! cursor-pointer" onClick={nextStep} > Continue @@ -238,7 +238,7 @@ export function MCPForm() { <Button variant="link" size="lg" - className="text-black/40 font-medium! text-lg underline w-fit px-0! cursor-pointer" + className="text-white font-medium! text-lg underline w-fit px-0! cursor-pointer" onClick={nextStep} > Skip For Now diff --git a/apps/web/app/onboarding/onboarding-background.tsx b/apps/web/app/onboarding/onboarding-background.tsx index ea9ba540..dce144ea 100644 --- a/apps/web/app/onboarding/onboarding-background.tsx +++ b/apps/web/app/onboarding/onboarding-background.tsx @@ -26,7 +26,6 @@ export function OnboardingBackground({ children }: OnboardingBackgroundProps) { backgroundPosition: "bottom", backgroundRepeat: "no-repeat", transform: `scale(${zoomScale})`, - transformOrigin: "center bottom", }} /> <div className="relative z-10 w-full max-w-4xl mx-auto">{children}</div> diff --git a/apps/web/components/chat-input.tsx b/apps/web/components/chat-input.tsx index c5fd0c5c..8a6edbf8 100644 --- a/apps/web/components/chat-input.tsx +++ b/apps/web/components/chat-input.tsx @@ -62,7 +62,7 @@ export function ChatInput() { className="w-full text-foreground placeholder-muted-foreground rounded-md outline-none resize-none text-base leading-relaxed px-6 py-4 bg-transparent" rows={2} /> - <div className="flex items-center gap-2 w-full justify-between bg-accent py-2 px-3 rounded-b-[14px]"> + <div className="flex items-center gap-2 w-full justify-between py-2 px-3 rounded-b-[14px]"> <ProjectSelector /> <Button onClick={handleSend} diff --git a/apps/web/components/create-project-dialog.tsx b/apps/web/components/create-project-dialog.tsx index 9a65b894..468a07d2 100644 --- a/apps/web/components/create-project-dialog.tsx +++ b/apps/web/components/create-project-dialog.tsx @@ -10,7 +10,6 @@ import { DialogTitle, } from "@repo/ui/components/dialog" import { Input } from "@repo/ui/components/input" -import { Label } from "@repo/ui/components/label" import { Loader2 } from "lucide-react" import { AnimatePresence, motion } from "motion/react" import { useState } from "react" @@ -47,7 +46,7 @@ export function CreateProjectDialog({ <AnimatePresence> {open && ( <Dialog onOpenChange={onOpenChange} open={open}> - <DialogContent className="sm:max-w-2xl bg-[#0f1419] backdrop-blur-xl border-white/10 text-white"> + <DialogContent className="sm:max-w-2xl backdrop-blur-xl"> <motion.div animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.95 }} @@ -55,7 +54,7 @@ export function CreateProjectDialog({ > <DialogHeader> <DialogTitle>Create New Project</DialogTitle> - <DialogDescription className="text-white/60"> + <DialogDescription> Give your project a unique name </DialogDescription> </DialogHeader> @@ -66,9 +65,7 @@ export function CreateProjectDialog({ initial={{ opacity: 0, y: 10 }} transition={{ delay: 0.1 }} > - <Label htmlFor="projectName">Project Name</Label> <Input - className="bg-white/5 border-white/10 text-white" id="projectName" onChange={(e) => setProjectName(e.target.value)} onKeyDown={(e) => { @@ -79,47 +76,31 @@ export function CreateProjectDialog({ placeholder="My Awesome Project" value={projectName} /> - <p className="text-xs text-white/50"> + <p className="text-xs"> This will help you organize your memories </p> </motion.div> </div> <DialogFooter> - <motion.div - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} + <Button onClick={handleClose} type="button" variant="outline"> + Cancel + </Button> + <Button + disabled={ + createProjectMutation.isPending || !projectName.trim() + } + onClick={handleCreate} + type="button" > - <Button - className="bg-white/5 hover:bg-white/10 border-white/10 text-white" - onClick={handleClose} - type="button" - variant="outline" - > - Cancel - </Button> - </motion.div> - <motion.div - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} - > - <Button - className="bg-white/10 hover:bg-white/20 text-white border-white/20" - disabled={ - createProjectMutation.isPending || !projectName.trim() - } - onClick={handleCreate} - type="button" - > - {createProjectMutation.isPending ? ( - <> - <Loader2 className="h-4 w-4 animate-spin mr-2" /> - Creating... - </> - ) : ( - "Create Project" - )} - </Button> - </motion.div> + {createProjectMutation.isPending ? ( + <> + <Loader2 className="h-4 w-4 animate-spin mr-2" /> + Creating... + </> + ) : ( + "Create Project" + )} + </Button> </DialogFooter> </motion.div> </DialogContent> diff --git a/apps/web/components/header.tsx b/apps/web/components/header.tsx index 2ea075d1..0d3682c0 100644 --- a/apps/web/components/header.tsx +++ b/apps/web/components/header.tsx @@ -6,11 +6,12 @@ import { Plus, SunIcon, MonitorIcon, - Network, User, CreditCard, Chrome, LogOut, + WaypointsIcon, + Gauge, } from "lucide-react" import { DropdownMenuContent, @@ -25,17 +26,19 @@ import { useAuth } from "@lib/auth-context" import { ConnectAIModal } from "./connect-ai-modal" import { useTheme } from "next-themes" import { cn } from "@lib/utils" -import { useRouter } from "next/navigation" +import { usePathname, useRouter } from "next/navigation" import { MCPIcon } from "./menu" import { authClient } from "@lib/auth" import { analytics } from "@/lib/analytics" -import { useGraphModal } from "@/stores" +import { useGraphModal, usePersistentChat } from "@/stores" export function Header({ onAddMemory }: { onAddMemory?: () => void }) { const { user } = useAuth() const { theme, setTheme } = useTheme() const router = useRouter() const { setIsOpen: setGraphModalOpen } = useGraphModal() + const { getCurrentChat } = usePersistentChat() + const pathname = usePathname() const handleSignOut = () => { analytics.userSignedOut() @@ -46,20 +49,31 @@ export function Header({ onAddMemory }: { onAddMemory?: () => void }) { return ( <div className="flex items-center justify-between w-full p-3 md:p-4"> <div className="flex items-center gap-2 md:gap-3 justify-between w-full"> - <Link - className="pointer-events-auto" - href={ - process.env.NODE_ENV === "development" - ? "http://localhost:3000" - : "https://app.supermemory.ai" - } - rel="noopener noreferrer" - > - <LogoFull className="h-8 hidden md:block" /> - <Logo className="h-8 md:hidden" /> - </Link> + <div className="flex items-center gap-1.5 md:gap-2"> + <Link + className="pointer-events-auto" + href={ + process.env.NODE_ENV === "development" + ? "http://localhost:3000" + : "https://app.supermemory.ai" + } + rel="noopener noreferrer" + > + {getCurrentChat()?.title && pathname.includes("/chat") ? ( + <div className="flex items-center gap-4"> + <Logo className="h-6 block text-foreground" /> + <span className="truncate">{getCurrentChat()?.title}</span> + </div> + ) : ( + <> + <LogoFull className="h-8 hidden md:block" /> + <Logo className="h-8 md:hidden text-foreground" /> + </> + )} + </Link> + </div> - <div className="flex items-center gap-1.5 md:gap-3"> + <div className="flex items-center gap-1.5 md:gap-2"> <Button variant="secondary" size="sm" @@ -76,15 +90,14 @@ export function Header({ onAddMemory }: { onAddMemory?: () => void }) { variant="ghost" size="sm" onClick={() => setGraphModalOpen(true)} - className="gap-1.5" > - <Network className="h-4 w-4" /> - <span className="hidden sm:inline">Graph View</span> + <WaypointsIcon className="h-5 w-5" /> + {/*<span className="hidden md:inline">Graph View</span>*/} </Button> <ConnectAIModal> <Button variant="ghost" size="sm" className="gap-1.5"> <MCPIcon className="h-4 w-4" /> - <span className="hidden lg:inline">Connect to AI (MCP)</span> + {/*<span className="hidden lg:inline">Connect to AI (MCP)</span>*/} </Button> </ConnectAIModal> <DropdownMenu> @@ -103,16 +116,22 @@ export function Header({ onAddMemory }: { onAddMemory?: () => void }) { </DropdownMenuLabel> <DropdownMenuSeparator /> <DropdownMenuItem onClick={() => router.push("/settings")}> - <User className="h-4 w-4 mr-2" /> + <User className="h-4 w-4" /> Profile </DropdownMenuItem> <DropdownMenuItem onClick={() => router.push("/settings/billing")} > - <CreditCard className="h-4 w-4 mr-2" /> + <CreditCard className="h-4 w-4" /> Billing </DropdownMenuItem> <DropdownMenuItem + onClick={() => router.push("/settings/integrations")} + > + <Gauge className="h-4 w-4" /> + Integrations + </DropdownMenuItem> + <DropdownMenuItem onClick={() => { window.open( "https://chromewebstore.google.com/detail/supermemory/afpgkkipfdpeaflnpoaffkcankadgjfc", @@ -121,7 +140,7 @@ export function Header({ onAddMemory }: { onAddMemory?: () => void }) { ) }} > - <Chrome className="h-4 w-4 mr-2" /> + <Chrome className="h-4 w-4" /> Chrome Extension </DropdownMenuItem> <DropdownMenuItem @@ -188,7 +207,7 @@ export function Header({ onAddMemory }: { onAddMemory?: () => void }) { </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem onClick={() => handleSignOut()}> - <LogOut className="h-4 w-4 mr-2" /> + <LogOut className="h-4 w-4" /> Logout </DropdownMenuItem> </DropdownMenuContent> diff --git a/apps/web/components/project-selector.tsx b/apps/web/components/project-selector.tsx index 0682a641..a492783b 100644 --- a/apps/web/components/project-selector.tsx +++ b/apps/web/components/project-selector.tsx @@ -25,7 +25,7 @@ import { SelectTrigger, SelectValue, } from "@repo/ui/components/select" -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" +import { useQuery } from "@tanstack/react-query" import { ChevronDown, FolderIcon, @@ -36,7 +36,6 @@ import { } from "lucide-react" import { AnimatePresence, motion } from "motion/react" import { useState } from "react" -import { toast } from "sonner" import { useProjectMutations } from "@/hooks/use-project-mutations" import { useProjectName } from "@/hooks/use-project-name" import { useProject } from "@/stores" @@ -52,7 +51,6 @@ interface Project { } export function ProjectSelector() { - const queryClient = useQueryClient() const [isOpen, setIsOpen] = useState(false) const [showCreateDialog, setShowCreateDialog] = useState(false) const { selectedProject } = useProject() @@ -69,13 +67,6 @@ export function ProjectSelector() { action: "move", targetProjectId: DEFAULT_PROJECT_ID, }) - const [expDialog, setExpDialog] = useState<{ - open: boolean - projectId: string - }>({ - open: false, - projectId: "", - }) const { data: projects = [], isLoading } = useQuery({ queryKey: ["projects"], @@ -91,30 +82,6 @@ export function ProjectSelector() { staleTime: 30 * 1000, }) - const enableExperimentalMutation = useMutation({ - mutationFn: async (projectId: string) => { - const response = await $fetch( - `@post/projects/${projectId}/enable-experimental`, - ) - if (response.error) { - throw new Error( - response.error?.message || "Failed to enable experimental mode", - ) - } - return response.data - }, - onSuccess: () => { - toast.success("Experimental mode enabled for project") - queryClient.invalidateQueries({ queryKey: ["projects"] }) - setExpDialog({ open: false, projectId: "" }) - }, - onError: (error) => { - toast.error("Failed to enable experimental mode", { - description: error instanceof Error ? error.message : "Unknown error", - }) - }, - }) - const handleProjectSelect = (containerTag: string) => { switchProject(containerTag) setIsOpen(false) @@ -138,7 +105,7 @@ export function ProjectSelector() { </span> <motion.div animate={{ rotate: isOpen ? 180 : 0 }} - transition={{ duration: 0.15 }} + transition={{ duration: 0.25 }} > <ChevronDown className="h-3 w-3" /> </motion.div> @@ -165,33 +132,30 @@ export function ProjectSelector() { <div className="p-1.5 max-h-64 overflow-y-auto"> <Button variant="ghost" - className={`flex items-center justify-between p-2 rounded-md transition-colors cursor-pointer ${ + className={`flex items-center w-full justify-between p-2 rounded-md transition-colors cursor-pointer ${ selectedProject === DEFAULT_PROJECT_ID ? "bg-accent" - : "hover:bg-accent/50" + : "hover:bg-accent/20" }`} onClick={() => handleProjectSelect(DEFAULT_PROJECT_ID)} > <div className="flex items-center gap-2"> <FolderIcon className="h-3.5 w-3.5" /> - <span className="text-xs font-medium">Default</span> + <span className="text-xs font-medium">Default Project</span> </div> </Button> {/* User Projects */} {projects .filter((p: Project) => p.containerTag !== DEFAULT_PROJECT_ID) - .map((project: Project, index: number) => ( - <motion.div + .map((project: Project) => ( + <div key={project.id} className={`flex items-center justify-between p-2 rounded-md transition-colors group ${ selectedProject === project.containerTag ? "bg-accent" : "hover:bg-accent/50" }`} - initial={{ opacity: 0, x: -5 }} - animate={{ opacity: 1, x: 0 }} - transition={{ delay: index * 0.03 }} > <button className="flex items-center gap-2 flex-1 cursor-pointer" @@ -208,45 +172,18 @@ export function ProjectSelector() { <div className="flex items-center gap-1"> <DropdownMenu> <DropdownMenuTrigger asChild> - <motion.button - className="p-1 hover:bg-accent rounded transition-all" + <Button + variant="ghost" + size="icon" + className="h-6 w-6" onClick={(e) => e.stopPropagation()} - whileHover={{ scale: 1.1 }} - whileTap={{ scale: 0.9 }} > <MoreHorizontal className="h-3 w-3" /> - </motion.button> + </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end"> - {/* Show experimental toggle only if NOT experimental and NOT default project */} - {!project.isExperimental && - project.containerTag !== DEFAULT_PROJECT_ID && ( - <DropdownMenuItem - className="text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300 cursor-pointer text-xs" - onClick={(e) => { - e.stopPropagation() - setExpDialog({ - open: true, - projectId: project.id, - }) - setIsOpen(false) - }} - > - <div className="h-3 w-3 mr-2 rounded border border-blue-600 dark:border-blue-400" /> - Enable Experimental Mode - </DropdownMenuItem> - )} - {project.isExperimental && ( - <DropdownMenuItem - className="text-blue-600/50 dark:text-blue-300/50 text-xs" - disabled - > - <div className="h-3 w-3 mr-2 rounded bg-blue-600 dark:bg-blue-400" /> - Experimental Mode Active - </DropdownMenuItem> - )} <DropdownMenuItem - className="text-red-600 dark:text-red-400 hover:text-red-500 dark:hover:text-red-300 cursor-pointer text-xs" + className="cursor-pointer text-xs hover:text-red-500" onClick={(e) => { e.stopPropagation() setDeleteDialog({ @@ -262,13 +199,13 @@ export function ProjectSelector() { setIsOpen(false) }} > - <Trash2 className="h-3 w-3 mr-2" /> + <Trash2 className="h-3 w-3" /> Delete Project </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </div> - </motion.div> + </div> ))} <motion.div @@ -489,82 +426,6 @@ export function ProjectSelector() { </Dialog> )} </AnimatePresence> - - {/* Experimental Mode Confirmation Dialog */} - <AnimatePresence> - {expDialog.open && ( - <Dialog - onOpenChange={(open) => setExpDialog({ ...expDialog, open })} - open={expDialog.open} - > - <DialogContent className="sm:max-w-lg"> - <motion.div - animate={{ opacity: 1, scale: 1 }} - className="flex flex-col gap-4" - exit={{ opacity: 0, scale: 0.95 }} - initial={{ opacity: 0, scale: 0.95 }} - > - <DialogHeader> - <DialogTitle>Enable Experimental Mode?</DialogTitle> - <DialogDescription> - Experimental mode enables beta features and advanced memory - relationships for this project. - <br /> - <br /> - <span className="text-yellow-600 dark:text-yellow-400 font-medium"> - Warning: - </span>{" "} - This action is{" "} - <span className="text-red-600 dark:text-red-400 font-bold"> - irreversible - </span> - . Once enabled, you cannot return to regular mode for this - project. - </DialogDescription> - </DialogHeader> - <DialogFooter> - <motion.div - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} - > - <Button - onClick={() => - setExpDialog({ open: false, projectId: "" }) - } - type="button" - variant="outline" - > - Cancel - </Button> - </motion.div> - <motion.div - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} - > - <Button - className="bg-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:hover:bg-blue-700 text-white" - disabled={enableExperimentalMutation.isPending} - onClick={() => - enableExperimentalMutation.mutate(expDialog.projectId) - } - type="button" - > - {enableExperimentalMutation.isPending ? ( - <> - <Loader2 className="h-4 w-4 animate-spin mr-2" /> - Enabling... - </> - ) : ( - "Enable Experimental Mode" - )} - </Button> - </motion.div> - </DialogFooter> - </motion.div> - </DialogContent> - </Dialog> - )} - </AnimatePresence> </div> ) } diff --git a/apps/web/components/views/add-memory/index.tsx b/apps/web/components/views/add-memory/index.tsx index d9c6aef8..19e02df1 100644 --- a/apps/web/components/views/add-memory/index.tsx +++ b/apps/web/components/views/add-memory/index.tsx @@ -1021,7 +1021,6 @@ export function AddMemoryView({ > <Label htmlFor="projectName">Project Name</Label> <Input - className="bg-white/5 border-white/10" id="projectName" onChange={(e) => setNewProjectName(e.target.value)} placeholder="My Awesome Project" diff --git a/packages/ui/assets/Logo.tsx b/packages/ui/assets/Logo.tsx index 805687d7..bb8800c8 100644 --- a/packages/ui/assets/Logo.tsx +++ b/packages/ui/assets/Logo.tsx @@ -16,7 +16,7 @@ export const Logo = ({ <title>supermemory Logo</title> <path d="M205.864 66.263h-76.401V0h-24.684v71.897c0 7.636 3.021 14.97 8.391 20.373l62.383 62.777 17.454-17.564-46.076-46.365h58.948v-24.84l-.015-.015ZM12.872 30.517l46.075 46.365H0v24.84h76.4v66.264h24.685V96.089c0-7.637-3.021-14.97-8.39-20.374l-62.37-62.762-17.453 17.564Z" - fill="#EFEFEF" + fill="currentColor" /> </svg> ); diff --git a/packages/ui/globals.css b/packages/ui/globals.css index c6c904c9..357e34b7 100644 --- a/packages/ui/globals.css +++ b/packages/ui/globals.css @@ -65,7 +65,7 @@ --destructive: oklch(0.6368 0.2078 25.3313); --border: oklch(0.9366 0.0017 247.8401); --input: oklch(0.9702 0 0); - --ring: oklch(1 0 0); + --ring: oklch(0 0 0); --chart-1: oklch(0.7197 0.1448 266.6983); --chart-2: oklch(0.8101 0.1488 148.2032); --chart-3: oklch(0.7507 0.1353 58.4182); @@ -125,7 +125,7 @@ --destructive: oklch(0.6368 0.2078 25.3313); --border: oklch(0.3715 0 0); --input: oklch(0.262 0.0074 285.8781); - --ring: oklch(0 0 0); + --ring: oklch(1 0 0); --chart-1: oklch(0.7197 0.1448 266.6983); --chart-2: oklch(0.8101 0.1488 148.2032); --chart-3: oklch(0.7507 0.1353 58.4182); |