ui: add animations to properties panel toggle

- Move toggle icon next to three-dots menu in a shared flex container
- Toggle icon fades in/out with opacity transition instead of hard mount/unmount
- Properties panel slides in/out with width + opacity transition (200ms ease-in-out)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dotta
2026-03-03 15:06:42 -06:00
parent c11d2d3eda
commit 31f02a80d8
2 changed files with 28 additions and 20 deletions

View File

@@ -6,10 +6,14 @@ import { ScrollArea } from "@/components/ui/scroll-area";
export function PropertiesPanel() { export function PropertiesPanel() {
const { panelContent, panelVisible, setPanelVisible } = usePanel(); const { panelContent, panelVisible, setPanelVisible } = usePanel();
if (!panelContent || !panelVisible) return null; if (!panelContent) return null;
return ( return (
<aside className="hidden md:flex w-80 border-l border-border bg-card flex-col shrink-0"> <aside
className="hidden md:flex border-l border-border bg-card flex-col shrink-0 overflow-hidden transition-[width,opacity] duration-200 ease-in-out"
style={{ width: panelVisible ? 320 : 0, opacity: panelVisible ? 1 : 0 }}
>
<div className="w-80 flex-1 flex flex-col min-w-[320px]">
<div className="flex items-center justify-between px-4 py-2 border-b border-border"> <div className="flex items-center justify-between px-4 py-2 border-b border-border">
<span className="text-sm font-medium">Properties</span> <span className="text-sm font-medium">Properties</span>
<Button variant="ghost" size="icon-xs" onClick={() => setPanelVisible(false)}> <Button variant="ghost" size="icon-xs" onClick={() => setPanelVisible(false)}>
@@ -19,6 +23,7 @@ export function PropertiesPanel() {
<ScrollArea className="flex-1"> <ScrollArea className="flex-1">
<div className="p-4">{panelContent}</div> <div className="p-4">{panelContent}</div>
</ScrollArea> </ScrollArea>
</div>
</aside> </aside>
); );
} }

View File

@@ -613,21 +613,23 @@ export function IssueDetail() {
<SlidersHorizontal className="h-4 w-4" /> <SlidersHorizontal className="h-4 w-4" />
</Button> </Button>
{!panelVisible && ( <div className="hidden md:flex items-center md:ml-auto shrink-0">
<Button <Button
variant="ghost" variant="ghost"
size="icon-xs" size="icon-xs"
className="hidden md:inline-flex ml-auto shrink-0" className={cn(
"shrink-0 transition-opacity duration-200",
panelVisible ? "opacity-0 pointer-events-none w-0 overflow-hidden" : "opacity-100",
)}
onClick={() => setPanelVisible(true)} onClick={() => setPanelVisible(true)}
title="Show properties" title="Show properties"
> >
<SlidersHorizontal className="h-4 w-4" /> <SlidersHorizontal className="h-4 w-4" />
</Button> </Button>
)}
<Popover open={moreOpen} onOpenChange={setMoreOpen}> <Popover open={moreOpen} onOpenChange={setMoreOpen}>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button variant="ghost" size="icon-xs" className="md:ml-auto shrink-0"> <Button variant="ghost" size="icon-xs" className="shrink-0">
<MoreHorizontal className="h-4 w-4" /> <MoreHorizontal className="h-4 w-4" />
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
@@ -648,6 +650,7 @@ export function IssueDetail() {
</PopoverContent> </PopoverContent>
</Popover> </Popover>
</div> </div>
</div>
<InlineEditor <InlineEditor
value={issue.title} value={issue.title}