diff options
| author | Mahesh Sanikommmu <[email protected]> | 2025-08-23 00:38:57 -0700 |
|---|---|---|
| committer | Mahesh Sanikommmu <[email protected]> | 2025-08-23 00:38:57 -0700 |
| commit | 3816666e2d9b5eaa6d8a0d0f0c838ede41a69f44 (patch) | |
| tree | 92ad10b35b9b9a07155304b560a283b53602a16c /apps/web/components | |
| parent | fix: env vars (diff) | |
| download | supermemory-3816666e2d9b5eaa6d8a0d0f0c838ede41a69f44.tar.xz supermemory-3816666e2d9b5eaa6d8a0d0f0c838ede41a69f44.zip | |
ui (memory detail): improved memory detail view and open chat
Diffstat (limited to 'apps/web/components')
| -rw-r--r-- | apps/web/components/memories/index.tsx | 53 | ||||
| -rw-r--r-- | apps/web/components/memories/memory-detail.tsx | 375 | ||||
| -rw-r--r-- | apps/web/components/memory-list-view.tsx | 497 |
3 files changed, 435 insertions, 490 deletions
diff --git a/apps/web/components/memories/index.tsx b/apps/web/components/memories/index.tsx new file mode 100644 index 00000000..97ef57bd --- /dev/null +++ b/apps/web/components/memories/index.tsx @@ -0,0 +1,53 @@ +import type { DocumentWithMemories } from "@ui/memory-graph/types"; + +export const formatDate = (date: string | Date) => { + const dateObj = new Date(date); + const now = new Date(); + const currentYear = now.getFullYear(); + const dateYear = dateObj.getFullYear(); + + const monthNames = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ]; + const month = monthNames[dateObj.getMonth()]; + const day = dateObj.getDate(); + + const getOrdinalSuffix = (n: number) => { + const s = ["th", "st", "nd", "rd"]; + const v = n % 100; + return n + (s[(v - 20) % 10] || s[v] || s[0]!); + }; + + const formattedDay = getOrdinalSuffix(day); + + if (dateYear !== currentYear) { + return `${month} ${formattedDay}, ${dateYear}`; + } + + return `${month} ${formattedDay}`; +}; + +export const getSourceUrl = (document: DocumentWithMemories) => { + if (document.type === "google_doc" && document.customId) { + return `https://docs.google.com/document/d/${document.customId}`; + } + if (document.type === "google_sheet" && document.customId) { + return `https://docs.google.com/spreadsheets/d/${document.customId}`; + } + if (document.type === "google_slide" && document.customId) { + return `https://docs.google.com/presentation/d/${document.customId}`; + } + // Fallback to existing URL for all other document types + return document.url; +};
\ No newline at end of file diff --git a/apps/web/components/memories/memory-detail.tsx b/apps/web/components/memories/memory-detail.tsx new file mode 100644 index 00000000..eeef6d89 --- /dev/null +++ b/apps/web/components/memories/memory-detail.tsx @@ -0,0 +1,375 @@ +import { getDocumentIcon } from '@/lib/document-icon'; +import { + Drawer, + DrawerContent, + DrawerHeader, + DrawerTitle, +} from '@repo/ui/components/drawer'; +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, +} from '@repo/ui/components/sheet'; +import { colors } from '@repo/ui/memory-graph/constants'; +import type { DocumentsWithMemoriesResponseSchema } from '@repo/validation/api'; +import { Badge } from '@ui/components/badge'; +import { Brain, Calendar, ExternalLink, Sparkles } from 'lucide-react'; +import { memo, useState } from 'react'; +import type { z } from 'zod'; +import { formatDate, getSourceUrl } from '.'; +import { Label1Regular } from '@ui/text/label/label-1-regular'; + +type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>; +type DocumentWithMemories = DocumentsResponse['documents'][0]; +type MemoryEntry = DocumentWithMemories['memoryEntries'][0]; + +const formatDocumentType = (type: string) => { + // Special case for PDF + if (type.toLowerCase() === 'pdf') return 'PDF'; + + // Replace underscores with spaces and capitalize each word + return type + .split('_') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) + .join(' '); +}; + +const MemoryDetailItem = memo(({ memory }: { memory: MemoryEntry }) => { + return ( + <button + className="p-4 rounded-lg transition-all relative overflow-hidden cursor-pointer" + style={{ + backgroundColor: memory.isLatest + ? colors.memory.primary + : 'rgba(255, 255, 255, 0.02)', + }} + tabIndex={0} + type="button" + > + <div className="flex items-start gap-2 relative z-10"> + <div + className="p-1 rounded" + style={{ + backgroundColor: memory.isLatest + ? colors.memory.secondary + : 'transparent', + }} + > + <Brain + className={`w-4 h-4 flex-shrink-0 transition-all ${ + memory.isLatest ? 'text-blue-400' : 'text-blue-400/50' + }`} + /> + </div> + <div className="flex-1 space-y-2"> + <Label1Regular + className="text-sm leading-relaxed text-left" + style={{ color: colors.text.primary }} + > + {memory.memory} + </Label1Regular> + <div className="flex gap-2 justify-between"> + <div + className="flex items-center gap-4 text-xs" + style={{ color: colors.text.muted }} + > + <span className="flex items-center gap-1"> + <Calendar className="w-3 h-3" /> + {formatDate(memory.createdAt)} + </span> + <span className="font-mono">v{memory.version}</span> + {memory.sourceRelevanceScore && ( + <span + className="flex items-center gap-1" + style={{ + color: + memory.sourceRelevanceScore > 70 + ? colors.accent.emerald + : colors.text.muted, + }} + > + <Sparkles className="w-3 h-3" /> + {memory.sourceRelevanceScore}% + </span> + )} + </div> + <div className="flex items-center gap-2 flex-wrap"> + {memory.isForgotten && ( + <Badge + className="text-xs border-red-500/30 backdrop-blur-sm" + style={{ + backgroundColor: colors.status.forgotten, + color: '#dc2626', + backdropFilter: 'blur(4px)', + WebkitBackdropFilter: 'blur(4px)', + }} + variant="destructive" + > + Forgotten + </Badge> + )} + {memory.isLatest && ( + <Badge + className="text-xs" + style={{ + backgroundColor: colors.memory.secondary, + color: colors.text.primary, + backdropFilter: 'blur(4px)', + WebkitBackdropFilter: 'blur(4px)', + }} + variant="default" + > + Latest + </Badge> + )} + {memory.forgetAfter && ( + <Badge + className="text-xs backdrop-blur-sm" + style={{ + color: colors.status.expiring, + backgroundColor: 'rgba(251, 165, 36, 0.1)', + backdropFilter: 'blur(4px)', + WebkitBackdropFilter: 'blur(4px)', + }} + variant="outline" + > + Expires: {formatDate(memory.forgetAfter)} + </Badge> + )} + </div> + </div> + </div> + </div> + </button> + ); +}); + +export const MemoryDetail = memo( + ({ + document, + isOpen, + onClose, + isMobile, + }: { + document: DocumentWithMemories | null; + isOpen: boolean; + onClose: () => void; + isMobile: boolean; + }) => { + if (!document) return null; + + const [isSummaryExpanded, setIsSummaryExpanded] = useState(false); + const activeMemories = document.memoryEntries.filter((m) => !m.isForgotten); + const forgottenMemories = document.memoryEntries.filter( + (m) => m.isForgotten + ); + + const HeaderContent = ({ + TitleComponent, + }: { + TitleComponent: typeof SheetTitle | typeof DrawerTitle; + }) => ( + <div className="flex items-start justify-between gap-2"> + <div className="flex items-start gap-3 flex-1"> + <div + className="p-2 rounded-lg" + style={{ + backgroundColor: colors.background.secondary, + }} + > + {getDocumentIcon(document.type, 'w-5 h-5')} + </div> + <div className="flex-1"> + <TitleComponent style={{ color: colors.text.primary }}> + {document.title || 'Untitled Document'} + </TitleComponent> + <div + className="flex items-center gap-2 mt-1 text-xs" + style={{ color: colors.text.muted }} + > + <span>{formatDocumentType(document.type)}</span> + <span>•</span> + <span>{formatDate(document.createdAt)}</span> + {document.url && ( + <> + <span>•</span> + <button + className="flex items-center gap-1 transition-all hover:gap-2" + onClick={() => { + const sourceUrl = getSourceUrl(document); + window.open(sourceUrl ?? undefined, '_blank'); + }} + style={{ color: colors.accent.primary }} + type="button" + > + View source + <ExternalLink className="w-3 h-3" /> + </button> + </> + )} + </div> + </div> + </div> + </div> + ); + + const SummarySection = () => { + if (!document.summary) return null; + + const shouldShowToggle = document.summary.length > 200; // Show toggle for longer summaries + + return ( + <div + className="mt-4 p-3 rounded-lg" + style={{ + backgroundColor: 'rgba(255, 255, 255, 0.03)', + border: '1px solid rgba(255, 255, 255, 0.08)', + }} + > + <p + className={`text-sm ${!isSummaryExpanded ? 'line-clamp-3' : ''}`} + style={{ color: colors.text.muted }} + > + {document.content} + </p> + {shouldShowToggle && ( + <button + onClick={() => setIsSummaryExpanded(!isSummaryExpanded)} + className="mt-2 text-xs hover:underline transition-all" + style={{ color: colors.accent.primary }} + type="button" + > + {isSummaryExpanded ? 'Show less' : 'Show more'} + </button> + )} + </div> + ); + }; + + const MemoryContent = () => ( + <div className="space-y-6 px-6"> + {activeMemories.length > 0 && ( + <div> + <div + className="text-sm font-medium mb-2 flex items-start gap-2 py-2" + style={{ + color: colors.text.secondary, + }} + > + Active Memories ({activeMemories.length}) + </div> + <div className="space-y-3"> + {activeMemories.map((memory, index) => ( + <div + key={memory.id} + > + <MemoryDetailItem memory={memory} /> + </div> + ))} + </div> + </div> + )} + + {forgottenMemories.length > 0 && ( + <div> + <div + className="text-sm font-medium mb-4 px-3 py-2 rounded-lg opacity-60" + style={{ + color: colors.text.muted, + backgroundColor: 'rgba(255, 255, 255, 0.02)', + }} + > + Forgotten Memories ({forgottenMemories.length}) + </div> + <div className="space-y-3 opacity-40"> + {forgottenMemories.map((memory) => ( + <MemoryDetailItem key={memory.id} memory={memory} /> + ))} + </div> + </div> + )} + + {activeMemories.length === 0 && forgottenMemories.length === 0 && ( + <div + className="text-center py-12 rounded-lg" + style={{ + backgroundColor: 'rgba(255, 255, 255, 0.02)', + }} + > + <Brain + className="w-12 h-12 mx-auto mb-4 opacity-30" + style={{ color: colors.text.muted }} + /> + <p style={{ color: colors.text.muted }}> + No memories found for this document + </p> + </div> + )} + </div> + ); + + if (isMobile) { + return ( + <Drawer onOpenChange={onClose} open={isOpen}> + <DrawerContent + className="border-0 p-0 overflow-hidden max-h-[90vh]" + style={{ + backgroundColor: colors.background.secondary, + borderTop: `1px solid ${colors.document.border}`, + backdropFilter: 'blur(20px)', + WebkitBackdropFilter: 'blur(20px)', + }} + > + {/* Header section with glass effect */} + <div + className="p-4 relative border-b" + style={{ + backgroundColor: 'rgba(255, 255, 255, 0.02)', + borderBottom: `1px solid ${colors.document.border}`, + }} + > + <DrawerHeader className="pb-0 px-0 text-left"> + <HeaderContent TitleComponent={DrawerTitle} /> + </DrawerHeader> + + <SummarySection /> + </div> + + <div className="flex-1 memory-drawer-scroll overflow-y-auto"> + <MemoryContent /> + </div> + </DrawerContent> + </Drawer> + ); + } + + return ( + <Sheet onOpenChange={onClose} open={isOpen}> + <SheetContent + className="w-full sm:max-w-2xl border-0 p-0 overflow-hidden" + style={{ + backgroundColor: colors.background.secondary, + }} + > + <div + className="p-6 relative" + style={{ + backgroundColor: 'rgba(255, 255, 255, 0.02)', + }} + > + <SheetHeader className="pb-0"> + <HeaderContent TitleComponent={SheetTitle} /> + </SheetHeader> + + <SummarySection /> + </div> + + <div className="h-[calc(100vh-200px)] memory-sheet-scroll overflow-y-auto"> + <MemoryContent /> + </div> + </SheetContent> + </Sheet> + ); + } +); diff --git a/apps/web/components/memory-list-view.tsx b/apps/web/components/memory-list-view.tsx index 8269562a..2cff96fd 100644 --- a/apps/web/components/memory-list-view.tsx +++ b/apps/web/components/memory-list-view.tsx @@ -2,42 +2,14 @@ import { useIsMobile } from "@hooks/use-mobile"; import { cn } from "@lib/utils"; -import { - GoogleDocs, - GoogleDrive, - GoogleSheets, - GoogleSlides, - MicrosoftExcel, - MicrosoftOneNote, - MicrosoftPowerpoint, - MicrosoftWord, - NotionDoc, - OneDrive, - PDF, -} from "@repo/ui/assets/icons"; import { Badge } from "@repo/ui/components/badge"; import { Card, CardContent, CardHeader } from "@repo/ui/components/card"; -import { - Drawer, - DrawerContent, - DrawerHeader, - DrawerTitle, -} from "@repo/ui/components/drawer"; -import { - Sheet, - SheetContent, - SheetHeader, - SheetTitle, -} from "@repo/ui/components/sheet"; import { colors } from "@repo/ui/memory-graph/constants"; import type { DocumentsWithMemoriesResponseSchema } from "@repo/validation/api"; import { useVirtualizer } from "@tanstack/react-virtual"; -import { Label1Regular } from "@ui/text/label/label-1-regular"; import { Brain, - Calendar, ExternalLink, - FileText, Sparkles, } from "lucide-react"; import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -45,9 +17,12 @@ import type { z } from "zod"; import useResizeObserver from "@/hooks/use-resize-observer"; import { analytics } from "@/lib/analytics"; +import { MemoryDetail } from "./memories/memory-detail"; +import { getDocumentIcon } from "@/lib/document-icon"; +import { formatDate, getSourceUrl } from "./memories"; + type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>; type DocumentWithMemories = DocumentsResponse["documents"][0]; -type MemoryEntry = DocumentWithMemories["memoryEntries"][0]; interface MemoryListViewProps { children?: React.ReactNode; @@ -85,222 +60,6 @@ const GreetingMessage = memo(() => { ); }); -const formatDate = (date: string | Date) => { - const dateObj = new Date(date); - const now = new Date(); - const currentYear = now.getFullYear(); - const dateYear = dateObj.getFullYear(); - - const monthNames = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ]; - const month = monthNames[dateObj.getMonth()]; - const day = dateObj.getDate(); - - const getOrdinalSuffix = (n: number) => { - const s = ["th", "st", "nd", "rd"]; - const v = n % 100; - return n + (s[(v - 20) % 10] || s[v] || s[0]!); - }; - - const formattedDay = getOrdinalSuffix(day); - - if (dateYear !== currentYear) { - return `${month} ${formattedDay}, ${dateYear}`; - } - - return `${month} ${formattedDay}`; -}; - -const formatDocumentType = (type: string) => { - // Special case for PDF - if (type.toLowerCase() === "pdf") return "PDF"; - - // Replace underscores with spaces and capitalize each word - return type - .split("_") - .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) - .join(" "); -}; - -const getDocumentIcon = (type: string, className: string) => { - const iconProps = { - className, - style: { color: colors.text.muted }, - }; - - switch (type) { - case "google_doc": - return <GoogleDocs {...iconProps} />; - case "google_sheet": - return <GoogleSheets {...iconProps} />; - case "google_slide": - return <GoogleSlides {...iconProps} />; - case "google_drive": - return <GoogleDrive {...iconProps} />; - case "notion": - case "notion_doc": - return <NotionDoc {...iconProps} />; - case "word": - case "microsoft_word": - return <MicrosoftWord {...iconProps} />; - case "excel": - case "microsoft_excel": - return <MicrosoftExcel {...iconProps} />; - case "powerpoint": - case "microsoft_powerpoint": - return <MicrosoftPowerpoint {...iconProps} />; - case "onenote": - case "microsoft_onenote": - return <MicrosoftOneNote {...iconProps} />; - case "onedrive": - return <OneDrive {...iconProps} />; - case "pdf": - return <PDF {...iconProps} />; - default: - return <FileText {...iconProps} />; - } -}; - -const getSourceUrl = (document: DocumentWithMemories) => { - if (document.type === "google_doc" && document.customId) { - return `https://docs.google.com/document/d/${document.customId}`; - } - if (document.type === "google_sheet" && document.customId) { - return `https://docs.google.com/spreadsheets/d/${document.customId}`; - } - if (document.type === "google_slide" && document.customId) { - return `https://docs.google.com/presentation/d/${document.customId}`; - } - // Fallback to existing URL for all other document types - return document.url; -}; - -const MemoryDetailItem = memo(({ memory }: { memory: MemoryEntry }) => { - return ( - <button - className="p-4 rounded-lg border transition-all relative overflow-hidden cursor-pointer" - style={{ - backgroundColor: memory.isLatest - ? colors.memory.primary - : "rgba(255, 255, 255, 0.02)", - borderColor: memory.isLatest - ? colors.memory.border - : "rgba(255, 255, 255, 0.1)", - backdropFilter: "blur(8px)", - WebkitBackdropFilter: "blur(8px)", - }} - tabIndex={0} - type="button" - > - <div className="flex items-start gap-2 relative z-10"> - <div - className="p-1 rounded" - style={{ - backgroundColor: memory.isLatest - ? colors.memory.secondary - : "transparent", - }} - > - <Brain - className={`w-4 h-4 flex-shrink-0 transition-all ${ - memory.isLatest ? "text-blue-400" : "text-blue-400/50" - }`} - /> - </div> - <div className="flex-1 space-y-2"> - <Label1Regular - className="text-sm leading-relaxed text-left" - style={{ color: colors.text.primary }} - > - {memory.memory} - </Label1Regular> - <div className="flex items-center gap-2 flex-wrap"> - {memory.isForgotten && ( - <Badge - className="text-xs border-red-500/30 backdrop-blur-sm" - style={{ - backgroundColor: colors.status.forgotten, - color: "#dc2626", - backdropFilter: "blur(4px)", - WebkitBackdropFilter: "blur(4px)", - }} - variant="destructive" - > - Forgotten - </Badge> - )} - {memory.isLatest && ( - <Badge - className="text-xs border-blue-400/30 backdrop-blur-sm" - style={{ - backgroundColor: colors.memory.secondary, - color: colors.accent.primary, - backdropFilter: "blur(4px)", - WebkitBackdropFilter: "blur(4px)", - }} - variant="default" - > - Latest - </Badge> - )} - {memory.forgetAfter && ( - <Badge - className="text-xs backdrop-blur-sm" - style={{ - borderColor: colors.status.expiring, - color: colors.status.expiring, - backgroundColor: "rgba(251, 165, 36, 0.1)", - backdropFilter: "blur(4px)", - WebkitBackdropFilter: "blur(4px)", - }} - variant="outline" - > - Expires: {formatDate(memory.forgetAfter)} - </Badge> - )} - </div> - <div - className="flex items-center gap-4 text-xs" - style={{ color: colors.text.muted }} - > - <span className="flex items-center gap-1"> - <Calendar className="w-3 h-3" /> - {formatDate(memory.createdAt)} - </span> - <span className="font-mono">v{memory.version}</span> - {memory.sourceRelevanceScore && ( - <span - className="flex items-center gap-1" - style={{ - color: - memory.sourceRelevanceScore > 70 - ? colors.accent.emerald - : colors.text.muted, - }} - > - <Sparkles className="w-3 h-3" /> - {memory.sourceRelevanceScore}% - </span> - )} - </div> - </div> - </div> - </button> - ); -}); - const DocumentCard = memo( ({ document, @@ -361,12 +120,12 @@ const DocumentCard = memo( </div> </CardHeader> <CardContent className="relative z-10 px-0"> - {document.summary && ( + {document.content && ( <p className="text-xs line-clamp-2 mb-3" style={{ color: colors.text.muted }} > - {document.summary} + {document.content} </p> )} <div className="flex items-center gap-2 flex-wrap"> @@ -402,248 +161,6 @@ const DocumentCard = memo( }, ); -const DocumentDetailSheet = memo( - ({ - document, - isOpen, - onClose, - isMobile, - }: { - document: DocumentWithMemories | null; - isOpen: boolean; - onClose: () => void; - isMobile: boolean; - }) => { - if (!document) return null; - - const [isSummaryExpanded, setIsSummaryExpanded] = useState(false); - const activeMemories = document.memoryEntries.filter((m) => !m.isForgotten); - const forgottenMemories = document.memoryEntries.filter( - (m) => m.isForgotten, - ); - - const HeaderContent = ({ - TitleComponent, - }: { - TitleComponent: typeof SheetTitle | typeof DrawerTitle; - }) => ( - <div className="flex items-start justify-between gap-2"> - <div className="flex items-start gap-3 flex-1"> - <div - className="p-2 rounded-lg" - style={{ - backgroundColor: colors.document.secondary, - border: `1px solid ${colors.document.border}`, - }} - > - {getDocumentIcon(document.type, "w-5 h-5")} - </div> - <div className="flex-1"> - <TitleComponent style={{ color: colors.text.primary }}> - {document.title || "Untitled Document"} - </TitleComponent> - <div - className="flex items-center gap-2 mt-1 text-xs" - style={{ color: colors.text.muted }} - > - <span>{formatDocumentType(document.type)}</span> - <span>•</span> - <span>{formatDate(document.createdAt)}</span> - {document.url && ( - <> - <span>•</span> - <button - className="flex items-center gap-1 transition-all hover:gap-2" - onClick={() => { - const sourceUrl = getSourceUrl(document); - window.open(sourceUrl ?? undefined, "_blank"); - }} - style={{ color: colors.accent.primary }} - type="button" - > - View source - <ExternalLink className="w-3 h-3" /> - </button> - </> - )} - </div> - </div> - </div> - </div> - ); - - const SummarySection = () => { - if (!document.summary) return null; - - const shouldShowToggle = document.summary.length > 200; // Show toggle for longer summaries - - return ( - <div - className="mt-4 p-3 rounded-lg" - style={{ - backgroundColor: "rgba(255, 255, 255, 0.03)", - border: "1px solid rgba(255, 255, 255, 0.08)", - }} - > - <p - className={`text-sm ${!isSummaryExpanded ? "line-clamp-3" : ""}`} - style={{ color: colors.text.muted }} - > - {document.summary} - </p> - {shouldShowToggle && ( - <button - onClick={() => setIsSummaryExpanded(!isSummaryExpanded)} - className="mt-2 text-xs hover:underline transition-all" - style={{ color: colors.accent.primary }} - type="button" - > - {isSummaryExpanded ? "Show less" : "Show more"} - </button> - )} - </div> - ); - }; - - const MemoryContent = () => ( - <div className="p-6 space-y-6"> - {activeMemories.length > 0 && ( - <div> - <div - className="text-sm font-medium mb-4 flex items-start gap-2 px-3 py-2 rounded-lg" - style={{ - color: colors.text.secondary, - backgroundColor: colors.memory.primary, - border: `1px solid ${colors.memory.border}`, - }} - > - <Brain className="w-4 h-4 text-blue-400" /> - Active Memories ({activeMemories.length}) - </div> - <div className="space-y-3"> - {activeMemories.map((memory, index) => ( - <div - className="animate-in fade-in slide-in-from-right-2" - key={memory.id} - style={{ animationDelay: `${index * 50}ms` }} - > - <MemoryDetailItem memory={memory} /> - </div> - ))} - </div> - </div> - )} - - {forgottenMemories.length > 0 && ( - <div> - <div - className="text-sm font-medium mb-4 px-3 py-2 rounded-lg opacity-60" - style={{ - color: colors.text.muted, - backgroundColor: "rgba(255, 255, 255, 0.02)", - border: "1px solid rgba(255, 255, 255, 0.08)", - }} - > - Forgotten Memories ({forgottenMemories.length}) - </div> - <div className="space-y-3 opacity-40"> - {forgottenMemories.map((memory) => ( - <MemoryDetailItem key={memory.id} memory={memory} /> - ))} - </div> - </div> - )} - - {activeMemories.length === 0 && forgottenMemories.length === 0 && ( - <div - className="text-center py-12 rounded-lg" - style={{ - backgroundColor: "rgba(255, 255, 255, 0.02)", - border: "1px solid rgba(255, 255, 255, 0.08)", - }} - > - <Brain - className="w-12 h-12 mx-auto mb-4 opacity-30" - style={{ color: colors.text.muted }} - /> - <p style={{ color: colors.text.muted }}> - No memories found for this document - </p> - </div> - )} - </div> - ); - - if (isMobile) { - return ( - <Drawer onOpenChange={onClose} open={isOpen}> - <DrawerContent - className="border-0 p-0 overflow-hidden max-h-[90vh]" - style={{ - backgroundColor: colors.background.secondary, - borderTop: `1px solid ${colors.document.border}`, - backdropFilter: "blur(20px)", - WebkitBackdropFilter: "blur(20px)", - }} - > - {/* Header section with glass effect */} - <div - className="p-4 relative border-b" - style={{ - backgroundColor: "rgba(255, 255, 255, 0.02)", - borderBottom: `1px solid ${colors.document.border}`, - }} - > - <DrawerHeader className="pb-0 px-0 text-left"> - <HeaderContent TitleComponent={DrawerTitle} /> - </DrawerHeader> - - <SummarySection /> - </div> - - <div className="flex-1 memory-drawer-scroll overflow-y-auto"> - <MemoryContent /> - </div> - </DrawerContent> - </Drawer> - ); - } - - return ( - <Sheet onOpenChange={onClose} open={isOpen}> - <SheetContent - className="w-full sm:max-w-2xl border-0 p-0 overflow-hidden" - style={{ - backgroundColor: colors.background.secondary, - borderLeft: `1px solid ${colors.document.border}`, - backdropFilter: "blur(20px)", - WebkitBackdropFilter: "blur(20px)", - }} - > - {/* Header section with glass effect */} - <div - className="p-6 relative" - style={{ - backgroundColor: "rgba(255, 255, 255, 0.02)", - borderBottom: `1px solid ${colors.document.border}`, - }} - > - <SheetHeader className="pb-0"> - <HeaderContent TitleComponent={SheetTitle} /> - </SheetHeader> - - <SummarySection /> - </div> - - <div className="h-[calc(100vh-200px)] memory-sheet-scroll overflow-y-auto"> - <MemoryContent /> - </div> - </SheetContent> - </Sheet> - ); - }, -); - export const MemoryListView = ({ children, documents, @@ -831,7 +348,7 @@ export const MemoryListView = ({ )} </div> - <DocumentDetailSheet + <MemoryDetail document={selectedDocument} isOpen={isDetailOpen} onClose={handleCloseDetails} |