Skip to content

Commit 48ada6a

Browse files
improve dropdown (#670)
1 parent 9f9e1d9 commit 48ada6a

File tree

1 file changed

+78
-49
lines changed

1 file changed

+78
-49
lines changed
+78-49
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
"use client";
2+
3+
import { useState, useEffect } from "react";
24
import {
35
DropdownMenu,
46
DropdownMenuContent,
57
DropdownMenuItem,
68
DropdownMenuLabel,
79
DropdownMenuSeparator,
810
DropdownMenuTrigger,
11+
Button,
912
} from "@repo/ui";
10-
import { signOut } from "next-auth/react";
11-
import { useSession } from "next-auth/react";
13+
import { signOut, useSession } from "next-auth/react";
1214
import { LogOut, UserRound } from "lucide-react";
1315
import { useRouter } from "next/navigation";
1416
import UserImage from "./UserImage";
17+
import { motion, AnimatePresence } from "framer-motion";
1518

1619
const dropDownData = [
1720
{
@@ -22,66 +25,92 @@ const dropDownData = [
2225
];
2326

2427
export default function UserAccountDropDown() {
25-
const session = useSession();
26-
const user = session.data?.user;
28+
const { data: session, status } = useSession();
29+
const user = session?.user;
2730
const router = useRouter();
28-
return (
29-
<>
30-
{user && (
31-
<DropdownMenu>
32-
<DropdownMenuTrigger className="w-[2rem] flex items-center p-[0.2rem] justify-center h-[2rem]">
33-
{!user.image ? (
34-
<div className="p-1 border-2 rounded-md border-[#1a1a1a]">
35-
<UserRound />
36-
</div>
37-
) : (
38-
<UserImage image={user.image} />
39-
)}
40-
</DropdownMenuTrigger>
31+
const [isOpen, setIsOpen] = useState(false);
32+
const [mounted, setMounted] = useState(false);
4133

42-
<DropdownMenuContent className="!w-[15rem] dark:shadow-[#030712] translate-y-8 scale-110 -translate-x-10 shadow-lg">
43-
<DropdownMenuLabel className="flex gap-4 items-center">
44-
<div className="!w-[2rem] flex items-center p-[0.2rem] justify-center !h-[2rem]">
45-
{!user.image ? (
46-
<div className="p-1 border-2 rounded-full border-[#1a1a1a]">
47-
<UserRound />
48-
</div>
49-
) : (
50-
<UserImage image={user.image} />
51-
)}
52-
</div>
34+
useEffect(() => {
35+
setMounted(true);
36+
}, []);
5337

54-
<div className="flex flex-col">
55-
<span className="max-w-[200px]">{user?.name}</span>
56-
<span className="text-[0.8rem] max-w-[200px] text-gray-400">{user?.email}</span>
38+
if (!mounted || status === "loading") return null;
39+
if (!user) return null;
40+
41+
return (
42+
<DropdownMenu onOpenChange={setIsOpen}>
43+
<DropdownMenuTrigger asChild>
44+
<Button
45+
variant="ghost"
46+
className="bg-secondary/15 hover:bg-secondary/25 flex items-center gap-2 rounded-xl px-3 py-2 shadow-sm transition-all duration-200 hover:shadow-md"
47+
>
48+
<div className="border-primary/20 h-8 w-8 overflow-hidden rounded-full border-2">
49+
{user.image ? (
50+
<UserImage image={user.image} />
51+
) : (
52+
<div className="from-primary-400 to-primary-600 flex h-full w-full items-center justify-center bg-gradient-to-br text-white">
53+
<UserRound size={16} />
5754
</div>
58-
</DropdownMenuLabel>
59-
<DropdownMenuSeparator />
55+
)}
56+
</div>
57+
</Button>
58+
</DropdownMenuTrigger>
6059

61-
{dropDownData.map((item, index) => {
62-
return (
63-
<DropdownMenuItem className="flex gap-2" onClick={() => router.push("/profile")} key={index}>
64-
<span>{item.icon}</span>
65-
<span>{item.name}</span>
60+
<AnimatePresence>
61+
{isOpen && (
62+
<DropdownMenuContent
63+
forceMount
64+
className="bg-secondary/15 border-primary/10 rounded-2xl border p-2 shadow-lg shadow-neutral-600/5 backdrop-blur-lg"
65+
align="end"
66+
>
67+
<motion.div
68+
initial={{ opacity: 0, y: -10 }}
69+
animate={{ opacity: 1, y: 0 }}
70+
exit={{ opacity: 0, y: -10 }}
71+
transition={{ duration: 0.2 }}
72+
>
73+
<DropdownMenuLabel className="flex items-center space-x-3 p-3">
74+
<div className="border-primary/20 h-12 w-12 overflow-hidden rounded-full border-2">
75+
{user.image ? (
76+
<UserImage image={user.image} />
77+
) : (
78+
<div className="from-primary-400 to-primary-600 flex h-full w-full items-center justify-center bg-gradient-to-br text-white">
79+
<UserRound size={24} />
80+
</div>
81+
)}
82+
</div>
83+
<div className="flex flex-col">
84+
<span className="text-foreground font-semibold">{user.name}</span>
85+
<span className="text-muted-foreground max-w-[150px] truncate text-xs">{user.email}</span>
86+
</div>
87+
</DropdownMenuLabel>
88+
<DropdownMenuSeparator className="bg-primary/10 my-2" />
89+
{dropDownData.map((item, index) => (
90+
<DropdownMenuItem
91+
key={index}
92+
className="focus:bg-secondary/25 hover:bg-secondary/25 flex cursor-pointer items-center space-x-3 rounded-lg p-3 transition-all duration-200 hover:shadow-md"
93+
onClick={() => router.push(item.href)}
94+
>
95+
<span className="text-foreground">{item.icon}</span>
96+
<span className="text-foreground">{item.name}</span>
6697
</DropdownMenuItem>
67-
);
68-
})}
69-
<DropdownMenuSeparator />
70-
{user && (
98+
))}
99+
<DropdownMenuSeparator className="bg-primary/10 my-2" />
71100
<DropdownMenuItem
101+
className="focus:bg-secondary/25 hover:bg-destructive/15 flex cursor-pointer items-center space-x-3 rounded-lg p-3 transition-all duration-200 hover:shadow-md"
72102
onClick={async () => {
73103
await signOut();
74104
router.push("/");
75105
}}
76-
className=" flex gap-2 focus:bg-[#f34e4e]"
77106
>
78-
<LogOut size={15} />
79-
Logout
107+
<LogOut size={15} className="text-destructive" />
108+
<span className="text-destructive">Logout</span>
80109
</DropdownMenuItem>
81-
)}
110+
</motion.div>
82111
</DropdownMenuContent>
83-
</DropdownMenu>
84-
)}
85-
</>
112+
)}
113+
</AnimatePresence>
114+
</DropdownMenu>
86115
);
87116
}

0 commit comments

Comments
 (0)