aboutsummaryrefslogtreecommitdiff
path: root/apps/web/components
diff options
context:
space:
mode:
authorMaheshtheDev <[email protected]>2025-10-04 21:38:13 +0000
committerMaheshtheDev <[email protected]>2025-10-04 21:38:13 +0000
commit583c2651b68ad29f4c335bd004fa0c7dfa8f25b3 (patch)
tree0ad62a692edc4de562a38819ab874d8f7cc88009 /apps/web/components
parentfix: model names (diff)
downloadsupermemory-583c2651b68ad29f4c335bd004fa0c7dfa8f25b3.tar.xz
supermemory-583c2651b68ad29f4c335bd004fa0c7dfa8f25b3.zip
feat: url cards as content preview with rich details (#452)
Improved memory detail UI with better document icons and layout and Added dark mode support to the Chrome extension button ### What changed? - Enhanced the WebsiteCard component with an `onOpenDetails` prop - Improved the MemoryDetail component with: - Better layout for document headers and source links - Enhanced content scrolling with proper height constraints - Improved spacing and padding in various sections - Added favicon support to document icons, showing website favicons for webpage documents - Fixed document type detection for webpages and URLs - Added dark mode support to the Chrome extension button component with appropriate color classes [Screen Recording 2025-10-03 at 11.34.01 PM.mov <span class="graphite__hidden">(uploaded via Graphite)</span> <img class="graphite__hidden" src="https://app.graphite.dev/user-attachments/thumbnails/2f6ceef2-43a2-4e11-bafa-0f3ce614696b.mov" />](https://app.graphite.dev/user-attachments/video/2f6ceef2-43a2-4e11-bafa-0f3ce614696b.mov)
Diffstat (limited to 'apps/web/components')
-rw-r--r--apps/web/components/chrome-extension-button.tsx28
-rw-r--r--apps/web/components/content-cards/website.tsx4
-rw-r--r--apps/web/components/header.tsx6
-rw-r--r--apps/web/components/masonry-memory-list.tsx1
-rw-r--r--apps/web/components/memories-utils/memory-detail.tsx52
-rw-r--r--apps/web/components/memory-list-view.tsx5
6 files changed, 50 insertions, 46 deletions
diff --git a/apps/web/components/chrome-extension-button.tsx b/apps/web/components/chrome-extension-button.tsx
index 5fd58cac..2b2ca713 100644
--- a/apps/web/components/chrome-extension-button.tsx
+++ b/apps/web/components/chrome-extension-button.tsx
@@ -130,42 +130,42 @@ export function ChromeExtensionButton() {
<div className="px-6 py-2 pb-4 space-y-4">
<div className="flex items-start gap-3">
- <div className="w-10 h-10 bg-blue-50 border border-blue-200 rounded-lg flex items-center justify-center flex-shrink-0">
- <TwitterIcon className="fill-blue-500 text-blue-500" />
+ <div className="w-10 h-10 bg-blue-50 dark:bg-blue-950 border border-blue-200 dark:border-blue-800 rounded-lg flex items-center justify-center flex-shrink-0">
+ <TwitterIcon className="fill-blue-500 dark:fill-blue-400 text-blue-500 dark:text-blue-400" />
</div>
<div>
- <h3 className="font-semibold text-sm text-gray-800">
+ <h3 className="font-semibold text-sm text-foreground">
Twitter Imports
</h3>
- <p className="text-xs text-gray-600">
+ <p className="text-xs text-muted-foreground">
Import your twitter timeline & save tweets.
</p>
</div>
</div>
<div className="flex items-start gap-3">
- <div className="w-10 h-10 bg-orange-50 border border-orange-200 rounded-lg flex items-center justify-center flex-shrink-0">
- <Bookmark className="w-5 h-5 text-orange-600" />
+ <div className="w-10 h-10 bg-orange-50 dark:bg-orange-950 border border-orange-200 dark:border-orange-800 rounded-lg flex items-center justify-center flex-shrink-0">
+ <Bookmark className="w-5 h-5 text-orange-600 dark:text-orange-400" />
</div>
<div>
- <h3 className="font-semibold text-sm text-gray-800">
+ <h3 className="font-semibold text-sm text-foreground">
Save All Bookmarks
</h3>
- <p className="text-xs text-gray-600">
+ <p className="text-xs text-muted-foreground">
Instantly save any webpage to your memory.
</p>
</div>
</div>
<div className="flex items-start gap-3">
- <div className="w-10 h-10 bg-green-50 border border-green-200 rounded-lg flex items-center justify-center flex-shrink-0">
- <Zap className="w-5 h-5 text-green-600" />
+ <div className="w-10 h-10 bg-green-50 dark:bg-green-950 border border-green-200 dark:border-green-800 rounded-lg flex items-center justify-center flex-shrink-0">
+ <Zap className="w-5 h-5 text-green-600 dark:text-green-400" />
</div>
<div>
- <h3 className="font-semibold text-sm text-gray-800">
+ <h3 className="font-semibold text-sm text-foreground">
Charge Empty Memory
</h3>
- <p className="text-xs text-gray-600">
+ <p className="text-xs text-muted-foreground">
Automatically capture & organize your browsing history.
</p>
</div>
@@ -175,7 +175,7 @@ export function ChromeExtensionButton() {
<div className="px-6 pb-4">
<Button
onClick={handleInstall}
- className="w-full bg-white border border-[#686CFD] text-gray-800 hover:bg-gray-50 font-semibold rounded-lg h-10 flex items-center justify-center gap-3"
+ className="w-full bg-background border border-primary text-foreground hover:bg-accent font-semibold rounded-lg h-10 flex items-center justify-center gap-3"
>
<div className="w-6 h-6 bg-[#686CFD] rounded-full flex items-center justify-center">
<Image
@@ -189,7 +189,7 @@ export function ChromeExtensionButton() {
</Button>
</div>
- <div className="px-6 pb-4 flex items-center justify-center gap-6 text-xs text-gray-500">
+ <div className="px-6 pb-4 flex items-center justify-center gap-6 text-xs text-muted-foreground">
<div className="flex items-center gap-1">
<Users className="w-3 h-3" />
<span>4K+ users</span>
diff --git a/apps/web/components/content-cards/website.tsx b/apps/web/components/content-cards/website.tsx
index b3ee7df6..f0e614c9 100644
--- a/apps/web/components/content-cards/website.tsx
+++ b/apps/web/components/content-cards/website.tsx
@@ -25,6 +25,7 @@ interface WebsiteCardProps {
description?: string
className?: string
onClick?: () => void
+ onOpenDetails?: () => void
onDelete?: () => void
showExternalLink?: boolean
}
@@ -36,6 +37,7 @@ export const WebsiteCard = ({
description,
className,
onClick,
+ onOpenDetails,
onDelete,
showExternalLink = true,
}: WebsiteCardProps) => {
@@ -44,6 +46,8 @@ export const WebsiteCard = ({
const handleCardClick = () => {
if (onClick) {
onClick()
+ } else if (onOpenDetails) {
+ onOpenDetails()
} else {
window.open(url, "_blank", "noopener,noreferrer")
}
diff --git a/apps/web/components/header.tsx b/apps/web/components/header.tsx
index c055e94d..2ea075d1 100644
--- a/apps/web/components/header.tsx
+++ b/apps/web/components/header.tsx
@@ -142,7 +142,7 @@ export function Header({ onAddMemory }: { onAddMemory?: () => void }) {
<MonitorIcon
className={cn(
theme === "system"
- ? "text-primay-foreground"
+ ? "text-primary-foreground"
: "text-muted-foreground",
"h-3 w-3 group-hover:text-foreground",
)}
@@ -160,7 +160,7 @@ export function Header({ onAddMemory }: { onAddMemory?: () => void }) {
<SunIcon
className={cn(
theme === "light"
- ? "text-primay-foreground"
+ ? "text-primary-foreground"
: "text-muted-foreground",
"h-3 w-3 group-hover:text-foreground",
)}
@@ -178,7 +178,7 @@ export function Header({ onAddMemory }: { onAddMemory?: () => void }) {
<MoonIcon
className={cn(
theme === "dark"
- ? "text-primay-foreground"
+ ? "text-primary-foreground"
: "text-muted-foreground",
"h-3 w-3 group-hover:text-foreground",
)}
diff --git a/apps/web/components/masonry-memory-list.tsx b/apps/web/components/masonry-memory-list.tsx
index 93326e49..0511a061 100644
--- a/apps/web/components/masonry-memory-list.tsx
+++ b/apps/web/components/masonry-memory-list.tsx
@@ -89,6 +89,7 @@ const DocumentCard = memo(
url={document.url}
title={document.title || "Untitled Document"}
image={document.ogImage}
+ onOpenDetails={() => onOpenDetails(document)}
onDelete={() => onDelete(document)}
/>
)
diff --git a/apps/web/components/memories-utils/memory-detail.tsx b/apps/web/components/memories-utils/memory-detail.tsx
index 8f238731..378d3f79 100644
--- a/apps/web/components/memories-utils/memory-detail.tsx
+++ b/apps/web/components/memories-utils/memory-detail.tsx
@@ -28,6 +28,7 @@ import type { z } from "zod"
import { formatDate, getSourceUrl } from "."
import { Label1Regular } from "@ui/text/label/label-1-regular"
import { HTMLContentRenderer } from "./html-content-renderer"
+import { Button } from "@ui/components/button"
type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>
type DocumentWithMemories = DocumentsResponse["documents"][0]
@@ -141,11 +142,13 @@ export const MemoryDetail = memo(
TitleComponent: typeof DialogTitle | typeof DrawerTitle
}) => (
<div className="flex items-start justify-between gap-2">
- <div className="flex items-start gap-2 md:gap-3 flex-1 min-w-0">
+ <div className="flex items-end gap-2 md:gap-3 flex-1 min-w-0">
<div className="p-1.5 md:p-2 rounded-lg bg-muted/10 flex-shrink-0">
{getDocumentIcon(
document.type,
"w-4 h-4 md:w-5 md:h-5 text-foreground",
+ document.source ?? undefined,
+ document.url ?? undefined,
)}
</div>
<div className="flex-1 min-w-0">
@@ -156,25 +159,24 @@ export const MemoryDetail = memo(
<span>{formatDocumentType(document.type)}</span>
<span>•</span>
<span>{formatDate(document.createdAt)}</span>
- {document.url && (
- <>
- <span>•</span>
- <button
- className="flex items-center gap-0.5 md:gap-1 transition-all hover:gap-1 md:hover:gap-2 text-primary hover:text-primary/80 whitespace-nowrap"
- onClick={() => {
- const sourceUrl = getSourceUrl(document)
- window.open(sourceUrl ?? undefined, "_blank")
- }}
- type="button"
- >
- <span className="hidden sm:inline">View source</span>
- <span className="sm:hidden">Source</span>
- <ExternalLink className="w-2.5 h-2.5 md:w-3 md:h-3" />
- </button>
- </>
- )}
</div>
</div>
+ {document.url && (
+ <div className="flex items-end">
+ <Button
+ onClick={() => {
+ const sourceUrl = getSourceUrl(document)
+ window.open(sourceUrl ?? undefined, "_blank")
+ }}
+ variant="secondary"
+ size="sm"
+ >
+ <span className="hidden sm:inline">visit source</span>
+ <span className="sm:hidden">Source</span>
+ <ExternalLink className="w-2.5 h-2.5 md:w-3 md:h-3" />
+ </Button>
+ </div>
+ )}
</div>
</div>
)
@@ -227,10 +229,10 @@ export const MemoryDetail = memo(
<div className="space-y-6">
{activeMemories.length > 0 && (
<div>
- <div className="text-sm font-medium mb-2 flex items-start gap-2 py-2 text-muted-foreground">
+ <div className="text-sm font-medium flex items-start gap-2 pb-2 text-muted-foreground">
Active Memories ({activeMemories.length})
</div>
- <div className="space-y-3">
+ <div className="space-y-3 max-h-[80vh] overflow-y-auto custom-scrollbar">
{activeMemories.map((memory) => (
<div key={memory.id}>
<MemoryDetailItem memory={memory} />
@@ -281,7 +283,7 @@ export const MemoryDetail = memo(
Content
</h4>
</div>
- <div className="p-3 md:p-4">
+ <div className="p-3 md:p-4 m-4">
<ContentDisplaySection />
</div>
</div>
@@ -324,8 +326,8 @@ export const MemoryDetail = memo(
<div className="flex-1 flex flex-col lg:flex-row overflow-hidden">
<div className="flex-1 flex flex-col h-full justify-between min-w-0">
- <div className="p-2 px-3 md:px-4 overflow-y-auto custom-scrollbar transition-all duration-300">
- <h3 className="font-medium text-[10px] md:text-xs text-muted-foreground uppercase pb-1 px-1">
+ <div className="p-2 px-3 md:pl-4 overflow-y-auto custom-scrollbar transition-all duration-300">
+ <h3 className="font-medium text-[10px] md:text-sm text-muted-foreground pb-2 px-1">
Content
</h3>
<ContentDisplaySection />
@@ -370,9 +372,9 @@ export const MemoryDetail = memo(
</div>
</div>
- <div className="w-full lg:w-96 flex flex-col border-t lg:border-t-0 lg:border-l border-border">
+ <div className="w-full lg:w-96 flex flex-col border-t lg:border-t-0 border-border">
<div className="flex-1 flex flex-col">
- <div className="flex-1 memory-dialog-scroll overflow-y-auto p-3 md:p-4">
+ <div className="flex-1 memory-dialog-scroll overflow-y-auto p-2 md:p-3">
<MemoryContent />
</div>
</div>
diff --git a/apps/web/components/memory-list-view.tsx b/apps/web/components/memory-list-view.tsx
index c2b4b0c8..02667147 100644
--- a/apps/web/components/memory-list-view.tsx
+++ b/apps/web/components/memory-list-view.tsx
@@ -294,10 +294,7 @@ export const MemoryListView = ({
// Always render with consistent structure
return (
<>
- <div
- className="h-full overflow-hidden relative pb-20"
- ref={containerRef}
- >
+ <div className="h-full overflow-hidden relative pb-20" ref={containerRef}>
{error ? (
<div className="h-full flex items-center justify-center p-4">
<div className="rounded-xl overflow-hidden">