feat(web): overhaul integrations page with featured hero, category rails and MCP setup modal (#979)

- Rebuild the integrations catalog as horizontally-scrollable category rails
  (MCP, Plugins, Knowledge bases, Apps & extensions) with header chevrons
- Add an auto-rotating Featured hero with problem-led headlines, backdrop
  imagery and a gradient FEATURED badge
- Surface all 9 MCP clients as individual cards that open a setup modal
  styled like the plugin connect flow (reuses MCPSteps embedded variant)
- Align MCP setup steps and the Claude Desktop timeline to the design system
- Merge the Integrations and Connections settings tabs into one entry
This commit is contained in:
MaheshtheDev 2026-05-27 01:10:12 +00:00
parent 31d416b04a
commit 9fa626cf17
4 changed files with 1918 additions and 474 deletions

View file

@ -8,8 +8,9 @@ export default function SettingsIntegrationsPage() {
const searchParams = useSearchParams()
useEffect(() => {
const qs = searchParams.toString()
router.replace(`/settings${qs ? `?${qs}` : ""}#integrations`)
const params = new URLSearchParams(searchParams.toString())
params.set("view", "integrations")
router.replace(`/?${params.toString()}`)
}, [router, searchParams])
return null

File diff suppressed because it is too large Load diff

View file

@ -69,52 +69,76 @@ export function ClaudeDesktopManualTimeline({
}: ClaudeDesktopManualTimelineProps) {
const isDetail = variant === "detail"
const textMuted = isDetail ? "text-[#B0B0B0]" : "text-muted-foreground"
const border = isDetail ? "border-[#3D434D]" : "border-border"
const spine = isDetail ? "bg-[#7C8C9E]" : "bg-muted-foreground/40"
const textMuted = isDetail ? "text-[#A1A1AA]" : "text-muted-foreground"
const border = isDetail ? "border-white/[0.07]" : "border-border"
const spine = isDetail ? "bg-white/[0.14]" : "bg-muted-foreground/40"
const circleBorder = isDetail
? "border-[#9CA8B8]"
? "border-white/[0.12]"
: "border-muted-foreground/50"
const circleBg = isDetail ? "bg-[#080B0F]" : "bg-background"
const codeBg = isDetail ? "bg-[#050608]" : "bg-muted"
const imgBorder = isDetail ? "border-[#3D434D]" : "border-border"
const screenshotBed = isDetail ? "bg-[#2A2D35]" : "bg-muted"
const circleBg = isDetail ? "bg-[#0D121A]" : "bg-background"
const codeBg = isDetail ? "bg-[#0B0E13]" : "bg-muted"
const imgBorder = isDetail ? "border-white/[0.07]" : "border-border"
const screenshotBed = isDetail ? "bg-[#0B0E13]" : "bg-muted"
return (
<div
className={cn(
"space-y-0",
isDetail
? "rounded-2xl border border-[#3D434D] bg-[#080B0F] p-5 sm:p-6"
? ""
: "rounded-xl border border-border bg-muted/50 p-4 sm:p-5",
)}
>
<div className="relative">
<div
className={cn(
"absolute top-4.5 bottom-4.5 left-4.5 w-0.5 rounded-full",
isDetail
? "absolute top-3 bottom-3 left-[10.5px] w-px"
: "absolute top-4.5 bottom-4.5 left-4.5 w-0.5 rounded-full",
spine,
)}
aria-hidden
/>
<ol className="relative m-0 list-none space-y-10">
<ol className="relative m-0 list-none space-y-7">
{STEPS.map((item) => (
<li className="relative flex gap-4 sm:gap-5" key={item.step}>
<div className="relative z-1 flex w-9 shrink-0 justify-center pt-0.5">
<div
className={cn(
"flex size-9 items-center justify-center rounded-full border-2 text-sm font-semibold tabular-nums shadow-sm",
circleBorder,
circleBg,
isDetail ? "text-[#FAFAFA]" : "text-foreground",
)}
>
{item.step}
</div>
<div
className={cn(
"relative z-1 flex shrink-0 justify-center pt-0.5",
isDetail ? "w-[22px]" : "w-9",
)}
>
{isDetail ? (
<div
className={cn(
"flex size-[22px] items-center justify-center rounded-full bg-[#0D121A] text-[11px] font-semibold tabular-nums text-[#4BA0FA]",
"shadow-[inset_0_2px_4px_rgba(0,0,0,0.3),inset_0_1px_2px_rgba(0,0,0,0.1)]",
)}
>
{item.step}
</div>
) : (
<div
className={cn(
"flex size-9 items-center justify-center rounded-full border-2 text-sm font-semibold tabular-nums shadow-sm",
circleBorder,
circleBg,
"text-foreground",
)}
>
{item.step}
</div>
)}
</div>
<div className="min-w-0 flex-1 space-y-3">
<p className={cn("text-sm leading-relaxed", textMuted)}>
<p
className={cn(
isDetail
? "text-[13px] leading-relaxed text-[#A1A1AA]"
: cn("text-sm leading-relaxed", textMuted),
)}
>
{item.body}
</p>
@ -123,14 +147,14 @@ export function ClaudeDesktopManualTimeline({
<div className="relative">
<pre
className={cn(
"max-w-full overflow-x-auto rounded-lg border p-4 pr-12 text-xs",
"max-w-full overflow-x-auto rounded-[10px] border p-4 pr-12 text-xs",
border,
codeBg,
)}
>
<code
className={cn(
"block font-mono whitespace-pre-wrap break-all text-emerald-400",
"block font-mono whitespace-pre-wrap break-all text-[#E4E4E7]",
dmMonoClassName(),
)}
>
@ -139,13 +163,13 @@ export function ClaudeDesktopManualTimeline({
</pre>
<button
type="button"
className="absolute top-2 right-2 flex size-8 cursor-pointer items-center justify-center rounded-md border border-[#3D434D] bg-[#121820] hover:bg-[#1a2230]"
className="absolute top-2 right-2 flex size-7 cursor-pointer items-center justify-center rounded-full bg-[#0D121A] shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.6)] transition-opacity hover:opacity-80"
onClick={onCopySnippet}
>
{snippetCopied ? (
<span className="text-xs text-emerald-500"></span>
<CheckIcon className="size-3.5 text-[#4BA0FA]" />
) : (
<CopyIcon className="size-3.5 text-[#8B8B8B] hover:text-white" />
<CopyIcon className="size-3.5 text-[#737373]" />
)}
</button>
</div>

View file

@ -30,6 +30,67 @@ import {
getManualInstallEntry,
} from "@/lib/mcp-manual-instructions"
import { ClaudeDesktopManualTimeline } from "@/components/mcp-modal/claude-desktop-manual-timeline"
import { INSET } from "@/components/integrations/install-steps"
function McpCodeBlock({
code,
multiline,
onCopy,
}: {
code: string
multiline?: boolean
onCopy?: () => void
}) {
const [copied, setCopied] = useState(false)
const copy = () => {
navigator.clipboard.writeText(code)
setCopied(true)
toast.success("Copied to clipboard!")
setTimeout(() => setCopied(false), 2000)
onCopy?.()
}
return (
<div
className={cn(
"group flex min-w-0 gap-2 rounded-[10px] border border-white/[0.07] bg-[#0B0E13] px-3 py-2.5",
multiline ? "items-start" : "items-center",
)}
>
<div className="relative min-w-0 flex-1">
<pre
className={cn(
"scrollbar-none min-w-0 overflow-x-auto font-mono text-[12px] leading-[1.6] text-[#E4E4E7]",
multiline ? "whitespace-pre-wrap break-all" : "whitespace-pre pr-4",
dmMonoClassName(),
)}
>
{code}
</pre>
{!multiline && (
<div
aria-hidden
className="pointer-events-none absolute inset-y-0 right-0 w-8 bg-gradient-to-l from-[#0B0E13] to-transparent"
/>
)}
</div>
<button
type="button"
aria-label="Copy"
onClick={copy}
className={cn(
"flex size-7 shrink-0 items-center justify-center rounded-full bg-[#0D121A] transition-opacity hover:opacity-80",
INSET,
)}
>
{copied ? (
<Check className="size-3.5 text-[#4BA0FA]" />
) : (
<CopyIcon className="size-3.5 text-[#737373]" />
)}
</button>
</div>
)
}
const clients = {
chatgpt: "ChatGPT",
@ -101,7 +162,8 @@ function ClientToolIcon({
return (
<div
className={cn(
"size-10 shrink-0 rounded-[10px] bg-[#0D121A] border border-[#242A33] flex items-center justify-center overflow-hidden",
"size-10 shrink-0 rounded-[10px] bg-[#080B0F] flex items-center justify-center overflow-hidden",
"shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.6)]",
)}
>
{failed ? (
@ -137,7 +199,6 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
"mcpTab",
parseAsStringLiteral(["oneClick", "manual"] as const).withDefault("manual"),
)
const [isCommandCopied, setIsCommandCopied] = useState(false)
const [isManualCopied, setIsManualCopied] = useState(false)
const [activeStep, setActiveStep] = useQueryState(
"mcpStep",
@ -170,15 +231,6 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
return command
}
const copyToClipboard = () => {
const command = generateInstallCommand()
navigator.clipboard.writeText(command)
analytics.mcpInstallCmdCopied()
setIsCommandCopied(true)
setActiveStep(3)
setTimeout(() => setIsCommandCopied(false), 2000)
}
const copyManualSnippet = (text: string) => {
navigator.clipboard.writeText(text)
analytics.mcpInstallCmdCopied()
@ -203,17 +255,6 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
? "manual"
: setupTab
const gradientStep3 =
activeStep === 3
? {
background:
"linear-gradient(94deg, #369BFD 4.8%, #36FDFD 77.04%, #36FDB5 143.99%)",
backgroundClip: "text",
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
}
: undefined
return (
<div
className={cn(
@ -228,11 +269,11 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
key={category.label}
className={cn(
"flex flex-col gap-4 py-5 sm:flex-row sm:items-start sm:gap-8",
rowIndex > 0 && "border-t border-[#242A33]",
rowIndex > 0 && "border-t border-white/[0.06]",
)}
>
<div className="w-full shrink-0 sm:w-30">
<p className="text-[13px] font-semibold tracking-[-0.01em] text-[#8B8B8B]">
<p className="text-[13px] font-semibold tracking-[-0.01em] text-[#A1A1AA]">
{category.label}
</p>
</div>
@ -249,9 +290,9 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
setActiveStep(2)
}}
className={cn(
"group flex w-full min-w-0 items-center gap-3 rounded-xl border border-[#242A33] bg-[#080B0F] p-3.5 text-left transition-colors",
"hover:border-[#3273FC4D] hover:bg-[#08142D]",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#3273FC]/40",
"group flex w-full min-w-0 items-center gap-3 rounded-[12px] bg-[#0D121A] p-3.5 text-left transition-colors",
"shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.5)] hover:bg-[#10151D]",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#4BA0FA]/40",
)}
>
<ClientToolIcon clientKey={item.key} title={item.title} />
@ -259,10 +300,12 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
<p className="text-sm font-medium text-[#FAFAFA]">
{item.title}
</p>
<p className="text-xs text-[#737373]">{item.subtitle}</p>
<p className="text-[12px] text-[#737373]">
{item.subtitle}
</p>
</div>
<ChevronRight
className="size-4 shrink-0 text-[#525866] transition-transform group-hover:translate-x-0.5"
className="size-4 shrink-0 text-[#525D6E] transition-transform group-hover:translate-x-0.5"
aria-hidden
/>
</button>
@ -270,51 +313,63 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
</div>
</div>
))}
<p className="pt-1 text-sm text-[#8B8B8B]">
<p className="pt-1 text-[13px] text-[#A1A1AA]">
You can connect several clients; setup is different for each one.
</p>
</div>
) : (
<div className={cn("space-y-4", dmSansClassName())}>
<button
type="button"
onClick={() => {
setSelectedClient(null)
setActiveStep(1)
}}
className="text-sm font-medium text-[#8B8B8B] transition-colors hover:text-[#FAFAFA]"
{!isEmbedded && (
<>
<button
type="button"
onClick={() => {
setSelectedClient(null)
setActiveStep(1)
}}
className="text-sm font-medium text-[#A1A1AA] transition-colors hover:text-[#FAFAFA]"
>
All clients
</button>
<div className="flex flex-wrap items-center gap-3">
<ClientToolIcon
clientKey={selectedKey}
title={clients[selectedKey]}
/>
<div>
<p className="text-lg font-medium text-[#FAFAFA]">
{clients[selectedKey]}
</p>
<p className="text-sm text-[#737373]">
{detailSetup ? setupInstructionsSubtitle(detailSetup) : ""}
</p>
</div>
</div>
</>
)}
<div
className={cn(
"space-y-4",
!isEmbedded && "border-t border-white/[0.06] pt-8",
)}
>
All clients
</button>
<div className="flex flex-wrap items-center gap-3">
<ClientToolIcon
clientKey={selectedKey}
title={clients[selectedKey]}
/>
<div>
<p className="text-lg font-medium text-[#FAFAFA]">
{clients[selectedKey]}
</p>
<p className="text-sm text-[#737373]">
{detailSetup ? setupInstructionsSubtitle(detailSetup) : ""}
</p>
</div>
</div>
<div className="space-y-4 border-t border-[#242A33] pt-8">
{detailSetup && mcpClientSetupShowsTabs(detailSetup) ? (
<div
className="flex w-full max-w-md flex-row gap-1 rounded-full border border-[#3D434D] bg-[#0D121A] p-1"
className={cn(
"flex w-full flex-row gap-0.5 rounded-full bg-[#0D121A] p-0.5",
"shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.5)]",
)}
role="tablist"
aria-label="Setup method"
>
<button
className={cn(
"min-h-9 flex-1 rounded-full px-3 py-2 text-center text-xs font-medium transition-all",
"min-h-8 flex-1 rounded-full px-3 text-center text-[12px] font-medium transition-colors",
effectiveSetupTab === "manual"
? "border border-[#3D434D] bg-[#080B0F] text-white"
: "text-[#8B8B8B] hover:text-white",
? "bg-white/[0.10] text-[#FAFAFA]"
: "text-[#A1A1AA] hover:text-[#FAFAFA]",
)}
onClick={() => setSetupTab("manual")}
role="tab"
@ -325,10 +380,10 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
</button>
<button
className={cn(
"min-h-9 flex-1 rounded-full px-3 py-2 text-center text-xs font-medium transition-all",
"min-h-8 flex-1 rounded-full px-3 text-center text-[12px] font-medium transition-colors",
effectiveSetupTab === "oneClick"
? "border border-[#3D434D] bg-[#080B0F] text-white"
: "text-[#8B8B8B] hover:text-white",
? "bg-white/[0.10] text-[#FAFAFA]"
: "text-[#A1A1AA] hover:text-[#FAFAFA]",
)}
onClick={() => setSetupTab("oneClick")}
role="tab"
@ -345,47 +400,31 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
<>
{selectedClient === "mcp-url" && (
<div className="space-y-2">
<p className="text-sm text-[#8B8B8B]">
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
Paste this URL into any MCP client that supports remote
servers over HTTPS.
</p>
<div className="relative">
<input
className={cn(
"w-full rounded-lg border border-[#3D434D] bg-black p-2 pr-10 font-mono text-xs text-emerald-400",
dmMonoClassName(),
)}
readOnly
value="https://mcp.supermemory.ai/mcp"
/>
<button
type="button"
className="absolute top-1 right-1 cursor-pointer p-1"
onClick={() => {
navigator.clipboard.writeText(
"https://mcp.supermemory.ai/mcp",
)
analytics.mcpInstallCmdCopied()
toast.success("Copied to clipboard!")
setActiveStep(3)
}}
>
<CopyIcon className="size-4 text-[#8B8B8B] hover:text-white" />
</button>
</div>
<McpCodeBlock
code="https://mcp.supermemory.ai/mcp"
onCopy={() => {
analytics.mcpInstallCmdCopied()
toast.success("Copied to clipboard!")
setActiveStep(3)
}}
/>
</div>
)}
{selectedClient === "cursor" && (
<div className="space-y-4">
<p className="text-sm text-[#8B8B8B]">
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
Open the link below to add supermemory in Cursor, or use
Manual instructions to edit{" "}
<code className="text-xs text-emerald-400/90">
<code className="font-mono text-[12px] text-[#8BC6FF]">
~/.cursor/mcp.json
</code>
.
</p>
<div className="flex flex-col items-center gap-4 rounded-xl border border-[#1e3a2f] bg-[#0a1510] p-6">
<div className="flex flex-col items-center gap-4 rounded-[10px] border border-white/[0.07] bg-[#0B0E13] p-6">
<a
href={getCursorDeeplink()}
onClick={() => {
@ -411,50 +450,18 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
{selectedClient !== "mcp-url" &&
selectedClient !== "cursor" && (
<div className="space-y-2">
<p className="text-sm text-[#8B8B8B]">
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
Run this command in your terminal. It installs the MCP
for {clients[selectedKey]} and starts OAuth when
needed.
</p>
<div className="relative">
<input
className={cn(
"w-full overflow-hidden text-ellipsis whitespace-nowrap rounded-xl py-4 pr-28 pl-3 text-xs text-white",
dmMonoClassName(),
)}
style={{
border: "1px solid rgba(61, 67, 77, 0.10)",
background: "#0D121A",
}}
readOnly
value={generateInstallCommand()}
/>
<button
type="button"
className={cn(
"absolute top-[5px] right-1 flex cursor-pointer items-center gap-2 rounded-[10px] px-3 py-2",
dmSansClassName(),
)}
style={{
background:
"linear-gradient(180deg, #267BF1 40.23%, #15468B 100%), linear-gradient(180deg, #0D121A -26.14%, #000 100%)",
border: "1px solid #000",
}}
onClick={copyToClipboard}
>
{isCommandCopied ? (
<>
<Check className="size-4 text-white" />
<span className="text-white">Copied</span>
</>
) : (
<>
<CopyIcon className="size-5 text-white stroke-[2px]" />
<span className="text-white">Copy</span>
</>
)}
</button>
</div>
<McpCodeBlock
code={generateInstallCommand()}
onCopy={() => {
analytics.mcpInstallCmdCopied()
setActiveStep(3)
}}
/>
</div>
)}
</>
@ -464,7 +471,7 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
if (manual.kind === "chatgpt") {
return (
<div className="space-y-3">
<ol className="list-decimal space-y-2 pl-5 text-sm text-[#8B8B8B]">
<ol className="list-decimal space-y-2 pl-5 text-[13px] leading-relaxed text-[#A1A1AA]">
<li>Open ChatGPT in your browser.</li>
<li>
Go to Settings Apps Advanced settings enable
@ -478,27 +485,15 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
Paste the URL below and complete OAuth in ChatGPT.
</li>
</ol>
<div className="relative">
<input
className={cn(
"w-full rounded-lg border border-[#3D434D] bg-black p-2 pr-10 font-mono text-xs text-emerald-400",
dmMonoClassName(),
)}
readOnly
value={CHATGPT_REMOTE_MCP_URL}
/>
<button
type="button"
className="absolute top-1 right-1 cursor-pointer p-1"
onClick={() =>
copyManualSnippet(CHATGPT_REMOTE_MCP_URL)
}
>
<CopyIcon className="size-4 text-[#8B8B8B] hover:text-white" />
</button>
</div>
<McpCodeBlock
code={CHATGPT_REMOTE_MCP_URL}
onCopy={() => {
analytics.mcpInstallCmdCopied()
setActiveStep(3)
}}
/>
<a
className="inline-block text-sm text-[#4BA0FA] underline hover:text-[#6BB8FF]"
className="inline-block text-[13px] text-[#4BA0FA] underline hover:text-[#8BC6FF]"
href="https://developers.openai.com/api/docs/guides/developer-mode/"
rel="noopener noreferrer"
target="_blank"
@ -523,36 +518,21 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
const snippet = buildMcpUrlRemoteJson("your-api-key-here")
return (
<div className="space-y-3">
<p className="text-sm text-[#8B8B8B]">
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
Add this to your client&apos;s MCP config. Replace the
placeholder with an API key from supermemory settings
(Integrations).
</p>
<div className="relative">
<pre className="max-w-full overflow-x-auto rounded-lg border border-[#3D434D] bg-black p-4 pr-12 text-xs">
<code
className={cn(
"block font-mono whitespace-pre-wrap break-all text-emerald-400",
dmMonoClassName(),
)}
>
{snippet}
</code>
</pre>
<button
type="button"
className="absolute top-2 right-2 flex size-8 cursor-pointer items-center justify-center rounded bg-[#0D121A] hover:bg-[#1a1a1a]"
onClick={() => copyManualSnippet(snippet)}
>
{isManualCopied ? (
<span className="text-emerald-500"></span>
) : (
<CopyIcon className="size-3.5" />
)}
</button>
</div>
<McpCodeBlock
code={snippet}
multiline
onCopy={() => {
analytics.mcpInstallCmdCopied()
setActiveStep(3)
}}
/>
{detailSetup?.oneClick ? (
<p className="text-xs text-[#737373]">
<p className="text-[12px] text-[#737373]">
Use Bearer auth in headers, or switch to One click
setup and paste the HTTPS URL if your client
supports OAuth only.
@ -563,35 +543,22 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
}
return (
<div className="space-y-3">
<p className="text-sm text-[#8B8B8B]">{manual.paths}</p>
<p className="text-sm text-[#8B8B8B]">
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
{manual.paths}
</p>
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
Merge the snippet with your existing file (create it if
needed). Restart the client and complete OAuth when
prompted.
</p>
<div className="relative">
<pre className="max-w-full overflow-x-auto rounded-lg border border-[#3D434D] bg-black p-4 pr-12 text-xs">
<code
className={cn(
"block font-mono whitespace-pre-wrap break-all text-emerald-400",
dmMonoClassName(),
)}
>
{manual.snippet}
</code>
</pre>
<button
type="button"
className="absolute top-2 right-2 flex size-8 cursor-pointer items-center justify-center rounded bg-[#0D121A] hover:bg-[#1a1a1a]"
onClick={() => copyManualSnippet(manual.snippet)}
>
{isManualCopied ? (
<span className="text-emerald-500"></span>
) : (
<CopyIcon className="size-3.5" />
)}
</button>
</div>
<McpCodeBlock
code={manual.snippet}
multiline
onCopy={() => {
analytics.mcpInstallCmdCopied()
setActiveStep(3)
}}
/>
</div>
)
})()
@ -599,47 +566,47 @@ export function MCPSteps({ variant = "full" }: MCPStepsProps) {
</div>
</div>
<div className="border-t border-[#242A33] pt-8">
<h3
className="mb-4 text-lg font-medium text-white"
style={gradientStep3}
>
{detailSetup != null &&
mcpClientShowsManual(detailSetup, effectiveSetupTab)
? selectedClient === "chatgpt"
? "Finish in ChatGPT"
: selectedClient === "claude"
? "Finish in Claude Desktop"
: "Save and restart"
: selectedClient === "cursor"
? "Finish in Cursor"
: "Run in terminal"}
</h3>
{activeStep === 3 && (
<p
{!isEmbedded && (
<div className="border-t border-white/[0.06] pt-6">
<h3
className={cn(
"flex items-center gap-2 rounded-xl p-4 pl-3 font-mono text-xs text-white",
dmMonoClassName(),
dmSansClassName(),
"mb-3 text-[15px] font-semibold tracking-[-0.01em] text-[#FAFAFA]",
)}
style={{
border: "1px solid rgba(61, 67, 77, 0.10)",
background: "#0D121A",
}}
>
<SyncLogoIcon className="size-4" />
{detailSetup != null &&
mcpClientShowsManual(detailSetup, effectiveSetupTab)
? selectedClient === "chatgpt"
? "Complete app setup in ChatGPT, then enable it for your chat."
? "Finish in ChatGPT"
: selectedClient === "claude"
? "After Connectors, complete any prompts so supermemory is enabled for chat."
: "Save your config, restart the client, and sign in if prompted."
? "Finish in Claude Desktop"
: "Save and restart"
: selectedClient === "cursor"
? "Complete the install in Cursor and sign in with OAuth if asked."
: "Waiting for installation"}
</p>
)}
</div>
? "Finish in Cursor"
: "Run in terminal"}
</h3>
{activeStep === 3 && (
<p
className={cn(
dmSansClassName(),
"flex items-center gap-2 rounded-[10px] border border-white/[0.07] bg-[#0B0E13] p-3 text-[12px] text-[#A1A1AA]",
)}
>
<SyncLogoIcon className="size-4 shrink-0 text-[#4BA0FA]" />
{detailSetup != null &&
mcpClientShowsManual(detailSetup, effectiveSetupTab)
? selectedClient === "chatgpt"
? "Complete app setup in ChatGPT, then enable it for your chat."
: selectedClient === "claude"
? "After Connectors, complete any prompts so supermemory is enabled for chat."
: "Save your config, restart the client, and sign in if prompted."
: selectedClient === "cursor"
? "Complete the install in Cursor and sign in with OAuth if asked."
: "Waiting for installation"}
</p>
)}
</div>
)}
</div>
)}
</div>