diff options
| author | Yash <[email protected]> | 2024-04-04 08:34:48 +0000 |
|---|---|---|
| committer | Yash <[email protected]> | 2024-04-04 08:34:48 +0000 |
| commit | c22751ee68d9fdd4e5bc5147922de32a20abf484 (patch) | |
| tree | ff5f4051cb8cd973a18a5431a0300ed8edbe63fb /apps/web/src | |
| parent | fix content paths (diff) | |
| download | supermemory-c22751ee68d9fdd4e5bc5147922de32a20abf484.tar.xz supermemory-c22751ee68d9fdd4e5bc5147922de32a20abf484.zip | |
add custom Bin component
Diffstat (limited to 'apps/web/src')
| -rw-r--r-- | apps/web/src/assets/Bin.tsx | 104 | ||||
| -rw-r--r-- | apps/web/src/assets/Memories.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/Main.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/Sidebar/MemoriesBar.tsx | 375 | ||||
| -rw-r--r-- | apps/web/src/components/Sidebar/index.tsx | 61 | ||||
| -rw-r--r-- | apps/web/src/components/ui/dropdown-menu.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/ui/popover.tsx | 39 |
7 files changed, 440 insertions, 145 deletions
diff --git a/apps/web/src/assets/Bin.tsx b/apps/web/src/assets/Bin.tsx new file mode 100644 index 00000000..d0793cef --- /dev/null +++ b/apps/web/src/assets/Bin.tsx @@ -0,0 +1,104 @@ +import { cn } from "@/lib/utils"; +import { useEffect, useRef } from "react"; + +export const Bin: React.FC<React.HTMLAttributes<HTMLDivElement> & {}> = ({ + className, + ...props +}) => { + const icon = useRef<HTMLDivElement>(null); + + useEffect(() => { + let timeout: ReturnType<typeof setTimeout> | undefined; + + const observer = new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + if ( + mutation.type === "attributes" && + mutation.attributeName === "data-open" && + (mutation.oldValue === "false" || mutation.oldValue === null) && + icon.current?.dataset["open"] === "true" + ) { + if (timeout) clearTimeout(timeout); + timeout = setTimeout(() => { + icon.current!.dataset["open"] = "false"; + }, 2000); + } + }); + }); + + observer.observe(icon.current!, { + attributes: true, //configure it to listen to attribute changes + }); + + return () => { + observer.disconnect(); + }; + }, []); + + return ( + <div + ref={icon} + data-open="false" + className={cn( + "relative z-[100] flex w-full origin-bottom flex-col items-center justify-center transition-transform delay-500 duration-500 data-[open='true']:-translate-y-2 data-[open='true']:scale-150 data-[open='true']:delay-0 [&[data-open='true']>[data-lid]]:rotate-[150deg] [&[data-open='true']>[data-lid]]:delay-0", + className, + )} + {...props} + > + <svg + data-lid + className="w-full origin-[90%_80%] transition-transform delay-500 duration-500 ease-in-out" + viewBox="0 0 24 7" + fill="none" + strokeWidth={1} + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M3 6H21" + stroke="currentColor" + strokeWidth={1} + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M8 6V4C8 3 9 2 10 2H14C15 2 16 3 16 4V6" + stroke="currentColor" + strokeWidth={1} + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + + <svg + className="-mt-[1px] w-full" + viewBox="0 0 24 19" + fill="none" + strokeWidth={1} + data-trash-bin + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M19 1V15C19 16 18 17 17 17H7C6 17 5 16 5 15V1" + stroke="currentColor" + strokeWidth={1} + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M10 6V12" + stroke="currentColor" + strokeWidth={1} + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M14 6V12" + stroke="currentColor" + strokeWidth={1} + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + </div> + ); +}; diff --git a/apps/web/src/assets/Memories.tsx b/apps/web/src/assets/Memories.tsx index f8fd83b8..3b1c177f 100644 --- a/apps/web/src/assets/Memories.tsx +++ b/apps/web/src/assets/Memories.tsx @@ -1,5 +1,3 @@ -import { svgId } from "@/lib/utils"; - export const MemoryIcon: React.FC<React.SVGAttributes<SVGElement>> = ( props, ) => ( diff --git a/apps/web/src/components/Main.tsx b/apps/web/src/components/Main.tsx index ef505db5..8796c52e 100644 --- a/apps/web/src/components/Main.tsx +++ b/apps/web/src/components/Main.tsx @@ -13,6 +13,8 @@ export default function Main({ sidebarOpen }: { sidebarOpen: boolean }) { const textArea = useRef<HTMLTextAreaElement>(null); + console.log("main px", sidebarOpen); + useEffect(() => { function onResize() { if (!textArea.current || !window.visualViewport) return; diff --git a/apps/web/src/components/Sidebar/MemoriesBar.tsx b/apps/web/src/components/Sidebar/MemoriesBar.tsx index 2890af56..367f0173 100644 --- a/apps/web/src/components/Sidebar/MemoriesBar.tsx +++ b/apps/web/src/components/Sidebar/MemoriesBar.tsx @@ -1,3 +1,4 @@ +import { useAutoAnimate } from "@formkit/auto-animate/react"; import { MemoryWithImage, MemoryWithImages3, @@ -5,99 +6,125 @@ import { } from "@/assets/MemoryWithImages"; import { type Space } from "../../../types/memory"; import { InputWithIcon } from "../ui/input"; -import { MoreHorizontal, Search } from "lucide-react"; +import { + ArrowUpRight, + Edit3, + MoreHorizontal, + Search, + Trash2, +} from "lucide-react"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "../ui/dropdown-menu"; +import { + animate, + AnimatePresence, + LayoutGroup, + motion, + useAnimate, + Variant, +} from "framer-motion"; +import { useRef, useState } from "react"; + +const spaces: Space[] = [ + { + id: 1, + title: "Cool Tech", + description: "Really cool mind blowing tech", + content: [ + { + id: 1, + title: "Perplexity", + description: "A good ui", + content: "", + image: "https://perplexity.ai/favicon.ico", + url: "https://perplexity.ai", + savedAt: new Date(), + baseUrl: "https://perplexity.ai", + space: "Cool tech", + }, + { + id: 2, + title: "Pi.ai", + description: "A good ui", + content: "", + image: "https://pi.ai/pi-logo-192.png?v=2", + url: "https://pi.ai", + savedAt: new Date(), + baseUrl: "https://pi.ai", + space: "Cool tech", + }, + { + id: 3, + title: "Visual Studio Code", + description: "A good ui", + content: "", + image: "https://code.visualstudio.com/favicon.ico", + url: "https://code.visualstudio.com", + savedAt: new Date(), + baseUrl: "https://code.visualstudio.com", + space: "Cool tech", + }, + ], + }, + { + id: 2, + title: "Cool Courses", + description: "Amazng", + content: [ + { + id: 1, + title: "Animation on the web", + description: "A good ui", + content: "", + image: "https://animations.dev/favicon.ico", + url: "https://animations.dev", + savedAt: new Date(), + baseUrl: "https://animations.dev", + space: "Cool courses", + }, + { + id: 2, + title: "Tailwind Course", + description: "A good ui", + content: "", + image: + "https://tailwindcss.com/_next/static/media/tailwindcss-mark.3c5441fc7a190fb1800d4a5c7f07ba4b1345a9c8.svg", + url: "https://tailwindcss.com", + savedAt: new Date(), + baseUrl: "https://tailwindcss.com", + space: "Cool courses", + }, + ], + }, + { + id: 3, + title: "Cool Libraries", + description: "Really cool mind blowing tech", + content: [ + { + id: 1, + title: "Perplexity", + description: "A good ui", + content: "", + image: "https://yashverma.me/logo.jpg", + url: "https://perplexity.ai", + savedAt: new Date(), + baseUrl: "https://perplexity.ai", + space: "Cool libraries", + }, + ], + }, +]; export function MemoriesBar() { - const spaces: Space[] = [ - { - id: 1, - title: "Cool Tech", - description: "Really cool mind blowing tech", - content: [ - { - id: 1, - title: "Perplexity", - description: "A good ui", - content: "", - image: "https://perplexity.ai/favicon.ico", - url: "https://perplexity.ai", - savedAt: new Date(), - baseUrl: "https://perplexity.ai", - space: "Cool tech", - }, - { - id: 2, - title: "Pi.ai", - description: "A good ui", - content: "", - image: "https://pi.ai/pi-logo-192.png?v=2", - url: "https://pi.ai", - savedAt: new Date(), - baseUrl: "https://pi.ai", - space: "Cool tech", - }, - { - id: 3, - title: "Visual Studio Code", - description: "A good ui", - content: "", - image: "https://code.visualstudio.com/favicon.ico", - url: "https://code.visualstudio.com", - savedAt: new Date(), - baseUrl: "https://code.visualstudio.com", - space: "Cool tech", - }, - ], - }, - { - id: 2, - title: "Cool Courses", - description: "Amazng", - content: [ - { - id: 1, - title: "Animation on the web", - description: "A good ui", - content: "", - image: "https://animations.dev/favicon.ico", - url: "https://animations.dev", - savedAt: new Date(), - baseUrl: "https://animations.dev", - space: "Cool courses", - }, - { - id: 2, - title: "Tailwind Course", - description: "A good ui", - content: "", - image: - "https://tailwindcss.com/_next/static/media/tailwindcss-mark.3c5441fc7a190fb1800d4a5c7f07ba4b1345a9c8.svg", - url: "https://tailwindcss.com", - savedAt: new Date(), - baseUrl: "https://tailwindcss.com", - space: "Cool courses", - }, - ], - }, - { - id: 3, - title: "Cool Libraries", - description: "Really cool mind blowing tech", - content: [ - { - id: 1, - title: "Perplexity", - description: "A good ui", - content: "", - image: "https://yashverma.me/logo.jpg", - url: "https://perplexity.ai", - savedAt: new Date(), - baseUrl: "https://perplexity.ai", - space: "Cool libraries", - }, - ], - }, - ]; + const [parent, enableAnimations] = useAutoAnimate(); + const [currentSpaces, setCurrentSpaces] = useState(spaces); + + console.log("currentSpaces: ", currentSpaces); return ( <div className="text-rgray-11 flex w-full flex-col items-start py-8 text-left"> @@ -109,28 +136,129 @@ export function MemoriesBar() { className="bg-rgray-4 mt-2 w-full" /> </div> - <div className="grid w-full grid-flow-row grid-cols-3 gap-1 px-2 py-5"> - {spaces.map((space) => ( - <Space key={space.id} {...space} /> + <div + ref={parent} + className="grid w-full grid-flow-row grid-cols-3 gap-1 px-2 py-5" + > + {currentSpaces.map((space) => ( + <SpaceItem + onDelete={() => + setCurrentSpaces((prev) => prev.filter((s) => s.id !== space.id)) + } + key={space.id} + {...space} + /> ))} </div> </div> ); } -export function Space({ title, description, content, id }: Space) { - console.log(title, content.map((c) => c.image).reverse()); +const SpaceExitVariant: Variant = { + opacity: 0, + scale: 0, + borderRadius: "50%", + background: "var(--gray-1)", + transition: { + duration: 0.2, + }, +}; + +export function SpaceItem({ + title, + description, + content, + id, + onDelete, +}: Space & { onDelete: () => void }) { + const [itemRef, animateItem] = useAnimate(); + return ( - <div className="hover:bg-rgray-2 has-[[data-space-text]:focus-visible]:bg-rgray-2 has-[[data-space-text]:focus-visible]:ring-rgray-7 [&:has-[[data-space-text]:focus-visible]>[data-more-button]]:opacity-100 relative flex flex-col-reverse items-center justify-center rounded-md p-2 pb-4 text-center font-normal ring-transparent transition has-[[data-space-text]:focus-visible]:outline-none has-[[data-space-text]:focus-visible]:ring-2 [&:hover>[data-more-button]]:opacity-100"> + <motion.div + ref={itemRef} + className="hover:bg-rgray-2 has-[[data-space-text]:focus-visible]:bg-rgray-2 has-[[data-space-text]:focus-visible]:ring-rgray-7 [&:has-[[data-space-text]:focus-visible]>[data-more-button]]:opacity-100 relative flex flex-col-reverse items-center justify-center rounded-md p-2 pb-4 text-center font-normal ring-transparent transition has-[[data-space-text]:focus-visible]:outline-none has-[[data-space-text]:focus-visible]:ring-2 [&:hover>[data-more-button]]:opacity-100" + > <button data-space-text className="focus-visible:outline-none"> {title} </button> - <button - data-more-button - className="hover:bg-rgray-3 focus-visible:bg-rgray-3 focus-visible:ring-rgray-7 absolute right-2 top-2 rounded-md p-1 opacity-0 ring-transparent transition focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2" - > - <MoreHorizontal className="text-rgray-11 h-5 w-5" /> - </button> + <SpaceMoreButton + onDelete={() => { + if (!itemRef.current) return; + const trash = document.querySelector("#trash")! as HTMLDivElement; + const trashBin = document.querySelector("#trash-button")!; + const trashRect = trashBin.getBoundingClientRect(); + const scopeRect = itemRef.current.getBoundingClientRect(); + const el = document.createElement("div"); + el.style.position = "fixed"; + el.style.top = "0"; + el.style.left = "0"; + el.style.width = "15px"; + el.style.height = "15px"; + el.style.backgroundColor = "var(--gray-7)"; + el.style.zIndex = "60"; + el.style.borderRadius = "50%"; + el.style.transform = "scale(5)"; + el.style.opacity = "0"; + trash.dataset["open"] = "true"; + const initial = { + x: scopeRect.left + scopeRect.width / 2, + y: scopeRect.top + scopeRect.height / 2, + }; + const delta = { + x: + trashRect.left + + trashRect.width / 2 - + scopeRect.left + + scopeRect.width / 2, + y: + trashRect.top + + trashRect.height / 4 - + scopeRect.top + + scopeRect.height / 2, + }; + const end = { + x: trashRect.left + trashRect.width / 2, + y: trashRect.top + trashRect.height / 4, + }; + el.style.offsetPath = `path('M ${initial.x} ${initial.y} Q ${delta.x * 0.01} ${delta.y * 0.01} ${end.x} ${end.y}`; + animateItem(itemRef.current, SpaceExitVariant, { + duration: 0.2, + }).then(() => { + itemRef.current.style.scale = "0"; + onDelete(); + }); + document.body.appendChild(el); + el.animate( + { + transform: ["scale(5)", "scale(1)"], + opacity: [0, 0.3, 1], + }, + { + duration: 200, + easing: "cubic-bezier(0.64, 0.57, 0.67, 1.53)", + fill: "forwards", + }, + ); + el.animate( + { + offsetDistance: ["0%", "100%"], + }, + { + duration: 2000, + easing: "cubic-bezier(0.64, 0.57, 0.67, 1.53)", + fill: "forwards", + delay: 200, + }, + ).onfinish = () => { + el.animate( + { transform: "scale(0)", opacity: 0 }, + { duration: 200, fill: "forwards" }, + ).onfinish = () => { + el.remove(); + }; + }; + }} + /> {content.length > 2 ? ( <MemoryWithImages3 className="h-24 w-24" @@ -150,6 +278,45 @@ export function Space({ title, description, content, id }: Space) { images={content.map((c) => c.image).reverse() as string[]} /> )} - </div> + </motion.div> + ); +} + +export function SpaceMoreButton({ onDelete }: { onDelete?: () => void }) { + const [isOpen, setIsOpen] = useState(false); + + return ( + <> + <DropdownMenu open={isOpen} onOpenChange={setIsOpen}> + <DropdownMenuTrigger asChild> + <button + data-more-button + className="hover:bg-rgray-3 focus-visible:bg-rgray-3 focus-visible:ring-rgray-7 absolute right-2 top-2 rounded-md p-1 opacity-0 ring-transparent transition focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2" + > + <MoreHorizontal className="text-rgray-11 h-5 w-5" /> + </button> + </DropdownMenuTrigger> + <DropdownMenuContent> + <DropdownMenuItem> + <ArrowUpRight + className="mr-2 h-4 w-4 scale-125" + strokeWidth={1.5} + /> + Open + </DropdownMenuItem> + <DropdownMenuItem onClick={() => {}}> + <Edit3 className="mr-2 h-4 w-4" strokeWidth={1.5} /> + Edit + </DropdownMenuItem> + <DropdownMenuItem + onClick={onDelete} + 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} /> + Move to Trash + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + </> ); } diff --git a/apps/web/src/components/Sidebar/index.tsx b/apps/web/src/components/Sidebar/index.tsx index 49ce446a..fe5fcb0a 100644 --- a/apps/web/src/components/Sidebar/index.tsx +++ b/apps/web/src/components/Sidebar/index.tsx @@ -2,9 +2,10 @@ import { StoredContent } from "@/server/db/schema"; import { MemoryIcon } from "../../assets/Memories"; import { Trash2, User2 } from "lucide-react"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { MemoriesBar } from "./MemoriesBar"; import { AnimatePresence, motion } from "framer-motion"; +import { Bin } from "@/assets/Bin"; export type MenuItem = { icon: React.ReactNode | React.ReactNode[]; @@ -39,34 +40,46 @@ export default function Sidebar({ const menuItems = [...menuItemsTop, ...menuItemsBottom]; const [selectedItem, setSelectedItem] = useState<string | null>(null); - React.useEffect(() => { - onSelectChange?.(selectedItem); - }, [selectedItem]); - const Subbar = menuItems.find((i) => i.label === selectedItem)?.content ?? (() => <></>); + useEffect(() => { + onSelectChange?.(selectedItem); + }, [selectedItem]); + return ( <> <div className="relative hidden h-screen max-h-screen w-max flex-col items-center text-sm font-light md:flex"> - <div className="bg-rgray-2 border-r-rgray-6 relative z-[10000] flex h-full w-full flex-col items-center justify-center border-r px-2 py-5 "> - {menuItemsTop.map((item, index) => ( - <MenuItem - key={index} - item={item} - selectedItem={selectedItem} - setSelectedItem={setSelectedItem} - /> - ))} + <div className="bg-rgray-2 border-r-rgray-6 relative z-[50] flex h-full w-full flex-col items-center justify-center border-r px-2 py-5 "> + <MenuItem + item={{ + label: "Memories", + icon: <MemoryIcon className="h-10 w-10" />, + content: MemoriesBar, + }} + selectedItem={selectedItem} + setSelectedItem={setSelectedItem} + /> + <div className="mt-auto" /> - {menuItemsBottom.map((item, index) => ( - <MenuItem - key={index} - item={item} - selectedItem={selectedItem} - setSelectedItem={setSelectedItem} - /> - ))} + + <MenuItem + item={{ + label: "Trash", + icon: <Bin id="trash" className="z-[300] h-7 w-7" />, + }} + selectedItem={selectedItem} + id='trash-button' + setSelectedItem={setSelectedItem} + /> + <MenuItem + item={{ + label: "Profile", + icon: <User2 strokeWidth={1.3} className="h-7 w-7" />, + }} + selectedItem={selectedItem} + setSelectedItem={setSelectedItem} + /> </div> <AnimatePresence> {selectedItem && ( @@ -84,7 +97,8 @@ const MenuItem = ({ item: { icon, label }, selectedItem, setSelectedItem, -}: { + ...props +}: React.HTMLAttributes<HTMLButtonElement> & { item: MenuItem; selectedItem: string | null; setSelectedItem: React.Dispatch<React.SetStateAction<string | null>>; @@ -93,6 +107,7 @@ const MenuItem = ({ data-state-on={selectedItem === label} onClick={() => setSelectedItem((prev) => (prev === label ? null : label))} className="on:opacity-100 on:bg-rgray-4 focus-visible:ring-rgray-7 relative z-[100] flex w-full flex-col items-center justify-center rounded-md px-3 py-3 opacity-80 ring-2 ring-transparent transition hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none" + {...props} > {icon} <span className="">{label}</span> diff --git a/apps/web/src/components/ui/dropdown-menu.tsx b/apps/web/src/components/ui/dropdown-menu.tsx index 375662bb..cbc5cb1e 100644 --- a/apps/web/src/components/ui/dropdown-menu.tsx +++ b/apps/web/src/components/ui/dropdown-menu.tsx @@ -65,7 +65,7 @@ const DropdownMenuContent = React.forwardRef< ref={ref} sideOffset={sideOffset} className={cn( - "data-[state=open]:animate-in bg-rgray-3 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-rgray-6 text-rgray-11 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md", + "data-[state=open]:animate-in bg-rgray-3 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-rgray-6 text-rgray-11 z-50 min-w-[9rem] overflow-hidden rounded-md border p-1 shadow-md", className, )} {...props} diff --git a/apps/web/src/components/ui/popover.tsx b/apps/web/src/components/ui/popover.tsx index 0c4563a8..cabe76a9 100644 --- a/apps/web/src/components/ui/popover.tsx +++ b/apps/web/src/components/ui/popover.tsx @@ -11,21 +11,30 @@ const PopoverTrigger = PopoverPrimitive.Trigger; const PopoverContent = React.forwardRef< React.ElementRef<typeof PopoverPrimitive.Content>, - React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> ->(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( - <PopoverPrimitive.Portal> - <PopoverPrimitive.Content - ref={ref} - align={align} - sideOffset={sideOffset} - className={cn( - "border-rgray-6 bg-rgray-3 text-rgray-11 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none", - className, - )} - {...props} - /> - </PopoverPrimitive.Portal> -)); + React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & { + animate?: boolean; + } +>( + ( + { className, align = "center", animate = true, sideOffset = 4, ...props }, + ref, + ) => ( + <PopoverPrimitive.Portal> + <PopoverPrimitive.Content + ref={ref} + align={align} + sideOffset={sideOffset} + className={cn( + "border-rgray-6 bg-rgray-3 text-rgray-11 z-50 w-72 rounded-md border p-4 shadow-md outline-none", + animate && + "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", + className, + )} + {...props} + /> + </PopoverPrimitive.Portal> + ), +); PopoverContent.displayName = PopoverPrimitive.Content.displayName; export { Popover, PopoverTrigger, PopoverContent }; |