Skip to content

Commit

Permalink
feat: Navbar
Browse files Browse the repository at this point in the history
  • Loading branch information
Lee-Dongwook committed Oct 21, 2024
1 parent 4820206 commit 2b06fa7
Show file tree
Hide file tree
Showing 13 changed files with 224 additions and 1 deletion.
7 changes: 7 additions & 0 deletions client/src/app/chat/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from "react";

const page = () => {
return <div>page</div>;
};

export default page;
2 changes: 2 additions & 0 deletions client/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import localFont from "next/font/local";

import AuthProvider from "@/providers/auth-provider";
import ThemeProvider from "@/providers/theme-provider";
import Navbar from "@/components/NavLink";
import { Toaster } from "@/components/ui/toaster";

const geistSans = localFont({
Expand Down Expand Up @@ -39,6 +40,7 @@ export default function RootLayout({
enableSystem
disableTransitionOnChange
>
<Navbar />
<main className="flex flex-col justify-center items-center min-h-screen">
{children}
</main>
Expand Down
7 changes: 7 additions & 0 deletions client/src/app/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from "react";

const page = () => {
return <div>page</div>;
};

export default page;
7 changes: 7 additions & 0 deletions client/src/app/setting/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from "react";

const page = () => {
return <div>page</div>;
};

export default page;
19 changes: 19 additions & 0 deletions client/src/components/Button/signout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";

import { signOut } from "next-auth/react";
import { Button } from "@/components/ui/button";

export default function SignOutButton() {
const signout = () => {
signOut({
redirect: true,
callbackUrl: `${window.location.origin}/signin`,
});
};

return (
<Button onClick={signout} variant="destructive">
Sign Out
</Button>
);
}
26 changes: 26 additions & 0 deletions client/src/components/ModeToggle/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"use client";

import { useTheme } from "next-themes";

import { Button } from "@/components/ui/button";
import { Moon, Sun } from "lucide-react";

export default function ModeToggle() {
const { theme, setTheme } = useTheme();

const toggleTheme = () => {
if (theme === "dark") {
setTheme("light");
} else {
setTheme("dark");
}
};

return (
<Button variant="outline" size="icon" onClick={toggleTheme}>
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
);
}
22 changes: 22 additions & 0 deletions client/src/components/NavLink/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Link from "next/link";
import MainNav from "@/components/NavLink/main-nav";
import UserNav from "@/components/NavLink/user-nav";
import ModeToggle from "@/components/ModeToggle";
import { Code } from "lucide-react";

export default function Navbar() {
return (
<header className="w-full fixed z-10 top-0 bg-gray-100 dark:bg-gray-900 border-b border-gray-200">
<nav className="h-16 px-4 flex items-center">
<Link href="/">
<Code />
</Link>
<MainNav />
<div className="ml-auto flex items-center space-x-4">
<ModeToggle />
<UserNav />
</div>
</nav>
</header>
);
}
44 changes: 44 additions & 0 deletions client/src/components/NavLink/main-nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client";

import { useState } from "react";
import { usePathname } from "next/navigation";
import Link from "next/link";
import { Menu } from "lucide-react";
import { mainNavLinks } from "@/constants";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

export default function MainNav() {
const [menuOpen, setMenuOpen] = useState<boolean>(false);
const pathName = usePathname();

return (
<div className="flex items-center lg:space-x-6 mx-4">
<Button className="lg:hidden" onClick={() => setMenuOpen(!menuOpen)}>
<Menu />
</Button>
<div
className={cn(
"absolute top-full left-0 w-full border bg-gray-100 dark:bg-gray-800",
"lg:border-none lg:static lg:flex lg:space-x-6",
menuOpen ? "block" : "hidden"
)}
>
{mainNavLinks.map((link) => (
<Link
className={cn(
"block py-2 px-4 text-sm transition-colors",
pathName === link.url
? "text-black dark:text-white"
: "text-muted-foreground"
)}
key={link.title}
href={link.url}
>
{link.title}
</Link>
))}
</div>
</div>
);
}
27 changes: 27 additions & 0 deletions client/src/components/NavLink/user-avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";

import { useSession } from "next-auth/react";
import { UserCircle2 } from "lucide-react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";

export default function UserAvatar() {
const { data: session } = useSession();

return (
<div>
{session?.user?.image ? (
<Avatar className="mx-auto w-8 h-8">
<AvatarImage
className="object-cover w-full h-full rounded-full"
src={session?.user?.image}
alt="user avatar"
/>
<AvatarFallback>CN</AvatarFallback>
</Avatar>
) : (
<UserCircle2 className="mx-auto w-8 h-8" />
)}
<p className="w-full text-center text-xs">{session?.user?.name}</p>
</div>
);
}
44 changes: 44 additions & 0 deletions client/src/components/NavLink/user-nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Link from "next/link";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { buttonVariants } from "@/components/ui/button";
import SignOutButton from "@/components/Button/signout";
import UserAvatar from "@/components/NavLink/user-avatar";
import { getUserSession } from "@/lib/authAction";

export default async function UserNav() {
const { session } = await getUserSession();

return (
<div>
{session ? (
<DropdownMenu>
<DropdownMenuTrigger>
<UserAvatar />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>
<Link href="/profile">Profile</Link>
</DropdownMenuItem>
<DropdownMenuItem>
<SignOutButton />
</DropdownMenuItem>
</DropdownMenuLabel>
</DropdownMenuContent>
</DropdownMenu>
) : (
<Link className={buttonVariants()} href="/signin">
Sign In
</Link>
)}
</div>
);
}
9 changes: 9 additions & 0 deletions client/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const mainNavLinks = [
{ title: "Home", url: "/" },
{ title: "My Documents", url: "/document" },
{ title: "Create Document", url: "/document/new" },
{ title: "Real-time Collaboration", url: "/document/realtime" },
{ title: "Profile", url: "/profile" },
{ title: "settings", url: "/setting" },
{ title: "Chat", url: "/chat" },
];
7 changes: 7 additions & 0 deletions client/src/lib/authAction.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use server";

import { getServerSession } from "next-auth";
import { redirect } from "next/navigation";
import bcrypt from "bcryptjs";
import connectDB from "@/lib/mongoDBConnect";
import { nextAuthOptions } from "@/lib/nextAuthOptions";
import User from "@/models/user.model";

interface SignUpWithCredentialsParams {
Expand All @@ -19,6 +21,11 @@ interface GetUserByEmailParams {
email: string;
}

export async function getUserSession() {
const session = await getServerSession(nextAuthOptions);
return { session };
}

export async function signUpWithCredentials({
name,
email,
Expand Down
4 changes: 3 additions & 1 deletion client/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ export default withAuth(
}
);

export const config = { matcher: ["/document/:path*"] };
export const config = {
matcher: ["/document/:path*", "/profile", "/setting", "/chat"],
};

0 comments on commit 2b06fa7

Please sign in to comment.