diff --git a/app/globals.css b/app/globals.css index 99ee3de..8440565 100644 --- a/app/globals.css +++ b/app/globals.css @@ -380,3 +380,27 @@ textarea:focus-visible { animation: none; } } + +/* The row-options menu pops from its anchor corner and slips away on close + (the anchor corner comes from an origin-* utility on the element). */ +@keyframes menuPopIn { + from { opacity: 0; transform: scale(0.92); } + to { opacity: 1; transform: scale(1); } +} +@keyframes menuPopOut { + from { opacity: 1; transform: scale(1); } + to { opacity: 0; transform: scale(0.96); } +} +.menu-pop { + animation: menuPopIn 130ms cubic-bezier(0.2, 0.7, 0.2, 1); +} +.menu-pop[data-closing] { + animation: menuPopOut 90ms ease-in forwards; + pointer-events: none; +} +@media (prefers-reduced-motion: reduce) { + .menu-pop, + .menu-pop[data-closing] { + animation: none; + } +} diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx index 9803ae6..dfdf152 100644 --- a/components/Sidebar.tsx +++ b/components/Sidebar.tsx @@ -7,6 +7,7 @@ import { ColorSwatchRow } from "@/components/ColorSwatchRow"; import { noteColorVar } from "@/lib/noteColors"; import { downloadNoteBody, downloadNotePdf } from "@/lib/downloadNote"; import { SyncStatus } from "@/lib/useNotes"; +import { useMenuPresence } from "@/lib/useMenuPresence"; import { Note } from "@/lib/types"; import { DotsIcon, @@ -459,6 +460,7 @@ function SidebarNoteRow({ onColor: (color: string | null) => void; }) { const [menuOpen, setMenuOpen] = useState(false); + const { mounted: menuMounted, closing: menuClosing } = useMenuPresence(menuOpen); const [flipUp, setFlipUp] = useState(false); const [isRenaming, setIsRenaming] = useState(false); const [renameValue, setRenameValue] = useState(""); @@ -575,16 +577,19 @@ function SidebarNoteRow({ > )} - {menuOpen && ( + {menuMounted && ( <> -