mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-08 03:08:21 +00:00
feat: major iteration on the app add: dashboard improvements few more improvements add few more improvements add few more changes home improvmeents few more improvements add lot of modifications fix few things
255 lines
6.1 KiB
TypeScript
255 lines
6.1 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useEffect } from "react"
|
|
import { useQueryState } from "nuqs"
|
|
import { cn } from "@lib/utils"
|
|
import { dmSansClassName } from "@/lib/fonts"
|
|
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 { ChromeDetail } from "@/components/integrations/chrome-detail"
|
|
import { ShortcutsDetail } from "@/components/integrations/shortcuts-detail"
|
|
import { RaycastDetail } from "@/components/integrations/raycast-detail"
|
|
import { ConnectionsDetail } from "@/components/integrations/connections-detail"
|
|
import { PluginsDetail } from "@/components/integrations/plugins-detail"
|
|
import {
|
|
ChromeIcon,
|
|
AppleShortcutsIcon,
|
|
RaycastIcon,
|
|
} from "@/components/integration-icons"
|
|
import { GoogleDrive, Notion, OneDrive } from "@ui/assets/icons"
|
|
import { ArrowLeft, Sun } from "lucide-react"
|
|
import {
|
|
integrationParam,
|
|
pluginsPanelParam,
|
|
type IntegrationParamValue,
|
|
} from "@/lib/search-params"
|
|
import Image from "next/image"
|
|
import { IntegrationGridCard } from "@/components/integrations/integration-grid-card"
|
|
|
|
type CardId =
|
|
| "mcp"
|
|
| "chrome"
|
|
| "connections"
|
|
| "shortcuts"
|
|
| "raycast"
|
|
| "import"
|
|
| "plugins"
|
|
|
|
interface IntegrationCardDef {
|
|
id: CardId
|
|
title: string
|
|
description: string
|
|
icon: React.ReactNode
|
|
pro?: boolean
|
|
}
|
|
|
|
const cards: IntegrationCardDef[] = [
|
|
{
|
|
id: "plugins",
|
|
title: "Plugins",
|
|
description:
|
|
"Hermes on every plan; Claude Code, OpenCode, OpenClaw, and more with Pro",
|
|
icon: (
|
|
<div className="flex items-center -space-x-1.5">
|
|
<Image
|
|
src="/images/plugins/claude-code.svg"
|
|
alt="Claude Code"
|
|
width={24}
|
|
height={24}
|
|
className="size-6 rounded"
|
|
/>
|
|
<Image
|
|
src="/images/plugins/opencode.svg"
|
|
alt="OpenCode"
|
|
width={24}
|
|
height={24}
|
|
className="size-6 rounded"
|
|
/>
|
|
<Image
|
|
src="/images/plugins/openclaw.svg"
|
|
alt="OpenClaw"
|
|
width={24}
|
|
height={24}
|
|
className="size-6 rounded"
|
|
/>
|
|
<Image
|
|
src="/images/plugins/hermes.svg"
|
|
alt="Hermes"
|
|
width={24}
|
|
height={24}
|
|
className="size-6 rounded"
|
|
/>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
id: "connections",
|
|
title: "Connections",
|
|
description: "Link Notion, Google Drive, or OneDrive to import your docs",
|
|
pro: true,
|
|
icon: (
|
|
<div className="flex items-center -space-x-1">
|
|
<GoogleDrive className="size-5" />
|
|
<Notion className="size-5" />
|
|
<OneDrive className="size-5" />
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
id: "mcp",
|
|
title: "Connect to AI",
|
|
description: "Set up MCP to use your memory in Cursor, Claude, and more",
|
|
icon: (
|
|
<img src="/onboarding/mcp.png" alt="MCP" className="size-20 h-auto" />
|
|
),
|
|
},
|
|
{
|
|
id: "chrome",
|
|
title: "Chrome Extension",
|
|
description: "Save any webpage, import bookmarks, sync ChatGPT memories",
|
|
icon: <ChromeIcon className="size-14" />,
|
|
},
|
|
{
|
|
id: "shortcuts",
|
|
title: "Apple Shortcuts",
|
|
description: "Add memories directly from iPhone, iPad or Mac",
|
|
icon: <AppleShortcutsIcon />,
|
|
},
|
|
{
|
|
id: "raycast",
|
|
title: "Raycast",
|
|
description: "Add and search memories from Raycast on Mac",
|
|
icon: <RaycastIcon className="size-10" />,
|
|
},
|
|
{
|
|
id: "import",
|
|
title: "Import Bookmarks",
|
|
description: "Bring in X/Twitter bookmarks and turn them into memories",
|
|
icon: <img src="/onboarding/x.png" alt="X" className="size-10" />,
|
|
},
|
|
]
|
|
|
|
function DetailWrapper({
|
|
onBack,
|
|
children,
|
|
}: {
|
|
onBack: () => void
|
|
children: React.ReactNode
|
|
}) {
|
|
return (
|
|
<div className="flex-1 p-4 md:p-6 pt-2">
|
|
<div className="max-w-3xl mx-auto">
|
|
<Button
|
|
variant="link"
|
|
className="text-white hover:text-gray-300 p-0 hover:no-underline cursor-pointer mb-4"
|
|
onClick={onBack}
|
|
>
|
|
<ArrowLeft className="size-4 mr-1" />
|
|
Back to Integrations
|
|
</Button>
|
|
{children}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const INTEGRATION_TO_CARD: Record<IntegrationParamValue, CardId> = {
|
|
import: "import",
|
|
chrome: "chrome",
|
|
connections: "connections",
|
|
}
|
|
|
|
export function IntegrationsView() {
|
|
const [integration, setIntegration] = useQueryState(
|
|
"integration",
|
|
integrationParam,
|
|
)
|
|
const [pluginsPanel, setPluginsPanel] = useQueryState(
|
|
"plugins",
|
|
pluginsPanelParam,
|
|
)
|
|
const [selectedCard, setSelectedCard] = useState<CardId | null>(null)
|
|
|
|
useEffect(() => {
|
|
if (pluginsPanel === true) {
|
|
setSelectedCard("plugins")
|
|
return
|
|
}
|
|
if (integration && INTEGRATION_TO_CARD[integration]) {
|
|
setSelectedCard(INTEGRATION_TO_CARD[integration])
|
|
}
|
|
}, [integration, pluginsPanel])
|
|
|
|
const handleBack = () => {
|
|
setSelectedCard(null)
|
|
setIntegration(null)
|
|
void setPluginsPanel(null)
|
|
}
|
|
|
|
switch (selectedCard) {
|
|
case "mcp":
|
|
return <MCPDetailView onBack={handleBack} />
|
|
case "import":
|
|
return <XBookmarksDetailView onBack={handleBack} />
|
|
case "chrome":
|
|
return (
|
|
<DetailWrapper onBack={handleBack}>
|
|
<ChromeDetail />
|
|
</DetailWrapper>
|
|
)
|
|
case "shortcuts":
|
|
return (
|
|
<DetailWrapper onBack={handleBack}>
|
|
<ShortcutsDetail />
|
|
</DetailWrapper>
|
|
)
|
|
case "raycast":
|
|
return (
|
|
<DetailWrapper onBack={handleBack}>
|
|
<RaycastDetail />
|
|
</DetailWrapper>
|
|
)
|
|
case "connections":
|
|
return (
|
|
<DetailWrapper onBack={handleBack}>
|
|
<ConnectionsDetail />
|
|
</DetailWrapper>
|
|
)
|
|
case "plugins":
|
|
return (
|
|
<DetailWrapper onBack={handleBack}>
|
|
<PluginsDetail />
|
|
</DetailWrapper>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="flex-1 p-4 md:p-6 pt-2">
|
|
<div className="max-w-3xl mx-auto">
|
|
<div className="mb-6 space-y-1">
|
|
<div className="flex items-center gap-2">
|
|
<Sun className="size-5 text-white" />
|
|
<h2 className="text-white text-xl font-medium">Integrations</h2>
|
|
</div>
|
|
<p className={cn("text-[#8B8B8B] text-sm", dmSansClassName())}>
|
|
Connect supermemory to your tools and workflows
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
{cards.map((card) => (
|
|
<IntegrationGridCard
|
|
key={card.id}
|
|
title={card.title}
|
|
description={card.description}
|
|
icon={card.icon}
|
|
pro={card.pro}
|
|
onClick={() => setSelectedCard(card.id)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|