"use client" import { useState, useRef, useCallback } from "react" import { dmSansClassName, dmSans125ClassName } from "@/lib/fonts" import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@ui/components/dialog" import { Button } from "@ui/components/button" import { cn } from "@lib/utils" import * as DialogPrimitive from "@radix-ui/react-dialog" import { XIcon, Download, Copy, Check } from "lucide-react" import { GradientLogo } from "@ui/assets/Logo" import { useAuth } from "@lib/auth-context" import { useLocalStorageUsername } from "@hooks/use-local-storage-username" import { toast } from "sonner" import * as htmlToImage from "html-to-image" type BackgroundTheme = "gradient" | "dark-gradient" | "black" interface ShareModalProps { isOpen: boolean onClose: () => void graphCanvasRef?: React.RefObject } // X/Twitter icon const XIcon2 = ({ className }: { className?: string }) => ( ) // LinkedIn icon const LinkedInIcon = ({ className }: { className?: string }) => ( ) // Instagram icon const InstagramIcon = ({ className }: { className?: string }) => ( ) // Background gradient overlay component const BackgroundGradient = ({ theme, className, }: { theme: BackgroundTheme className?: string }) => { if (theme === "black") { return (
{/* Dotted pattern */}
) } if (theme === "dark-gradient") { return (
{/* Base dark background */}
{/* Blue glow effect */}
{/* Dotted pattern */}
) } // Default: gradient theme (first screenshot) return (
{/* Base dark blue gradient */}
{/* Blue glow from bottom */}
{/* Dotted pattern */}
) } // Theme selector button const ThemeButton = ({ theme, isSelected, onClick, }: { theme: BackgroundTheme isSelected: boolean onClick: () => void }) => { const getPreviewContent = () => { if (theme === "black") { return
} if (theme === "dark-gradient") { return (
) } return (
) } return ( ) } // Social button component const SocialButton = ({ icon, onClick, label, }: { icon: React.ReactNode onClick: () => void label: string }) => ( ) export function ShareModal({ isOpen, onClose, graphCanvasRef, }: ShareModalProps) { const { user } = useAuth() const [selectedTheme, setSelectedTheme] = useState("gradient") const [isCopying, setIsCopying] = useState(false) const [copied, setCopied] = useState(false) const previewRef = useRef(null) const localStorageUsername = useLocalStorageUsername() const displayName = user?.displayUsername || localStorageUsername || user?.name || "" const userName = displayName ? `${displayName.split(" ")[0]}'s` : "Your" const capturePreview = useCallback(async (): Promise => { if (!previewRef.current) return null try { const dataUrl = await htmlToImage.toPng(previewRef.current, { pixelRatio: 2, quality: 1, }) // Convert data URL to blob const response = await fetch(dataUrl) const blob = await response.blob() return blob } catch (error) { console.error("Failed to capture preview:", error) return null } }, []) const handleCopySnapshot = useCallback(async () => { setIsCopying(true) try { const blob = await capturePreview() if (!blob) { throw new Error("Failed to capture image") } await navigator.clipboard.write([ new ClipboardItem({ "image/png": blob, }), ]) setCopied(true) toast.success("Snapshot copied to clipboard!") setTimeout(() => setCopied(false), 2000) } catch (error) { console.error("Failed to copy:", error) toast.error("Failed to copy snapshot. Try downloading instead.") } finally { setIsCopying(false) } }, [capturePreview]) const handleDownload = useCallback(async () => { try { const blob = await capturePreview() if (!blob) { throw new Error("Failed to capture image") } const url = URL.createObjectURL(blob) const a = document.createElement("a") a.href = url a.download = `supermemory-graph-${Date.now()}.png` document.body.appendChild(a) a.click() document.body.removeChild(a) URL.revokeObjectURL(url) toast.success("Snapshot downloaded!") } catch (error) { console.error("Failed to download:", error) toast.error("Failed to download snapshot") } }, [capturePreview]) const handleShareTwitter = useCallback(async () => { const text = encodeURIComponent( "Check out my knowledge graph on supermemory! 🧠\n\nhttps://supermemory.ai", ) window.open(`https://twitter.com/intent/tweet?text=${text}`, "_blank") }, []) const handleShareLinkedIn = useCallback(async () => { const url = encodeURIComponent("https://supermemory.ai") window.open( `https://www.linkedin.com/sharing/share-offsite/?url=${url}`, "_blank", ) }, []) const handleShareInstagram = useCallback(async () => { // Instagram doesn't have a direct share URL, so we'll download and show a message await handleDownload() toast.info("Image downloaded! You can now share it on Instagram.") }, [handleDownload]) const handleClose = () => { onClose() } return ( !open && handleClose()}>
{/* Header */}
Share snapshot of your supermemory Close
{/* Preview area */}
{/* Branding header */}
{userName} supermemory
{/* Graph canvas placeholder - will show the actual graph */}
{graphCanvasRef?.current ? ( Memory graph ) : (
Graph preview will appear here
)}
{/* Bottom controls */}
{/* Theme selectors */}
setSelectedTheme("gradient")} /> setSelectedTheme("dark-gradient")} /> setSelectedTheme("black")} />
{/* Action buttons */}
} onClick={handleDownload} label="Download" /> } onClick={handleShareTwitter} label="Share on X" /> } onClick={handleShareLinkedIn} label="Share on LinkedIn" /> } onClick={handleShareInstagram} label="Share on Instagram" />
) }