mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-05-21 18:45:03 +00:00
192 lines
5.6 KiB
TypeScript
192 lines
5.6 KiB
TypeScript
"use client"
|
|
|
|
import { CHROME_EXTENSION_URL } from "@repo/lib/constants"
|
|
import { useState } from "react"
|
|
import { Button } from "@ui/components/button"
|
|
import { MCPDetailView } from "@/components/mcp-modal/mcp-detail-view"
|
|
import { XBookmarksDetailView } from "@/components/onboarding/x-bookmarks-detail-view"
|
|
import { useRouter } from "next/navigation"
|
|
import { cn } from "@lib/utils"
|
|
import { dmSansClassName } from "@/lib/fonts"
|
|
import { useOrgOnboarding } from "@hooks/use-org-onboarding"
|
|
import { analytics } from "@/lib/analytics"
|
|
|
|
const integrationCards = [
|
|
{
|
|
title: "Capture",
|
|
description: "Add the Chrome extension for one-click saves",
|
|
icon: (
|
|
<div className="rounded-full flex items-center justify-center">
|
|
<img
|
|
src="/onboarding/chrome.png"
|
|
alt="Chrome"
|
|
className="w-20 h-auto"
|
|
/>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
title: "Connect to AI",
|
|
description: "Set up once and use your memory in Cursor, Claude, etc",
|
|
icon: (
|
|
<div className="rounded flex items-center justify-center">
|
|
<img src="/onboarding/mcp.png" alt="MCP" className="size-28 h-auto" />
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
title: "Connect",
|
|
description: "Link Notion, Google Drive, or OneDrive to import your docs",
|
|
icon: (
|
|
<div className="rounded flex items-center justify-center">
|
|
<img
|
|
src="/onboarding/connectors.png"
|
|
alt="Connectors"
|
|
className="w-20 h-auto"
|
|
/>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
title: "Import",
|
|
description:
|
|
"Bring in X/Twitter bookmarks, and turn them into useful memories",
|
|
icon: (
|
|
<div className="rounded flex items-center justify-center">
|
|
<img src="/onboarding/x.png" alt="X" className="size-14" />
|
|
</div>
|
|
),
|
|
},
|
|
]
|
|
|
|
export function IntegrationsStep() {
|
|
const router = useRouter()
|
|
const [selectedCard, setSelectedCard] = useState<string | null>(null)
|
|
const { markOrgOnboarded } = useOrgOnboarding()
|
|
|
|
const handleContinue = () => {
|
|
markOrgOnboarded()
|
|
analytics.onboardingCompleted()
|
|
router.push("/")
|
|
}
|
|
|
|
if (selectedCard === "Connect to AI") {
|
|
return <MCPDetailView onBack={() => setSelectedCard(null)} />
|
|
}
|
|
if (selectedCard === "Import") {
|
|
return <XBookmarksDetailView onBack={() => setSelectedCard(null)} />
|
|
}
|
|
return (
|
|
<div className="flex flex-col items-center justify-center h-full p-8">
|
|
<div className="text-center mb-6 flex flex-col items-center justify-center space-y-2">
|
|
<h1 className="text-white text-[32px] font-medium">
|
|
Build your personal memory
|
|
</h1>
|
|
<p
|
|
className={cn(
|
|
"text-white text-sm opacity-60 max-w-xs",
|
|
dmSansClassName(),
|
|
)}
|
|
>
|
|
Your supermemory comes alive when you <br /> capture and connect
|
|
what's important
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-3 max-w-lg w-full mb-12">
|
|
{integrationCards.map((card) => {
|
|
const isClickable =
|
|
card.title === "Connect to AI" ||
|
|
card.title === "Capture" ||
|
|
card.title === "Import"
|
|
|
|
if (isClickable) {
|
|
return (
|
|
<button
|
|
key={card.title}
|
|
type="button"
|
|
className={cn(
|
|
"bg-[#080B0F] relative rounded-lg p-3 hover:border-[#3374FF] hover:border-[0.1px] transition-colors duration-300 border-[0.1px] border-[#0D121A] cursor-pointer text-left w-full hover:bg-[url('/onboarding/bg-gradient-1.png')] hover:bg-[length:175%_auto] hover:bg-[center_top_2rem] hover:bg-no-repeat",
|
|
"hover:border-b-0 border-b-0",
|
|
)}
|
|
onClick={() => {
|
|
if (card.title === "Capture") {
|
|
analytics.onboardingChromeExtensionClicked({
|
|
source: "onboarding",
|
|
})
|
|
window.open(CHROME_EXTENSION_URL, "_blank")
|
|
} else {
|
|
analytics.onboardingIntegrationClicked({
|
|
integration: card.title,
|
|
})
|
|
if (card.title === "Connect to AI") {
|
|
analytics.onboardingMcpDetailOpened()
|
|
} else if (card.title === "Import") {
|
|
analytics.onboardingXBookmarksDetailOpened()
|
|
}
|
|
setSelectedCard(card.title)
|
|
}
|
|
}}
|
|
>
|
|
<div className="flex-1 mt-10">
|
|
<h3 className="text-white text-sm font-medium">
|
|
{card.title}
|
|
</h3>
|
|
<p
|
|
className={cn(
|
|
"text-[#8B8B8B] text-xs leading-relaxed",
|
|
dmSansClassName(),
|
|
)}
|
|
>
|
|
{card.description}
|
|
</p>
|
|
</div>
|
|
<div className="absolute top-0 right-0">{card.icon}</div>
|
|
</button>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div
|
|
key={card.title}
|
|
className={cn(
|
|
"bg-[#080B0F] relative rounded-lg p-3 hover:border-[#3374FF] hover:border-[0.1px] transition-colors duration-300 border-[0.1px] border-[#0D121A] hover:bg-[url('/onboarding/bg-gradient-1.png')] hover:bg-[length:175%_auto] hover:bg-[center_top_2rem] hover:bg-no-repeat",
|
|
"hover:border-b-0 border-b-0",
|
|
)}
|
|
>
|
|
<div className="flex-1 mt-10">
|
|
<h3 className="text-white text-sm font-medium">{card.title}</h3>
|
|
<p
|
|
className={cn(
|
|
"text-[#8B8B8B] text-xs leading-relaxed",
|
|
dmSansClassName(),
|
|
)}
|
|
>
|
|
{card.description}
|
|
</p>
|
|
</div>
|
|
<div className="absolute top-0 right-0">{card.icon}</div>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
|
|
<div className="flex justify-between w-full max-w-4xl">
|
|
<Button
|
|
variant="link"
|
|
className="text-white hover:text-gray-300 hover:no-underline cursor-pointer"
|
|
onClick={() => router.push("/onboarding/setup?step=relatable")}
|
|
>
|
|
← Back
|
|
</Button>
|
|
<Button
|
|
variant="link"
|
|
className="text-white hover:text-gray-300 hover:no-underline cursor-pointer"
|
|
onClick={handleContinue}
|
|
>
|
|
Continue →
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|