aboutsummaryrefslogtreecommitdiff
path: root/apps/web/app
diff options
context:
space:
mode:
authorMahesh Sanikommmu <[email protected]>2025-08-23 00:38:57 -0700
committerMahesh Sanikommmu <[email protected]>2025-08-23 00:38:57 -0700
commit3816666e2d9b5eaa6d8a0d0f0c838ede41a69f44 (patch)
tree92ad10b35b9b9a07155304b560a283b53602a16c /apps/web/app
parentfix: env vars (diff)
downloadsupermemory-3816666e2d9b5eaa6d8a0d0f0c838ede41a69f44.tar.xz
supermemory-3816666e2d9b5eaa6d8a0d0f0c838ede41a69f44.zip
ui (memory detail): improved memory detail view and open chat
Diffstat (limited to 'apps/web/app')
-rw-r--r--apps/web/app/page.tsx556
1 files changed, 278 insertions, 278 deletions
diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx
index 335d79e3..d6edc122 100644
--- a/apps/web/app/page.tsx
+++ b/apps/web/app/page.tsx
@@ -388,284 +388,284 @@ const MemoryGraphPage = () => {
}, []);
return (
- <div className="relative h-screen bg-[#0f1419] overflow-hidden touch-none">
- {/* Main content area */}
- <motion.div
- animate={{
- marginRight: isOpen && !isMobile ? 600 : 0,
- }}
- className="h-full relative"
- transition={{
- duration: 0.2,
- ease: [0.4, 0, 0.2, 1], // Material Design easing - snappy but smooth
- }}
- >
- <motion.div
- animate={{ opacity: 1, y: 0 }}
- className="absolute md:top-4 md:right-4 md:bottom-auto md:left-auto bottom-8 left-6 z-20 rounded-xl overflow-hidden"
- id={TOUR_STEP_IDS.VIEW_TOGGLE}
- initial={{ opacity: 0, y: -20 }}
- transition={{ type: "spring", stiffness: 300, damping: 25 }}
- >
- <GlassMenuEffect rounded="rounded-xl" />
- <div className="relative z-10 p-2 flex gap-1">
- <motion.button
- animate={{
- color: viewMode === "graph" ? "#93c5fd" : "#cbd5e1",
- }}
- className="relative h-8 px-3 flex items-center gap-2 text-sm font-medium rounded-md transition-colors"
- onClick={() => handleViewModeChange("graph")}
- transition={{ duration: 0.2 }}
- whileHover={{ scale: 1.02 }}
- whileTap={{ scale: 0.98 }}
- >
- {viewMode === "graph" && (
- <motion.div
- className="absolute inset-0 bg-blue-500/20 rounded-md"
- layoutId="activeBackground"
- transition={{
- type: "spring",
- stiffness: 400,
- damping: 30,
- }}
- />
- )}
- <span className="relative z-10 flex items-center gap-2">
- <LayoutGrid className="w-4 h-4" />
- <span className="hidden md:inline">Graph</span>
- </span>
- </motion.button>
-
- <motion.button
- animate={{
- color: viewMode === "list" ? "#93c5fd" : "#cbd5e1",
- }}
- className="relative h-8 px-3 flex items-center gap-2 text-sm font-medium rounded-md transition-colors"
- onClick={() => handleViewModeChange("list")}
- transition={{ duration: 0.2 }}
- whileHover={{ scale: 1.02 }}
- whileTap={{ scale: 0.98 }}
- >
- {viewMode === "list" && (
- <motion.div
- className="absolute inset-0 bg-blue-500/20 rounded-md"
- layoutId="activeBackground"
- transition={{
- type: "spring",
- stiffness: 400,
- damping: 30,
- }}
- />
- )}
- <span className="relative z-10 flex items-center gap-2">
- <List className="w-4 h-4" />
- <span className="hidden md:inline">List</span>
- </span>
- </motion.button>
- </div>
- </motion.div>
-
- {/* Animated content switching */}
- <AnimatePresence mode="wait">
- {viewMode === "graph" ? (
- <motion.div
- animate={{ opacity: 1, scale: 1 }}
- className="absolute inset-0"
- exit={{ opacity: 0, scale: 0.95 }}
- id={TOUR_STEP_IDS.MEMORY_GRAPH}
- initial={{ opacity: 0, scale: 0.95 }}
- key="graph"
- transition={{
- type: "spring",
- stiffness: 500,
- damping: 30,
- }}
- >
- <MemoryGraph
- documents={allDocuments}
- error={error}
- hasMore={hasMore}
- isLoading={isPending}
- isLoadingMore={isLoadingMore}
- legendId={TOUR_STEP_IDS.LEGEND}
- loadMoreDocuments={loadMoreDocuments}
- showSpacesSelector={false}
- totalLoaded={totalLoaded}
- variant="consumer"
- highlightDocumentIds={allHighlightDocumentIds}
- highlightsVisible={isOpen}
- occludedRightPx={isOpen && !isMobile ? 600 : 0}
- autoLoadOnViewport={false}
- isExperimental={isCurrentProjectExperimental}
- >
- <div className="absolute inset-0 flex items-center justify-center">
- <div className="rounded-xl overflow-hidden">
- <div className="relative z-10 text-slate-200 px-6 py-4 text-center">
- <p className="text-lg font-medium mb-2">
- No Memories to Visualize
- </p>
- <button
- type="button"
- className="text-sm text-blue-400 hover:text-blue-300 transition-colors cursor-pointer underline"
- onClick={() => setShowAddMemoryView(true)}
- >
- Create one?
- </button>
- </div>
- </div>
- </div>
- </MemoryGraph>
- </motion.div>
- ) : (
- <motion.div
- animate={{ opacity: 1, scale: 1 }}
- className="absolute inset-0 md:ml-18"
- exit={{ opacity: 0, scale: 0.95 }}
- id={TOUR_STEP_IDS.MEMORY_LIST}
- initial={{ opacity: 0, scale: 0.95 }}
- key="list"
- transition={{
- type: "spring",
- stiffness: 500,
- damping: 30,
- }}
- >
- <MemoryListView
- documents={allDocuments}
- error={error}
- hasMore={hasMore}
- isLoading={isPending}
- isLoadingMore={isLoadingMore}
- loadMoreDocuments={loadMoreDocuments}
- totalLoaded={totalLoaded}
- >
- <div className="absolute inset-0 flex items-center justify-center">
- <div className="rounded-xl overflow-hidden">
- <div className="relative z-10 text-slate-200 px-6 py-4 text-center">
- <p className="text-lg font-medium mb-2">
- No Memories to Visualize
- </p>
- <button
- className="text-sm text-blue-400 hover:text-blue-300 transition-colors cursor-pointer underline"
- onClick={() => setShowAddMemoryView(true)}
- type="button"
- >
- Create one?
- </button>
- </div>
- </div>
- </div>
- </MemoryListView>
- </motion.div>
- )}
- </AnimatePresence>
-
- {/* Top Bar */}
- <div className="absolute top-2 left-0 right-0 z-10 p-4 flex items-center justify-between">
- <div className="flex items-center gap-3 justify-between w-full md:w-fit md:justify-start">
- <Link
- className="pointer-events-auto"
- href="https://supermemory.ai"
- rel="noopener noreferrer"
- target="_blank"
- >
- <LogoFull
- className="h-8 hidden md:block"
- id={TOUR_STEP_IDS.LOGO}
- />
- <Logo className="h-8 md:hidden" id={TOUR_STEP_IDS.LOGO} />
- </Link>
-
- <div className="hidden sm:block">
- <ProjectSelector />
- </div>
-
- <ConnectAIModal>
- <Button
- variant="outline"
- size="sm"
- className="bg-white/5 hover:bg-white/10 border-white/20 text-white hover:text-white px-2 sm:px-3"
- >
- <Unplug className="h-4 w-4" />
- <span className="hidden sm:inline ml-2">
- Connect to your AI
- </span>
- <span className="sm:hidden ml-1">Connect AI</span>
- </Button>
- </ConnectAIModal>
- </div>
-
- <div>
- <Menu />
- </div>
- </div>
-
- {/* Floating Open Chat Button */}
- {!isOpen && !isMobile && (
- <motion.div
- animate={{ opacity: 1, scale: 1 }}
- className="fixed bottom-6 right-6 z-50"
- initial={{ opacity: 0, scale: 0.8 }}
- transition={{
- type: "spring",
- stiffness: 300,
- damping: 25,
- }}
- >
- <Button
- className="h-14 px-4 bg-blue-600 hover:bg-blue-700 text-white shadow-lg hover:shadow-xl transition-all duration-200 rounded-full flex items-center gap-2"
- onClick={() => setIsOpen(true)}
- size="lg"
- >
- <MessageSquare className="h-5 w-5" />
- <span className="font-medium">Open Chat</span>
- </Button>
- </motion.div>
- )}
- </motion.div>
-
- {/* Chat panel - positioned absolutely */}
- <motion.div
- className="fixed top-0 right-0 h-full z-50 md:z-auto"
- style={{
- width: isOpen ? (isMobile ? "100vw" : "600px") : 0,
- pointerEvents: isOpen ? "auto" : "none",
- }}
- id={TOUR_STEP_IDS.FLOATING_CHAT}
- >
- <motion.div
- animate={{ x: isOpen ? 0 : isMobile ? "100%" : 600 }}
- className="absolute inset-0"
- exit={{ x: isMobile ? "100%" : 600 }}
- initial={{ x: isMobile ? "100%" : 600 }}
- key="chat"
- transition={{
- type: "spring",
- stiffness: 500,
- damping: 40,
- }}
- >
- <ChatRewrite />
- </motion.div>
- </motion.div>
-
- {showAddMemoryView && (
- <AddMemoryView
- initialTab="note"
- onClose={() => setShowAddMemoryView(false)}
- />
- )}
-
- {/* Tour Alert Dialog */}
- <TourAlertDialog onOpenChange={setShowTourDialog} open={showTourDialog} />
-
- {/* Referral/Upgrade Modal */}
- <ReferralUpgradeModal
- isOpen={showReferralModal}
- onClose={() => setShowReferralModal(false)}
- />
- </div>
- );
+ <div className="relative h-screen bg-[#0f1419] overflow-hidden touch-none">
+ {/* Main content area */}
+ <motion.div
+ animate={{
+ marginRight: isOpen && !isMobile ? 600 : 0,
+ }}
+ className="h-full relative"
+ transition={{
+ duration: 0.2,
+ ease: [0.4, 0, 0.2, 1], // Material Design easing - snappy but smooth
+ }}
+ >
+ <motion.div
+ animate={{ opacity: 1, y: 0 }}
+ className="absolute md:top-4 md:right-4 md:bottom-auto md:left-auto bottom-8 left-6 z-20 rounded-xl overflow-hidden"
+ id={TOUR_STEP_IDS.VIEW_TOGGLE}
+ initial={{ opacity: 0, y: -20 }}
+ transition={{ type: 'spring', stiffness: 300, damping: 25 }}
+ >
+ <GlassMenuEffect rounded="rounded-xl" />
+ <div className="relative z-10 p-2 flex gap-1">
+ <motion.button
+ animate={{
+ color: viewMode === 'graph' ? '#93c5fd' : '#cbd5e1',
+ }}
+ className="relative h-8 px-3 flex items-center gap-2 text-sm font-medium rounded-md transition-colors"
+ onClick={() => handleViewModeChange('graph')}
+ transition={{ duration: 0.2 }}
+ whileHover={{ scale: 1.02 }}
+ whileTap={{ scale: 0.98 }}
+ >
+ {viewMode === 'graph' && (
+ <motion.div
+ className="absolute inset-0 bg-blue-500/20 rounded-md"
+ layoutId="activeBackground"
+ transition={{
+ type: 'spring',
+ stiffness: 400,
+ damping: 30,
+ }}
+ />
+ )}
+ <span className="relative z-10 flex items-center gap-2">
+ <LayoutGrid className="w-4 h-4" />
+ <span className="hidden md:inline">Graph</span>
+ </span>
+ </motion.button>
+
+ <motion.button
+ animate={{
+ color: viewMode === 'list' ? '#93c5fd' : '#cbd5e1',
+ }}
+ className="relative h-8 px-3 flex items-center gap-2 text-sm font-medium rounded-md transition-colors"
+ onClick={() => handleViewModeChange('list')}
+ transition={{ duration: 0.2 }}
+ whileHover={{ scale: 1.02 }}
+ whileTap={{ scale: 0.98 }}
+ >
+ {viewMode === 'list' && (
+ <motion.div
+ className="absolute inset-0 bg-blue-500/20 rounded-md"
+ layoutId="activeBackground"
+ transition={{
+ type: 'spring',
+ stiffness: 400,
+ damping: 30,
+ }}
+ />
+ )}
+ <span className="relative z-10 flex items-center gap-2">
+ <List className="w-4 h-4" />
+ <span className="hidden md:inline">List</span>
+ </span>
+ </motion.button>
+ </div>
+ </motion.div>
+
+ {/* Animated content switching */}
+ <AnimatePresence mode="wait">
+ {viewMode === 'graph' ? (
+ <motion.div
+ animate={{ opacity: 1, scale: 1 }}
+ className="absolute inset-0"
+ exit={{ opacity: 0, scale: 0.95 }}
+ id={TOUR_STEP_IDS.MEMORY_GRAPH}
+ initial={{ opacity: 0, scale: 0.95 }}
+ key="graph"
+ transition={{
+ type: 'spring',
+ stiffness: 500,
+ damping: 30,
+ }}
+ >
+ <MemoryGraph
+ documents={allDocuments}
+ error={error}
+ hasMore={hasMore}
+ isLoading={isPending}
+ isLoadingMore={isLoadingMore}
+ legendId={TOUR_STEP_IDS.LEGEND}
+ loadMoreDocuments={loadMoreDocuments}
+ showSpacesSelector={false}
+ totalLoaded={totalLoaded}
+ variant="consumer"
+ highlightDocumentIds={allHighlightDocumentIds}
+ highlightsVisible={isOpen}
+ occludedRightPx={isOpen && !isMobile ? 600 : 0}
+ autoLoadOnViewport={false}
+ isExperimental={isCurrentProjectExperimental}
+ >
+ <div className="absolute inset-0 flex items-center justify-center">
+ <div className="rounded-xl overflow-hidden">
+ <div className="relative z-10 text-slate-200 px-6 py-4 text-center">
+ <p className="text-lg font-medium mb-2">
+ No Memories to Visualize
+ </p>
+ <button
+ type="button"
+ className="text-sm text-blue-400 hover:text-blue-300 transition-colors cursor-pointer underline"
+ onClick={() => setShowAddMemoryView(true)}
+ >
+ Create one?
+ </button>
+ </div>
+ </div>
+ </div>
+ </MemoryGraph>
+ </motion.div>
+ ) : (
+ <motion.div
+ animate={{ opacity: 1, scale: 1 }}
+ className="absolute inset-0 md:ml-18"
+ exit={{ opacity: 0, scale: 0.95 }}
+ id={TOUR_STEP_IDS.MEMORY_LIST}
+ initial={{ opacity: 0, scale: 0.95 }}
+ key="list"
+ transition={{
+ type: 'spring',
+ stiffness: 500,
+ damping: 30,
+ }}
+ >
+ <MemoryListView
+ documents={allDocuments}
+ error={error}
+ hasMore={hasMore}
+ isLoading={isPending}
+ isLoadingMore={isLoadingMore}
+ loadMoreDocuments={loadMoreDocuments}
+ totalLoaded={totalLoaded}
+ >
+ <div className="absolute inset-0 flex items-center justify-center">
+ <div className="rounded-xl overflow-hidden">
+ <div className="relative z-10 text-slate-200 px-6 py-4 text-center">
+ <p className="text-lg font-medium mb-2">
+ No Memories to Visualize
+ </p>
+ <button
+ className="text-sm text-blue-400 hover:text-blue-300 transition-colors cursor-pointer underline"
+ onClick={() => setShowAddMemoryView(true)}
+ type="button"
+ >
+ Create one?
+ </button>
+ </div>
+ </div>
+ </div>
+ </MemoryListView>
+ </motion.div>
+ )}
+ </AnimatePresence>
+
+ {/* Top Bar */}
+ <div className="absolute top-2 left-0 right-0 z-10 p-4 flex items-center justify-between">
+ <div className="flex items-center gap-3 justify-between w-full md:w-fit md:justify-start">
+ <Link
+ className="pointer-events-auto"
+ href="https://supermemory.ai"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <LogoFull
+ className="h-8 hidden md:block"
+ id={TOUR_STEP_IDS.LOGO}
+ />
+ <Logo className="h-8 md:hidden" id={TOUR_STEP_IDS.LOGO} />
+ </Link>
+
+ <div className="hidden sm:block">
+ <ProjectSelector />
+ </div>
+
+ <ConnectAIModal>
+ <Button
+ variant="outline"
+ size="sm"
+ className="bg-white/5 hover:bg-white/10 border-white/20 text-white hover:text-white px-2 sm:px-3"
+ >
+ <Unplug className="h-4 w-4" />
+ <span className="hidden sm:inline ml-2">
+ Connect to your AI
+ </span>
+ <span className="sm:hidden ml-1">Connect AI</span>
+ </Button>
+ </ConnectAIModal>
+ </div>
+
+ <div>
+ <Menu />
+ </div>
+ </div>
+
+ {/* Floating Open Chat Button */}
+ {!isOpen && !isMobile && (
+ <motion.div
+ animate={{ opacity: 1, scale: 1 }}
+ className="fixed bottom-6 right-6 z-50"
+ initial={{ opacity: 0, scale: 0.8 }}
+ transition={{
+ type: 'spring',
+ stiffness: 300,
+ damping: 25,
+ }}
+ >
+ <Button
+ className="px-4 bg-white hover:bg-white/80 text-[#001A39] shadow-lg hover:shadow-xl transition-all duration-200 rounded-full flex items-center gap-2 cursor-pointer"
+ onClick={() => setIsOpen(true)}
+ size="lg"
+ >
+ <MessageSquare className="h-5 w-5" />
+ <span className="font-medium">Open Chat</span>
+ </Button>
+ </motion.div>
+ )}
+ </motion.div>
+
+ {/* Chat panel - positioned absolutely */}
+ <motion.div
+ className="fixed top-0 right-0 h-full z-50 md:z-auto"
+ style={{
+ width: isOpen ? (isMobile ? '100vw' : '600px') : 0,
+ pointerEvents: isOpen ? 'auto' : 'none',
+ }}
+ id={TOUR_STEP_IDS.FLOATING_CHAT}
+ >
+ <motion.div
+ animate={{ x: isOpen ? 0 : isMobile ? '100%' : 600 }}
+ className="absolute inset-0"
+ exit={{ x: isMobile ? '100%' : 600 }}
+ initial={{ x: isMobile ? '100%' : 600 }}
+ key="chat"
+ transition={{
+ type: 'spring',
+ stiffness: 500,
+ damping: 40,
+ }}
+ >
+ <ChatRewrite />
+ </motion.div>
+ </motion.div>
+
+ {showAddMemoryView && (
+ <AddMemoryView
+ initialTab="note"
+ onClose={() => setShowAddMemoryView(false)}
+ />
+ )}
+
+ {/* Tour Alert Dialog */}
+ <TourAlertDialog onOpenChange={setShowTourDialog} open={showTourDialog} />
+
+ {/* Referral/Upgrade Modal */}
+ <ReferralUpgradeModal
+ isOpen={showReferralModal}
+ onClose={() => setShowReferralModal(false)}
+ />
+ </div>
+ );
};
// Wrapper component to handle auth and waitlist checks