aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMahesh Sanikommmu <[email protected]>2025-08-16 20:15:39 -0700
committerMahesh Sanikommmu <[email protected]>2025-08-16 20:15:39 -0700
commitfddc21aab2f9f59623d76802d0ab2b17cbe7fa5b (patch)
treeaf2d510bf4c1913d9f7c5fd3348b9697e7928af6
parentMerge pull request #366 from supermemoryai/mahesh/supermemory-new (diff)
downloadsupermemory-fddc21aab2f9f59623d76802d0ab2b17cbe7fa5b.tar.xz
supermemory-fddc21aab2f9f59623d76802d0ab2b17cbe7fa5b.zip
added usage notes
-rw-r--r--CONTRIBUTE.md288
-rw-r--r--README.md114
-rw-r--r--apps/web/components/views/connections-tab-content.tsx664
-rw-r--r--apps/web/public/add-connections.pngbin0 -> 339198 bytes
-rw-r--r--apps/web/public/add-memory.pngbin0 -> 371710 bytes
-rw-r--r--apps/web/public/chat.pngbin0 -> 342407 bytes
-rw-r--r--apps/web/public/mcp.pngbin0 -> 421670 bytes
7 files changed, 645 insertions, 421 deletions
diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md
new file mode 100644
index 00000000..b3ea376f
--- /dev/null
+++ b/CONTRIBUTE.md
@@ -0,0 +1,288 @@
+# Contributing to supermemory
+
+Thank you for your interest in contributing to supermemory! We welcome contributions from developers of all skill levels. This guide will help you get started with contributing to our AI-powered memory layer API.
+
+## πŸš€ Quick Start
+
+### Prerequisites
+
+Before you begin, ensure you have the following installed:
+
+- **Bun** (>= 1.2.17) - Our preferred package manager
+- **Git** for version control
+
+### Setting Up the Development Environment
+
+1. **Fork and Clone the Repository**
+
+ ```bash
+ git clone https://github.com/your-username/supermemory-app.git
+ cd supermemory-app
+ ```
+
+2. **Install Dependencies**
+
+ ```bash
+ bun install
+ ```
+
+3. **Set Up Environment Variables**
+
+ ```bash
+ # Copy the example environment file
+ cp .env.example .env.local
+
+ # Edit the file with your configuration
+ # You'll need to add your API keys and database URLs
+ ```
+
+4. **Start the Development Server**
+
+ ```bash
+ bun run dev
+ ```
+
+ This will start all applications in the monorepo. The web app will be available at `http://localhost:3000`.
+
+## πŸ“ Project Structure
+
+supermemory is organized as a monorepo using Turbo:
+
+```
+supermemory-app/
+β”œβ”€β”€ apps/
+β”‚ └── web/ # Next.js web application
+β”œβ”€β”€ packages/
+β”‚ β”œβ”€β”€ ui/ # Shared UI components
+β”‚ β”œβ”€β”€ lib/ # Shared utilities and logic
+β”‚ β”œβ”€β”€ hooks/ # Shared React hooks
+β”‚ β”œβ”€β”€ validation/ # Zod schemas and validation
+β”‚ β”œβ”€β”€ eslint-config/ # ESLint configurations
+β”‚ └── typescript-config/ # TypeScript configurations
+└── turbo.json # Turbo configuration
+```
+
+## πŸ› οΈ Development Workflow
+
+### Available Scripts
+
+- `bun run dev` - Start development servers for all apps
+- `bun run build` - Build all applications
+- `bun run format-lint` - Format and lint code using Biome
+- `bun run check-types` - Type check all packages
+
+### Code Quality
+
+We use several tools to maintain code quality:
+
+- **Biome** for linting and formatting
+- **TypeScript** for type safety
+- **Turbo** for build optimization
+
+Before submitting a PR, ensure your code passes all checks:
+
+```bash
+bun run format-lint
+bun run check-types
+bun run build
+```
+
+### Tech Stack
+
+- **Frontend**: Next.js 15, React 19, TypeScript
+- **Styling**: Tailwind CSS, Radix UI components
+- **State Management**: Zustand, TanStack Query
+- **Build Tool**: Turbo (monorepo)
+- **Package Manager**: Bun
+- **Deployment**: Cloudflare (OpenNext.js)
+
+## 🎯 How to Contribute
+
+### Types of Contributions
+
+We welcome various types of contributions:
+
+- πŸ› **Bug fixes**
+- ✨ **New features**
+- 🎨 **UI/UX enhancements**
+- ⚑ **Performance optimizations**
+
+### Finding Issues to Work On
+
+1. Check our [Issues](https://github.com/supermemoryai/supermemory/issues) page
+2. Look for issues labeled `good first issue` for beginners
+3. Issues labeled `help wanted` are great for contributors
+4. Feel free to propose new features by opening an issue first
+
+### Making Changes
+
+1. **Create a Branch**
+
+ ```bash
+ git checkout -b feature/your-feature-name
+ # or
+ git checkout -b fix/your-bug-fix
+ ```
+
+2. **Make Your Changes**
+ - Follow our coding standards (see below)
+ - Write clear, concise commit messages
+ - Add tests if applicable
+ - Update documentation if needed
+
+3. **Test Your Changes**
+ ```bash
+ bun run dev # Test locally
+ bun run build # Ensure it builds
+ bun run format-lint # Check formatting
+ bun run check-types # Check types
+ ```
+
+## πŸ“ Coding Standards
+
+### General Guidelines
+
+- Use **TypeScript** for all new code
+- Follow the existing code style and patterns
+- Write self-documenting code with clear variable names
+- Add JSDoc comments for complex functions
+- Keep functions small and focused
+
+### Component Guidelines
+
+- Use functional components with hooks
+- Prefer composition over inheritance
+- Extract reusable logic into custom hooks
+- Use proper TypeScript types for props
+
+### File Naming
+
+- Use `kebab-case` for file names
+- Use `PascalCase` for component files
+- Use `camelCase` for utility functions
+
+### Import Organization
+
+```typescript
+// 1. React and Next.js imports
+import React from 'react';
+import { NextPage } from 'next';
+
+// 2. Third-party libraries
+import { clsx } from 'clsx';
+import { motion } from 'motion';
+
+// 3. Internal packages
+import { Button } from '@repo/ui';
+import { useAuth } from '@repo/lib';
+
+// 4. Relative imports
+import { Header } from './header';
+import { Footer } from './footer';
+```
+
+## πŸ”„ Pull Request Process
+
+### Before Submitting
+
+1. Ensure your branch is up to date with `main`
+2. Run all quality checks
+3. Test your changes thoroughly
+4. Update documentation if needed
+
+### PR Guidelines
+
+1. **Title**: Use a clear, descriptive title
+ - βœ… `feat: add semantic search to memory graph`
+ - βœ… `fix: resolve authentication redirect loop`
+ - ❌ `update stuff`
+
+2. **Description**: Include:
+ - What changes you made and why
+ - Screenshots for UI changes
+ - Any breaking changes
+ - Related issue numbers
+
+3. **Size**: Keep PRs focused and reasonably sized
+ - Prefer multiple small PRs over one large PR
+ - Each PR should address a single concern
+
+### Review Process
+
+1. All PRs require at least one review
+2. Address feedback promptly and professionally
+3. Be open to suggestions and improvements
+4. Maintain a collaborative attitude
+
+## πŸ› Reporting Issues
+
+### Bug Reports
+
+When reporting bugs, please include:
+
+- **Environment**: OS, Node.js version, browser
+- **Steps to reproduce** the issue
+- **Expected behavior**
+- **Actual behavior**
+- **Screenshots** if applicable
+- **Error messages** or console logs
+
+### Feature Requests
+
+For feature requests, please provide:
+
+- **Problem statement**: What problem does this solve?
+- **Proposed solution**: How should it work?
+- **Alternatives considered**: Other approaches you've thought of
+- **Additional context**: Any relevant information
+
+## πŸ—οΈ Architecture Guidelines
+
+### State Management
+
+- Use **Zustand** for global state
+- Use **TanStack Query** for server state
+- Keep state as local as possible
+- Use proper TypeScript types for state
+
+### API Integration
+
+- Use the existing API client patterns
+- Handle loading and error states properly
+- Implement proper error boundaries
+- Use optimistic updates where appropriate
+
+### Performance
+
+- Use React.memo() for expensive components
+- Implement proper loading states
+- Optimize images and assets
+- Use code splitting where beneficial
+
+## 🀝 Community Guidelines
+
+### Code of Conduct
+
+- Be respectful and inclusive
+- Welcome newcomers and help them learn
+- Focus on constructive feedback
+- Maintain professionalism in all interactions
+
+### Getting Help
+
+- **Discord**: Join our community server
+- **GitHub Discussions**: For questions and ideas
+- **Issues**: For bug reports and feature requests
+- **Email**: [[email protected]](mailto:[email protected])
+
+## πŸ“„ License
+
+By contributing to supermemory, you agree that your contributions will be licensed under the same license as the project.
+
+## πŸ™ Recognition
+
+All contributors will be recognized in our README and release notes. We appreciate every contribution, no matter how small!
+
+---
+
+Thank you for contributing to supermemory! Together, we're building the future of AI-powered knowledge management. πŸš€
diff --git a/README.md b/README.md
index afd2af2a..28179e96 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-<div align="center" style="padding-bottom:10px;padding-top:10px">
+<div align="center" style="padding-bottom:20px;padding-top:20px">
<img src="logo.svg" alt="supermemory Logo" width="400" />
</div>
@@ -6,94 +6,70 @@
<img src="apps/web/public/landing-page.jpeg" alt="supermemory" width="100%" />
</div>
-## ✨ Features
+## Features
### Core Functionality
-- **Add Memories from Any Content**: Easily add memories from URLs, PDFs, and plain textβ€”just paste, upload, or link.
-- **Chat with Your Memories**: Converse with your stored content using natural language chat.
-- **Supermemory MCP Integration**: Seamlessly connect with all major AI tools (Claude, Cursor, etc.) via Supermemory MCP.
-- **Graph View for All Memories**: Visualize and explore your memories and their connections in an interactive graph mode.
-
-## πŸ—οΈ Architecture
-This is a **Turborepo monorepo**
+- **[Add Memories from Any Content](#add-memory)**: Easily add memories from URLs, PDFs, and plain textβ€”just paste, upload, or link.
+- **[Chat with Your Memories](#chat-memories)**: Converse with your stored content using natural language chat.
+- **[Supermemory MCP Integration](#mcp-integration)**: Seamlessly connect with all major AI tools (Claude, Cursor, etc.) via Supermemory MCP.
-### Technology Stack
-- **Frontend**: Next.js 15 with React 19
-- **Backend**: Hono API framework on Cloudflare Workers
-- **Database**: PostgreSQL with Drizzle ORM
-- **Authentication**: Better Auth with organization support
-- **Package Manager**: Bun
-- **Monorepo**: Turbo for build optimization
-- **Styling**: Tailwind CSS with Radix UI components
-- **Monitoring**: Sentry for error tracking and performance monitoring
+## How do i use this?
-### Project Structure
-```
-β”œβ”€β”€ apps/
-β”‚ └── web/ # Next.js web application
-β”œβ”€β”€ packages/ # Shared packages and utilities
-β”œβ”€β”€ CLAUDE.md # Development guidelines for AI assistants
-β”œβ”€β”€ turbo.json # Turborepo configuration
-└── package.json # Root package configuration
-```
+Go to [app.supermemory.ai](https://app.supermemory.ai) and sign into with your account
-## πŸš€ Getting Started
+1. <a id="add-memory"></a>Start Adding Memory with your choose of format (Note, Link, File)
+<div align="center" style="padding-bottom:10px;padding-top:10px">
+ <img src="apps/web/public/add-memory.png" alt="supermemory" width="100%" />
+</div>
-### Prerequisites
-- **Bun** package manager
+2. You can also Connect to your favourite services (Notion, Google Drive, OneDrive)
+<div align="center" style="padding-bottom:10px;padding-top:10px">
+ <img src="apps/web/public/add-connections.png" alt="supermemory" width="100%" />
+</div>
-### Installation
+3. <a id="chat-memories"></a>Once Memories are added, you can chat with Supermemory by clicking on "Open Chat" and retrieve info from your saved memories
+<div align="center" style="padding-bottom:10px;padding-top:10px">
+ <img src="apps/web/public/chat.png" alt="supermemory" width="100%" />
+</div>
-1. **Clone the repository**
- ```bash
- git clone https://github.com/supermemoryai/supermemory-app.git
- cd supermemory
- ```
+4. <a id="mcp-integration"></a>Add MCP to your AI Tools (by clicking on "Connect to your AI" and select the AI tool you are trying to integrate)
+<div align="center" style="padding-bottom:10px;padding-top:10px">
+ <img src="apps/web/public/mcp.png" alt="supermemory" width="100%" />
+</div>
-2. **Install dependencies**
- ```bash
- bun install
- ```
+## Support
-3. **Environment Setup**
-
- Create environment files for each app:
- ```bash
- # Copy environment templates
- cp apps/web/.env.example apps/web/.env.local
- ```
+Have questions or feedback? We're here to help:
-### Development
+- Documentation: [docs.supermemory.ai](https://docs.supermemory.ai)
-#### Start all applications in development mode:
-```bash
-bun run dev
-```
+## Contributing
-This will start:
-- Web app at `http://localhost:3000`
-- API endpoints available through the web app
+We welcome contributions from developers of all skill levels! Whether you're fixing bugs, adding features, or improving documentation, your help makes supermemory better for everyone.
+### Quick Start for Contributors
-## πŸ§ͺ Development Workflow
+1. **Fork and clone** the repository
+2. **Install dependencies** with `bun install`
+3. **Set up your environment** by copying `.env.example` to `.env.local`
+4. **Start developing** with `bun run dev`
-### Code Quality
-- **Linting & Formatting**: Uses Biome for consistent code style
-- **Type Safety**: Strict TypeScript configuration across all packages
+For detailed guidelines, development setup, coding standards, and the complete contribution workflow, please see our [**Contributing Guide**](CONTRIBUTE.md).
-## 🀝 Contributing
+### Ways to Contribute
-### Development Guidelines
-- Follow the code style enforced by Biome
-- Write tests for new features
-- Update documentation when adding new functionality
-- Ensure all checks pass before submitting PRs
+- πŸ› **Bug fixes** - Help us squash those pesky issues
+- ✨ **New features** - Add functionality that users will love
+- 🎨 **UI/UX improvements** - Make the interface more intuitive
+- ⚑ **Performance optimizations** - Help us make supermemory faster
+Check out our [Issues](https://github.com/supermemoryai/supermemory/issues) page for `good first issue` and `help wanted` labels to get started!
-## πŸ’¬ Support & Community
+## Updates & Roadmap
-- **Issues**: [GitHub Issues](https://github.com/supermemoryai/supermemory-app/issues)
-- **Email**: [[email protected]](mailto:[email protected])
-- **Twitter**: [@supermemoryai](https://x.com/supermemoryai)
+Stay up to date with the latest improvements:
+- [Changelog](https://docs.supermemory.ai/changelog/overview)
+- [X](https://x.com/supermemoryai)
diff --git a/apps/web/components/views/connections-tab-content.tsx b/apps/web/components/views/connections-tab-content.tsx
index 177c2a4d..a94ed708 100644
--- a/apps/web/components/views/connections-tab-content.tsx
+++ b/apps/web/components/views/connections-tab-content.tsx
@@ -1,382 +1,342 @@
-"use client"
+'use client';
-import { $fetch } from "@lib/api"
+import { $fetch } from '@lib/api';
import {
- fetchConnectionsFeature,
- fetchConsumerProProduct,
-} from "@repo/lib/queries"
-import { Button } from "@repo/ui/components/button"
+ fetchConnectionsFeature,
+ fetchConsumerProProduct,
+} from '@repo/lib/queries';
+import { Button } from '@repo/ui/components/button';
import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogHeader,
- DialogTitle,
-} from "@repo/ui/components/dialog"
-import { Skeleton } from "@repo/ui/components/skeleton"
-import type { ConnectionResponseSchema } from "@repo/validation/api"
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
-import { GoogleDrive, Notion, OneDrive } from "@ui/assets/icons"
-import { useCustomer } from "autumn-js/react"
-import { Plus, Trash2 } from "lucide-react"
-import { AnimatePresence, motion } from "motion/react"
-import Link from "next/link"
-import { useEffect, useState } from "react"
-import { toast } from "sonner"
-import type { z } from "zod"
-import { useProject } from "@/stores"
-import { analytics } from "@/lib/analytics"
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from '@repo/ui/components/dialog';
+import { Skeleton } from '@repo/ui/components/skeleton';
+import type { ConnectionResponseSchema } from '@repo/validation/api';
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { GoogleDrive, Notion, OneDrive } from '@ui/assets/icons';
+import { useCustomer } from 'autumn-js/react';
+import { Trash2 } from 'lucide-react';
+import { AnimatePresence, motion } from 'motion/react';
+import Link from 'next/link';
+import { useEffect } from 'react';
+import { toast } from 'sonner';
+import type { z } from 'zod';
+import { useProject } from '@/stores';
+import { analytics } from '@/lib/analytics';
// Define types
-type Connection = z.infer<typeof ConnectionResponseSchema>
+type Connection = z.infer<typeof ConnectionResponseSchema>;
// Connector configurations
const CONNECTORS = {
- "google-drive": {
- title: "Google Drive",
- description: "Connect your Google Docs, Sheets, and Slides",
- icon: GoogleDrive,
- },
- notion: {
- title: "Notion",
- description: "Import your Notion pages and databases",
- icon: Notion,
- },
- onedrive: {
- title: "OneDrive",
- description: "Access your Microsoft Office documents",
- icon: OneDrive,
- },
-} as const
+ 'google-drive': {
+ title: 'Google Drive',
+ description: 'Connect your Google Docs, Sheets, and Slides',
+ icon: GoogleDrive,
+ },
+ notion: {
+ title: 'Notion',
+ description: 'Import your Notion pages and databases',
+ icon: Notion,
+ },
+ onedrive: {
+ title: 'OneDrive',
+ description: 'Access your Microsoft Office documents',
+ icon: OneDrive,
+ },
+} as const;
-type ConnectorProvider = keyof typeof CONNECTORS
+type ConnectorProvider = keyof typeof CONNECTORS;
export function ConnectionsTabContent() {
- const queryClient = useQueryClient()
- const [showAddDialog, setShowAddDialog] = useState(false)
- const { selectedProject } = useProject()
- const autumn = useCustomer()
+ const queryClient = useQueryClient();
+ const { selectedProject } = useProject();
+ const autumn = useCustomer();
- const handleUpgrade = async () => {
- try {
- await autumn.attach({
- productId: "consumer_pro",
- successUrl: "https://app.supermemory.ai/",
- })
- window.location.reload()
- } catch (error) {
- console.error(error)
- }
- }
+ const handleUpgrade = async () => {
+ try {
+ await autumn.attach({
+ productId: 'consumer_pro',
+ successUrl: 'https://app.supermemory.ai/',
+ });
+ window.location.reload();
+ } catch (error) {
+ console.error(error);
+ }
+ };
- const { data: connectionsCheck } = fetchConnectionsFeature(autumn as any)
- const connectionsUsed = connectionsCheck?.balance ?? 0
- const connectionsLimit = connectionsCheck?.included_usage ?? 0
+ const { data: connectionsCheck } = fetchConnectionsFeature(autumn as any);
+ const connectionsUsed = connectionsCheck?.balance ?? 0;
+ const connectionsLimit = connectionsCheck?.included_usage ?? 0;
- const { data: proCheck } = fetchConsumerProProduct(autumn as any)
- const isProUser = proCheck?.allowed ?? false
+ const { data: proCheck } = fetchConsumerProProduct(autumn as any);
+ const isProUser = proCheck?.allowed ?? false;
- const canAddConnection = connectionsUsed < connectionsLimit
+ const canAddConnection = connectionsUsed < connectionsLimit;
- // Fetch connections
- const {
- data: connections = [],
- isLoading,
- error,
- } = useQuery({
- queryKey: ["connections"],
- queryFn: async () => {
- const response = await $fetch("@post/connections/list", {
- body: {
- containerTags: [],
- },
- })
+ // Fetch connections
+ const {
+ data: connections = [],
+ isLoading,
+ error,
+ } = useQuery({
+ queryKey: ['connections'],
+ queryFn: async () => {
+ const response = await $fetch('@post/connections/list', {
+ body: {
+ containerTags: [],
+ },
+ });
- if (response.error) {
- throw new Error(response.error?.message || "Failed to load connections")
- }
+ if (response.error) {
+ throw new Error(
+ response.error?.message || 'Failed to load connections'
+ );
+ }
- return response.data as Connection[]
- },
- staleTime: 30 * 1000,
- refetchInterval: 60 * 1000,
- })
+ return response.data as Connection[];
+ },
+ staleTime: 30 * 1000,
+ refetchInterval: 60 * 1000,
+ });
- // Show error toast if connections fail to load
- useEffect(() => {
- if (error) {
- toast.error("Failed to load connections", {
- description: error instanceof Error ? error.message : "Unknown error",
- })
- }
- }, [error])
+ // Show error toast if connections fail to load
+ useEffect(() => {
+ if (error) {
+ toast.error('Failed to load connections', {
+ description: error instanceof Error ? error.message : 'Unknown error',
+ });
+ }
+ }, [error]);
- // Add connection mutation
- const addConnectionMutation = useMutation({
- mutationFn: async (provider: ConnectorProvider) => {
- // Check if user can add connections
- if (!canAddConnection && !isProUser) {
- throw new Error(
- "Free plan doesn't include connections. Upgrade to Pro for unlimited connections.",
- )
- }
+ // Add connection mutation
+ const addConnectionMutation = useMutation({
+ mutationFn: async (provider: ConnectorProvider) => {
+ // Check if user can add connections
+ if (!canAddConnection && !isProUser) {
+ throw new Error(
+ "Free plan doesn't include connections. Upgrade to Pro for unlimited connections."
+ );
+ }
- const response = await $fetch("@post/connections/:provider", {
- params: { provider },
- body: {
- redirectUrl: window.location.href,
- containerTags: [selectedProject],
- },
- })
+ const response = await $fetch('@post/connections/:provider', {
+ params: { provider },
+ body: {
+ redirectUrl: window.location.href,
+ containerTags: [selectedProject],
+ },
+ });
- // biome-ignore lint/style/noNonNullAssertion: its fine
- if ("data" in response && !("error" in response.data!)) {
- return response.data
- }
+ // biome-ignore lint/style/noNonNullAssertion: its fine
+ if ('data' in response && !('error' in response.data!)) {
+ return response.data;
+ }
- throw new Error(response.error?.message || "Failed to connect")
- },
- onSuccess: (data, provider) => {
- analytics.connectionAdded(provider)
- analytics.connectionAuthStarted()
- if (data?.authLink) {
- window.location.href = data.authLink
- }
- },
- onError: (error, provider) => {
- analytics.connectionAuthFailed()
- toast.error(`Failed to connect ${provider}`, {
- description: error instanceof Error ? error.message : "Unknown error",
- })
- },
- })
+ throw new Error(response.error?.message || 'Failed to connect');
+ },
+ onSuccess: (data, provider) => {
+ analytics.connectionAdded(provider);
+ analytics.connectionAuthStarted();
+ if (data?.authLink) {
+ window.location.href = data.authLink;
+ }
+ },
+ onError: (error, provider) => {
+ analytics.connectionAuthFailed();
+ toast.error(`Failed to connect ${provider}`, {
+ description: error instanceof Error ? error.message : 'Unknown error',
+ });
+ },
+ });
- // Delete connection mutation
- const deleteConnectionMutation = useMutation({
- mutationFn: async (connectionId: string) => {
- await $fetch(`@delete/connections/${connectionId}`)
- },
- onSuccess: () => {
- analytics.connectionDeleted()
- toast.success(
- "Connection removal has started. supermemory will permanently delete the documents in the next few minutes.",
- )
- queryClient.invalidateQueries({ queryKey: ["connections"] })
- },
- onError: (error) => {
- toast.error("Failed to remove connection", {
- description: error instanceof Error ? error.message : "Unknown error",
- })
- },
- })
+ // Delete connection mutation
+ const deleteConnectionMutation = useMutation({
+ mutationFn: async (connectionId: string) => {
+ await $fetch(`@delete/connections/${connectionId}`);
+ },
+ onSuccess: () => {
+ analytics.connectionDeleted();
+ toast.success(
+ 'Connection removal has started. supermemory will permanently delete the documents in the next few minutes.'
+ );
+ queryClient.invalidateQueries({ queryKey: ['connections'] });
+ },
+ onError: (error) => {
+ toast.error('Failed to remove connection', {
+ description: error instanceof Error ? error.message : 'Unknown error',
+ });
+ },
+ });
- const getProviderIcon = (provider: string) => {
- const connector = CONNECTORS[provider as ConnectorProvider]
- if (connector) {
- const Icon = connector.icon
- return <Icon className="h-10 w-10" />
- }
- return <span className="text-2xl">πŸ“Ž</span>
- }
+ const getProviderIcon = (provider: string) => {
+ const connector = CONNECTORS[provider as ConnectorProvider];
+ if (connector) {
+ const Icon = connector.icon;
+ return <Icon className="h-10 w-10" />;
+ }
+ return <span className="text-2xl">πŸ“Ž</span>;
+ };
- return (
- <div className="space-y-4">
- <div className="flex justify-between items-center mb-4">
- <div>
- <p className="text-sm text-white/70">
- Connect your favorite services to import documents
- </p>
- {!isProUser && (
- <p className="text-xs text-white/50 mt-1">
- Connections require a Pro subscription
- </p>
- )}
- </div>
- <motion.div whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
- <Button
- className="bg-white/10 hover:bg-white/20 text-white border-white/20"
- disabled={!canAddConnection && !isProUser}
- onClick={() => setShowAddDialog(true)}
- size="sm"
- >
- <Plus className="h-4 w-4 mr-2" />
- Add
- </Button>
- </motion.div>
- </div>
+ return (
+ <div className="space-y-4">
+ <div className="mb-4">
+ <p className="text-sm text-white/70">
+ Connect your favorite services to import documents
+ </p>
+ {!isProUser && (
+ <p className="text-xs text-white/50 mt-1">
+ Connections require a Pro subscription
+ </p>
+ )}
+ </div>
- {/* Show upgrade prompt for free users */}
- {!isProUser && (
- <motion.div
- animate={{ opacity: 1, y: 0 }}
- className="p-4 bg-yellow-500/10 border border-yellow-500/20 rounded-lg"
- initial={{ opacity: 0, y: -10 }}
- >
- <p className="text-sm text-yellow-400 mb-2">
- πŸ”Œ Connections are a Pro feature
- </p>
- <p className="text-xs text-white/60 mb-3">
- Connect Google Drive, Notion, OneDrive and more to automatically
- sync your documents.
- </p>
- <Button
- asChild
- className="bg-yellow-500/20 hover:bg-yellow-500/30 text-yellow-400 border-yellow-500/30"
- onClick={handleUpgrade}
- size="sm"
- variant="secondary"
- >
- Upgrade to Pro
- </Button>
- </motion.div>
- )}
+ {/* Show upgrade prompt for free users */}
+ {!isProUser && (
+ <motion.div
+ animate={{ opacity: 1, y: 0 }}
+ className="p-4 bg-yellow-500/10 border border-yellow-500/20 rounded-lg"
+ initial={{ opacity: 0, y: -10 }}
+ >
+ <p className="text-sm text-yellow-400 mb-2">
+ πŸ”Œ Connections are a Pro feature
+ </p>
+ <p className="text-xs text-white/60 mb-3">
+ Connect Google Drive, Notion, OneDrive and more to automatically
+ sync your documents.
+ </p>
+ <Button
+ asChild
+ className="bg-yellow-500/20 hover:bg-yellow-500/30 text-yellow-400 border-yellow-500/30"
+ onClick={handleUpgrade}
+ size="sm"
+ variant="secondary"
+ >
+ Upgrade to Pro
+ </Button>
+ </motion.div>
+ )}
- {isLoading ? (
- <div className="space-y-3">
- {[...Array(2)].map((_, i) => (
- <motion.div
- animate={{ opacity: 1 }}
- className="p-4 bg-white/5 rounded-lg"
- initial={{ opacity: 0 }}
- key={`skeleton-${Date.now()}-${i}`}
- transition={{ delay: i * 0.1 }}
- >
- <Skeleton className="h-12 w-full bg-white/10" />
- </motion.div>
- ))}
- </div>
- ) : connections.length === 0 ? (
- <motion.div
- animate={{ opacity: 1, scale: 1 }}
- className="text-center py-8"
- initial={{ opacity: 0, scale: 0.9 }}
- transition={{ type: "spring", damping: 20 }}
- >
- <p className="text-white/50 mb-4">No connections yet</p>
- <motion.div whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
- <Button
- className="bg-white/10 hover:bg-white/20 text-white border-white/20"
- onClick={() => setShowAddDialog(true)}
- size="sm"
- variant="secondary"
- >
- Add Your First Connection
- </Button>
- </motion.div>
- </motion.div>
- ) : (
- <motion.div className="space-y-2">
- <AnimatePresence>
- {connections.map((connection, index) => (
- <motion.div
- animate={{ opacity: 1, x: 0 }}
- className="flex items-center justify-between p-3 bg-white/5 rounded-lg hover:bg-white/10 transition-colors"
- exit={{ opacity: 0, x: 20 }}
- initial={{ opacity: 0, x: -20 }}
- key={connection.id}
- layout
- transition={{ delay: index * 0.05 }}
- >
- <div className="flex items-center gap-3">
- <motion.div
- animate={{ rotate: 0, opacity: 1 }}
- initial={{ rotate: -180, opacity: 0 }}
- transition={{ delay: index * 0.05 + 0.2 }}
- >
- {getProviderIcon(connection.provider)}
- </motion.div>
- <div>
- <p className="font-medium text-white capitalize">
- {connection.provider.replace("-", " ")}
- </p>
- {connection.email && (
- <p className="text-sm text-white/60">
- {connection.email}
- </p>
- )}
- </div>
- </div>
- <motion.div
- whileHover={{ scale: 1.1 }}
- whileTap={{ scale: 0.9 }}
- >
- <Button
- className="text-white/50 hover:text-red-400"
- disabled={deleteConnectionMutation.isPending}
- onClick={() =>
- deleteConnectionMutation.mutate(connection.id)
- }
- size="icon"
- variant="ghost"
- >
- <Trash2 className="h-4 w-4" />
- </Button>
- </motion.div>
- </motion.div>
- ))}
- </AnimatePresence>
- </motion.div>
- )}
+ {isLoading ? (
+ <div className="space-y-3">
+ {[...Array(2)].map((_, i) => (
+ <motion.div
+ animate={{ opacity: 1 }}
+ className="p-4 bg-white/5 rounded-lg"
+ initial={{ opacity: 0 }}
+ key={`skeleton-${Date.now()}-${i}`}
+ transition={{ delay: i * 0.1 }}
+ >
+ <Skeleton className="h-12 w-full bg-white/10" />
+ </motion.div>
+ ))}
+ </div>
+ ) : connections.length === 0 ? (
+ <motion.div
+ animate={{ opacity: 1, scale: 1 }}
+ className="text-center py-4"
+ initial={{ opacity: 0, scale: 0.9 }}
+ transition={{ type: 'spring', damping: 20 }}
+ >
+ <p className="text-white/50 mb-2">No connections yet</p>
+ <p className="text-xs text-white/40">
+ Choose a service below to connect
+ </p>
+ </motion.div>
+ ) : (
+ <motion.div className="space-y-2">
+ <AnimatePresence>
+ {connections.map((connection, index) => (
+ <motion.div
+ animate={{ opacity: 1, x: 0 }}
+ className="flex items-center justify-between p-3 bg-white/5 rounded-lg hover:bg-white/10 transition-colors"
+ exit={{ opacity: 0, x: 20 }}
+ initial={{ opacity: 0, x: -20 }}
+ key={connection.id}
+ layout
+ transition={{ delay: index * 0.05 }}
+ >
+ <div className="flex items-center gap-3">
+ <motion.div
+ animate={{ rotate: 0, opacity: 1 }}
+ initial={{ rotate: -180, opacity: 0 }}
+ transition={{ delay: index * 0.05 + 0.2 }}
+ >
+ {getProviderIcon(connection.provider)}
+ </motion.div>
+ <div>
+ <p className="font-medium text-white capitalize">
+ {connection.provider.replace('-', ' ')}
+ </p>
+ {connection.email && (
+ <p className="text-sm text-white/60">
+ {connection.email}
+ </p>
+ )}
+ </div>
+ </div>
+ <motion.div
+ whileHover={{ scale: 1.1 }}
+ whileTap={{ scale: 0.9 }}
+ >
+ <Button
+ className="text-white/50 hover:text-red-400"
+ disabled={deleteConnectionMutation.isPending}
+ onClick={() =>
+ deleteConnectionMutation.mutate(connection.id)
+ }
+ size="icon"
+ variant="ghost"
+ >
+ <Trash2 className="h-4 w-4" />
+ </Button>
+ </motion.div>
+ </motion.div>
+ ))}
+ </AnimatePresence>
+ </motion.div>
+ )}
- {/* Add Connection Dialog */}
- <AnimatePresence>
- {showAddDialog && (
- <Dialog onOpenChange={setShowAddDialog} open={showAddDialog}>
- <DialogContent className="sm:max-w-2xl bg-black/90 backdrop-blur-xl border-white/10 text-white">
- <motion.div
- animate={{ opacity: 1, scale: 1 }}
- exit={{ opacity: 0, scale: 0.95 }}
- initial={{ opacity: 0, scale: 0.95 }}
- >
- <DialogHeader>
- <DialogTitle>Add a Connection</DialogTitle>
- <DialogDescription className="text-white/60">
- Choose a service to connect and import your documents
- </DialogDescription>
- </DialogHeader>
- <div className="grid gap-3 py-4">
- {Object.entries(CONNECTORS).map(
- ([provider, config], index) => {
- const Icon = config.icon
- return (
- <motion.div
- animate={{ opacity: 1, y: 0 }}
- initial={{ opacity: 0, y: 20 }}
- key={provider}
- transition={{ delay: index * 0.05 }}
- whileHover={{ scale: 1.02 }}
- whileTap={{ scale: 0.98 }}
- >
- <Button
- className="justify-start h-auto p-4 bg-white/5 hover:bg-white/10 border-white/10 text-white w-full"
- disabled={addConnectionMutation.isPending}
- onClick={() => {
- addConnectionMutation.mutate(
- provider as ConnectorProvider,
- )
- setShowAddDialog(false)
- // onClose?.()
- }}
- variant="outline"
- >
- <Icon className="h-8 w-8 mr-3" />
- <div className="text-left">
- <div className="font-medium">{config.title}</div>
- <div className="text-sm text-white/60 mt-0.5">
- {config.description}
- </div>
- </div>
- </Button>
- </motion.div>
- )
- },
- )}
- </div>
- </motion.div>
- </DialogContent>
- </Dialog>
- )}
- </AnimatePresence>
- </div>
- )
+ {/* Available Connections Section */}
+ <div className="mt-6">
+ <h3 className="text-lg font-medium text-white mb-4">
+ Available Connections
+ </h3>
+ <div className="grid gap-3">
+ {Object.entries(CONNECTORS).map(([provider, config], index) => {
+ const Icon = config.icon;
+ return (
+ <motion.div
+ animate={{ opacity: 1, y: 0 }}
+ initial={{ opacity: 0, y: 20 }}
+ key={provider}
+ transition={{ delay: index * 0.05 }}
+ whileHover={{ scale: 1.02 }}
+ whileTap={{ scale: 0.98 }}
+ >
+ <Button
+ className="justify-start h-auto p-4 bg-white/5 hover:bg-white/10 border-white/10 text-white w-full"
+ disabled={addConnectionMutation.isPending}
+ onClick={() => {
+ addConnectionMutation.mutate(provider as ConnectorProvider);
+ }}
+ variant="outline"
+ >
+ <Icon className="h-8 w-8 mr-3" />
+ <div className="text-left">
+ <div className="font-medium">{config.title}</div>
+ <div className="text-sm text-white/60 mt-0.5">
+ {config.description}
+ </div>
+ </div>
+ </Button>
+ </motion.div>
+ );
+ })}
+ </div>
+ </div>
+ </div>
+ );
}
diff --git a/apps/web/public/add-connections.png b/apps/web/public/add-connections.png
new file mode 100644
index 00000000..1f49f4da
--- /dev/null
+++ b/apps/web/public/add-connections.png
Binary files differ
diff --git a/apps/web/public/add-memory.png b/apps/web/public/add-memory.png
new file mode 100644
index 00000000..248ea3e3
--- /dev/null
+++ b/apps/web/public/add-memory.png
Binary files differ
diff --git a/apps/web/public/chat.png b/apps/web/public/chat.png
new file mode 100644
index 00000000..869c27ec
--- /dev/null
+++ b/apps/web/public/chat.png
Binary files differ
diff --git a/apps/web/public/mcp.png b/apps/web/public/mcp.png
new file mode 100644
index 00000000..05ceb619
--- /dev/null
+++ b/apps/web/public/mcp.png
Binary files differ