diff options
| author | Yash <[email protected]> | 2024-04-11 10:22:55 +0530 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-04-11 10:22:55 +0530 |
| commit | 628a01709be73b3b1d5859d2878a0bdc768d14fd (patch) | |
| tree | 179aa936536510cc707368fc7c330c4c7fbdc3f8 /apps/web/src/components | |
| parent | save user ID with url to ensure that same website can be saved by users (diff) | |
| parent | Merge branch 'main' of https://github.com/Dhravya/supermemory into new-ui (diff) | |
| download | supermemory-628a01709be73b3b1d5859d2878a0bdc768d14fd.tar.xz supermemory-628a01709be73b3b1d5859d2878a0bdc768d14fd.zip | |
Merge pull request #5 from Dhravya/new-ui
New UI
Diffstat (limited to 'apps/web/src/components')
| -rw-r--r-- | apps/web/src/components/Sidebar.tsx | 145 | ||||
| -rw-r--r-- | apps/web/src/components/Sidebar/AddMemoryDialog.tsx | 64 | ||||
| -rw-r--r-- | apps/web/src/components/Sidebar/MemoriesBar.tsx | 168 |
3 files changed, 140 insertions, 237 deletions
diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx deleted file mode 100644 index f19deeb5..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 ?? "/icons/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..5a1d92f0 --- /dev/null +++ b/apps/web/src/components/Sidebar/AddMemoryDialog.tsx @@ -0,0 +1,64 @@ +import { Editor } from "novel"; +import { + DialogClose, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "../ui/dialog"; +import { Input } from "../ui/input"; +import { Label } from "../ui/label"; +import { useRef } from "react"; + +export 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-modal-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> + </> + ); +} + +export function NoteAddPage() { + return ( + <> + <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-modal-autofocus + /> + <Editor + disableLocalStorage + className="novel-editor bg-rgray-4 border-rgray-7 dark mt-5 max-h-[60vh] min-h-[40vh] w-[50vw] overflow-y-auto rounded-lg border [&>div>div]:p-5" + /> + <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..83984233 100644 --- a/apps/web/src/components/Sidebar/MemoriesBar.tsx +++ b/apps/web/src/components/Sidebar/MemoriesBar.tsx @@ -1,3 +1,4 @@ +import { Editor } from "novel"; import { useAutoAnimate } from "@formkit/auto-animate/react"; import { MemoryWithImage, @@ -22,7 +23,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 +39,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, NoteAddPage } from "./AddMemoryDialog"; export function MemoriesBar() { const [parent, enableAnimations] = useAutoAnimate(); @@ -59,38 +62,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 +303,45 @@ 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(); + const novel = document.querySelector('[contenteditable="true"]') as + | HTMLDivElement + | undefined; + if (novel) { + novel.autofocus = false; + novel.onfocus = () => { + ( + document.querySelector("[data-modal-autofocus]") as + | HTMLInputElement + | undefined + )?.focus(); + novel.onfocus = null; + }; + } + ( + document.querySelector("[data-modal-autofocus]") as + | HTMLInputElement + | undefined + )?.focus(); + }} + className="w-max max-w-[auto]" > - <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" && <NoteAddPage />} + </DialogContent> + </Dialog> ); } |