aboutsummaryrefslogtreecommitdiff
path: root/apps/web/src/components
diff options
context:
space:
mode:
authorYash <[email protected]>2024-04-11 01:34:49 +0000
committerYash <[email protected]>2024-04-11 01:34:49 +0000
commite6fc9c42278d979b155fd71b1f8f13e72c990208 (patch)
treeaedbe7081527820c473555a32b3edafb2d3ae479 /apps/web/src/components
parentbetter md (diff)
downloadsupermemory-e6fc9c42278d979b155fd71b1f8f13e72c990208.tar.xz
supermemory-e6fc9c42278d979b155fd71b1f8f13e72c990208.zip
ok
Diffstat (limited to 'apps/web/src/components')
-rw-r--r--apps/web/src/components/Sidebar.tsx145
-rw-r--r--apps/web/src/components/Sidebar/AddMemoryDialog.tsx39
-rw-r--r--apps/web/src/components/Sidebar/MemoriesBar.tsx174
3 files changed, 120 insertions, 238 deletions
diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx
deleted file mode 100644
index 66ca1652..00000000
--- a/apps/web/src/components/Sidebar.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-'use client';
-import { StoredContent } from '@/server/db/schema';
-import {
- Plus,
- MoreHorizontal,
- ArrowUpRight,
- Edit3,
- Trash2,
-} from 'lucide-react';
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from './ui/dropdown-menu';
-
-import { useState, useEffect, useRef } from 'react';
-
-export default function Sidebar() {
- const websites: StoredContent[] = [
- {
- id: 1,
- content: '',
- title: 'Visual Studio Code',
- url: 'https://code.visualstudio.com',
- description: '',
- image: 'https://code.visualstudio.com/favicon.ico',
- baseUrl: 'https://code.visualstudio.com',
- savedAt: new Date()
- },
- {
- id: 1,
- content: '',
- title: "yxshv/vscode: An unofficial remake of vscode's landing page",
- url: 'https://github.com/yxshv/vscode',
- description: '',
- image: 'https://github.com/favicon.ico',
- baseUrl: 'https://github.com',
- savedAt: new Date()
- },
- ];
-
- return (
- <aside className="bg-rgray-3 flex h-screen w-[25%] flex-col items-start justify-between py-5 pb-[50vh] font-light">
- <div className="flex items-center justify-center gap-1 px-5 text-xl font-normal">
- <img src="/brain.png" alt="logo" className="h-10 w-10" />
- SuperMemory
- </div>
- <div className="flex w-full flex-col items-start justify-center p-2">
- <h1 className="mb-1 flex w-full items-center justify-center px-3 font-normal">
- Websites
- <button className="ml-auto ">
- <Plus className="h-4 w-4 min-w-4" />
- </button>
- </h1>
- {websites.map((item) => (
- <ListItem key={item.id} item={item} />
- ))}
- </div>
- </aside>
- );
-}
-
-export const ListItem: React.FC<{ item: StoredContent }> = ({ item }) => {
- const [isEditing, setIsEditing] = useState(false);
- const editInputRef = useRef<HTMLInputElement>(null);
-
- useEffect(() => {
- if (isEditing) {
- setTimeout(() => {
- editInputRef.current?.focus();
- }, 500);
- }
- }, [isEditing]);
-
- return (
- <div className="hover:bg-rgray-5 focus-within:bg-rgray-5 flex w-full items-center rounded-full py-1 pl-3 pr-2 transition [&:hover>a>[data-upright-icon]]:block [&:hover>a>img]:hidden [&:hover>button]:opacity-100">
- <a
- href={item.url}
- target="_blank"
- onClick={(e) => isEditing && e.preventDefault()}
- className="flex w-[90%] items-center gap-2 focus:outline-none"
- >
- {isEditing ? (
- <Edit3 className="h-4 w-4" strokeWidth={1.5} />
- ) : (
- <>
- <img
- src={item.image ?? '/brain.png'}
- alt={item.title ?? 'Untitiled website'}
- className="h-4 w-4"
- />
- <ArrowUpRight
- data-upright-icon
- className="hidden h-4 w-4 min-w-4 scale-125"
- strokeWidth={1.5}
- />
- </>
- )}
- {isEditing ? (
- <input
- ref={editInputRef}
- autoFocus
- className="text-rgray-12 w-full bg-transparent focus:outline-none"
- placeholder={item.title ?? 'Untitled website'}
- onBlur={(e) => setIsEditing(false)}
- onKeyDown={(e) => e.key === 'Escape' && setIsEditing(false)}
- />
- ) : (
- <span className="w-full truncate text-nowrap">
- {item.title ?? 'Untitled website'}
- </span>
- )}
- </a>
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <button className="ml-auto w-4 min-w-4 rounded-[0.15rem] opacity-0 focus:opacity-100 focus:outline-none">
- <MoreHorizontal className="h-4 w-4 min-w-4" />
- </button>
- </DropdownMenuTrigger>
- <DropdownMenuContent className="w-5">
- <DropdownMenuItem onClick={() => window.open(item.url)}>
- <ArrowUpRight
- className="mr-2 h-4 w-4 scale-125"
- strokeWidth={1.5}
- />
- Open
- </DropdownMenuItem>
- <DropdownMenuItem
- onClick={(e) => {
- setIsEditing(true);
- }}
- >
- <Edit3 className="mr-2 h-4 w-4 " strokeWidth={1.5} />
- Edit
- </DropdownMenuItem>
- <DropdownMenuItem className="focus:bg-red-100 focus:text-red-400 dark:focus:bg-red-100/10">
- <Trash2 className="mr-2 h-4 w-4 " strokeWidth={1.5} />
- Delete
- </DropdownMenuItem>
- </DropdownMenuContent>
- </DropdownMenu>
- </div>
- );
-};
diff --git a/apps/web/src/components/Sidebar/AddMemoryDialog.tsx b/apps/web/src/components/Sidebar/AddMemoryDialog.tsx
new file mode 100644
index 00000000..1bd4b688
--- /dev/null
+++ b/apps/web/src/components/Sidebar/AddMemoryDialog.tsx
@@ -0,0 +1,39 @@
+import { useEffect, useRef } from "react";
+import {
+ DialogClose,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "../ui/dialog";
+import { Input } from "../ui/input";
+import { Label } from "../ui/label";
+
+export default function AddMemoryPage() {
+ return (
+ <>
+ <DialogHeader>
+ <DialogTitle>Add a web page to memory</DialogTitle>
+ <DialogDescription>
+ This will take you the web page you are trying to add to memory, where
+ the extension will save the page to memory
+ </DialogDescription>
+ </DialogHeader>
+ <Label className="mt-5">URL</Label>
+ <Input
+ placeholder="Enter the URL of the page"
+ type="url"
+ data-autofocus
+ className="bg-rgray-4 mt-2 w-full"
+ />
+ <DialogFooter>
+ <DialogClose className="bg-rgray-4 hover:bg-rgray-5 focus-visible:bg-rgray-5 focus-visible:ring-rgray-7 rounded-md px-4 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2">
+ Add
+ </DialogClose>
+ <DialogClose className="hover:bg-rgray-4 focus-visible:bg-rgray-4 focus-visible:ring-rgray-7 rounded-md px-3 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2">
+ Cancel
+ </DialogClose>
+ </DialogFooter>
+ </>
+ );
+}
diff --git a/apps/web/src/components/Sidebar/MemoriesBar.tsx b/apps/web/src/components/Sidebar/MemoriesBar.tsx
index d7d8b5b5..779dea25 100644
--- a/apps/web/src/components/Sidebar/MemoriesBar.tsx
+++ b/apps/web/src/components/Sidebar/MemoriesBar.tsx
@@ -1,10 +1,13 @@
+import { Editor } from "novel";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import {
MemoryWithImage,
MemoryWithImages3,
MemoryWithImages2,
} from "@/assets/MemoryWithImages";
-import { type CollectedSpaces } from "../../../types/memory";
+import { type CollectedSpaces }
+
+from "../../../types/memory";
import { Input, InputWithIcon } from "../ui/input";
import {
ArrowUpRight,
@@ -22,7 +25,7 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
-import { useState } from "react";
+import { useEffect, useRef, useState } from "react";
import { Variant, useAnimate, motion } from "framer-motion";
import { useMemory } from "@/contexts/MemoryContext";
import { SpaceIcon } from "@/assets/Memories";
@@ -38,6 +41,8 @@ import {
import { Label } from "../ui/label";
import useViewport from "@/hooks/useViewport";
import useTouchHold from "@/hooks/useTouchHold";
+import { DialogTrigger } from "@radix-ui/react-dialog";
+import AddMemoryPage from "./AddMemoryDialog";
export function MemoriesBar() {
const [parent, enableAnimations] = useAutoAnimate();
@@ -59,38 +64,43 @@ export function MemoriesBar() {
/>
</div>
<div className="mt-2 flex w-full px-8">
- <DropdownMenu open={isDropdownOpen} onOpenChange={setIsDropdownOpen}>
- <DropdownMenuTrigger asChild>
- <button className="focus-visible:bg-rgray-4 focus-visible:ring-rgray-7 hover:bg-rgray-4 ml-auto flex items-center justify-center rounded-md px-3 py-2 transition focus-visible:outline-none focus-visible:ring-2">
- <Plus className="mr-2 h-5 w-5" />
- Add
- </button>
- </DropdownMenuTrigger>
- <DropdownMenuContent>
- <DropdownMenuItem
- onClick={() => {
- setIsDropdownOpen(false);
- setAddMemoryState("page");
- }}
- >
- <Sparkles className="mr-2 h-4 w-4" />
- Page to Memory
- </DropdownMenuItem>
- <DropdownMenuItem>
- <Text className="mr-2 h-4 w-4" />
- Note
- </DropdownMenuItem>
- <DropdownMenuItem>
- <SpaceIcon className="mr-2 h-4 w-4" />
- Space
- </DropdownMenuItem>
- </DropdownMenuContent>
- </DropdownMenu>
+ <AddMemoryModal isOpen={isDropdownOpen} type={addMemoryState}>
+ <DropdownMenu open={isDropdownOpen} onOpenChange={setIsDropdownOpen}>
+ <DropdownMenuTrigger asChild>
+ <button className="focus-visible:bg-rgray-4 focus-visible:ring-rgray-7 hover:bg-rgray-4 ml-auto flex items-center justify-center rounded-md px-3 py-2 transition focus-visible:outline-none focus-visible:ring-2">
+ <Plus className="mr-2 h-5 w-5" />
+ Add
+ </button>
+ </DropdownMenuTrigger>
+ <DropdownMenuContent onCloseAutoFocus={(e) => e.preventDefault()}>
+ <DialogTrigger className="block w-full">
+ <DropdownMenuItem
+ onClick={() => {
+ setAddMemoryState("page");
+ }}
+ >
+ <Sparkles className="mr-2 h-4 w-4" />
+ Page to Memory
+ </DropdownMenuItem>
+ </DialogTrigger>
+ <DialogTrigger className="block w-full">
+ <DropdownMenuItem
+ onClick={() => {
+ setAddMemoryState("note");
+ }}
+ >
+ <Text className="mr-2 h-4 w-4" />
+ Note
+ </DropdownMenuItem>
+ </DialogTrigger>
+ <DropdownMenuItem>
+ <SpaceIcon className="mr-2 h-4 w-4" />
+ Space
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
+ </AddMemoryModal>
</div>
- <AddMemoryModal
- state={addMemoryState}
- onStateChange={setAddMemoryState}
- />
<div
ref={parent}
className="grid w-full grid-flow-row grid-cols-3 gap-1 px-2 py-5"
@@ -295,69 +305,47 @@ export function SpaceMoreButton({
}
export function AddMemoryModal({
- state,
- onStateChange,
+ type,
+ children,
+ isOpen,
}: {
- state: "page" | "note" | "space" | null;
- onStateChange: (state: "page" | "note" | "space" | null) => void;
+ type: "page" | "note" | "space" | null;
+ children?: React.ReactNode | React.ReactNode[];
+ isOpen: boolean;
}) {
return (
- <>
- <Dialog
- open={state === "page"}
- onOpenChange={(open) => onStateChange(open ? "page" : null)}
+ <Dialog>
+ {children}
+ <DialogContent
+ onOpenAutoFocus={(e) => {
+ e.preventDefault();
+ (
+ document.querySelector("[data-autofocus]") as
+ | HTMLInputElement
+ | undefined
+ )?.focus();
+ }}
>
- <DialogContent>
- <DialogHeader>
- <DialogTitle>Add a web page to memory</DialogTitle>
- <DialogDescription>
- This will take you the web page you are trying to add to memory,
- where the extension will save the page to memory
- </DialogDescription>
- </DialogHeader>
- <Label className="mt-5">URL</Label>
- <Input
- autoFocus
- placeholder="Enter the URL of the page"
- type="url"
- className="bg-rgray-4 mt-2 w-full"
- />
- <DialogFooter>
- <DialogClose className="bg-rgray-4 hover:bg-rgray-5 focus-visible:bg-rgray-5 focus-visible:ring-rgray-7 rounded-md px-4 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2">
- Add
- </DialogClose>
- <DialogClose className="hover:bg-rgray-4 focus-visible:bg-rgray-4 focus-visible:ring-rgray-7 rounded-md px-3 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2">
- Cancel
- </DialogClose>
- </DialogFooter>
- </DialogContent>
- </Dialog>
- <Dialog open={state === "note"}>
- <DialogContent>
- <DialogHeader>
- <DialogTitle>Add a web page to memory</DialogTitle>
- <DialogDescription>
- This will take you the web page you are trying to add to memory,
- where the extension will save the page to memory
- </DialogDescription>
- </DialogHeader>
- <Label className="mt-5">URL</Label>
- <Input
- autoFocus
- placeholder="Enter the URL of the page"
- type="url"
- className="bg-rgray-4 mt-2 w-full"
- />
- <DialogFooter>
- <DialogClose className="bg-rgray-4 hover:bg-rgray-5 focus-visible:bg-rgray-5 focus-visible:ring-rgray-7 rounded-md px-4 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2">
- Add
- </DialogClose>
- <DialogClose className="hover:bg-rgray-4 focus-visible:bg-rgray-4 focus-visible:ring-rgray-7 rounded-md px-3 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2">
- Cancel
- </DialogClose>
- </DialogFooter>
- </DialogContent>
- </Dialog>
- </>
+ {type === "page" && <AddMemoryPage />}
+ {type === "note" && (
+ <>
+ <Input
+ className="w-full border-none p-0 text-xl ring-0 placeholder:text-white/30 focus-visible:ring-0"
+ placeholder="Name of the note"
+ data-autofocus
+ />
+ <Editor />
+ <DialogFooter>
+ <DialogClose className="bg-rgray-4 hover:bg-rgray-5 focus-visible:bg-rgray-5 focus-visible:ring-rgray-7 rounded-md px-4 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2">
+ Add
+ </DialogClose>
+ <DialogClose className="hover:bg-rgray-4 focus-visible:bg-rgray-4 focus-visible:ring-rgray-7 rounded-md px-3 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2">
+ Cancel
+ </DialogClose>
+ </DialogFooter>
+ </>
+ )}
+ </DialogContent>
+ </Dialog>
);
}