Skip to content

Commit 2841c5c

Browse files
Added avatar with option to logout/in (#85)
1 parent 74761f7 commit 2841c5c

File tree

4 files changed

+231
-20
lines changed

4 files changed

+231
-20
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
},
1818
"dependencies": {
1919
"@auth/prisma-adapter": "^1.6.0",
20+
"@headlessui/react": "^2.2.0",
2021
"@hookform/resolvers": "^3.3.4",
2122
"@prisma/client": "^5.14.0",
2223
"@radix-ui/react-avatar": "^1.0.4",

pnpm-lock.yaml

+152-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"use client";
2+
3+
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
4+
import { UserRound } from "lucide-react";
5+
import { Button } from "../ui/button";
6+
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
7+
import { Session } from "next-auth";
8+
import { useMemo } from "react";
9+
import { signIn, signOut } from "next-auth/react";
10+
11+
interface DropdownItem {
12+
name: string;
13+
href?: string;
14+
onClick?: () => void;
15+
}
16+
17+
export default function AvatarDropdown({ user }: { user: Session | null }) {
18+
const solutions: DropdownItem[] = useMemo(() => {
19+
if (user === null) {
20+
return [
21+
{
22+
name: "Logg inn",
23+
onClick: () => signIn(),
24+
},
25+
];
26+
}
27+
28+
return [{ name: "Logg ut", onClick: () => signOut() }];
29+
}, [user]);
30+
31+
return (
32+
<Popover className="relative">
33+
<PopoverButton as={Button} size={"icon"} variant={"ghost"}>
34+
<Avatar className="duration-100 hover:brightness-90">
35+
{Boolean(user?.user.image) && (
36+
<AvatarImage src={user!.user.image ?? undefined} alt="@profile" />
37+
)}
38+
<AvatarFallback>
39+
<UserRound className="text-foreground" />
40+
</AvatarFallback>
41+
</Avatar>
42+
</PopoverButton>
43+
44+
<PopoverPanel
45+
transition
46+
className="absolute left-1/2 z-10 mt-5 flex w-fit max-w-40 -translate-x-1/2 px-2 transition data-[closed]:translate-y-1 data-[closed]:opacity-0 data-[enter]:duration-200 data-[leave]:duration-150 data-[enter]:ease-out data-[leave]:ease-in"
47+
>
48+
<div className="w-56 shrink rounded-xl bg-white p-4 text-sm/6 font-semibold text-gray-900 shadow-lg ring-1 ring-gray-900/5">
49+
{solutions.map((item) =>
50+
Boolean(item.href) ? (
51+
<a
52+
key={item.name}
53+
href={item.href}
54+
className="block p-2 hover:text-indigo-600"
55+
>
56+
{item.name}
57+
</a>
58+
) : (
59+
<span
60+
key={item.name}
61+
onClick={item.onClick!}
62+
className="block cursor-pointer p-2 hover:text-indigo-600"
63+
>
64+
{item.name}
65+
</span>
66+
),
67+
)}
68+
</div>
69+
</PopoverPanel>
70+
</Popover>
71+
);
72+
}

src/components/layout/navbar.tsx

+6-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"use server";
2-
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar";
3-
import { Button } from "~/components/ui/button";
2+
43
import { ThemeModeToggler } from "~/components/ui/theme-mode-toggler";
5-
import { UserRound } from "lucide-react";
4+
import { getServerAuthSession } from "../../server/auth";
5+
import AvatarDropdown from "./avatar-dropdown";
66

77
export default async function Navbar() {
8+
const user = await getServerAuthSession();
9+
810
return (
911
<nav className="flex w-full flex-col content-start bg-background">
1012
<div className="flex w-full items-center justify-between gap-3 border-b-[1px] p-3">
@@ -23,14 +25,7 @@ export default async function Navbar() {
2325
</p>
2426
</div>
2527
<div className="flex gap-3">
26-
<Button size={"icon"} variant={"ghost"}>
27-
<Avatar className="duration-100 hover:brightness-90">
28-
<AvatarImage src="https://github.com/shadcn.png" alt="@profile" />
29-
<AvatarFallback>
30-
<UserRound className="text-foreground" />
31-
</AvatarFallback>
32-
</Avatar>
33-
</Button>
28+
<AvatarDropdown user={user} />
3429
<ThemeModeToggler />
3530
</div>
3631
</div>

0 commit comments

Comments
 (0)