|
1 | 1 | 'use client'; |
2 | 2 |
|
3 | | -import React from 'react'; |
| 3 | +import React, { useState } from 'react'; |
4 | 4 | import { usePathname } from 'next/navigation'; |
5 | 5 | import { signOut } from 'next-auth/react'; |
6 | 6 | import Link from 'next/link'; |
| 7 | +import { Menu as MenuIcon, X } from 'lucide-react'; |
7 | 8 | import Header from './Header'; |
8 | 9 |
|
9 | 10 | export default function Menu({ session }) { |
10 | 11 | const pathname = usePathname(); |
11 | 12 | const username = session?.username; |
| 13 | + const [isOpen, setIsOpen] = useState(false); |
12 | 14 |
|
13 | 15 | const isActive = (path) => pathname === path; |
14 | 16 | const isProfileActive = pathname.startsWith(`/${username}`); |
15 | 17 |
|
| 18 | + const toggleMenu = () => { |
| 19 | + setIsOpen(!isOpen); |
| 20 | + }; |
| 21 | + |
| 22 | + const menuItems = [ |
| 23 | + { href: '/explore', label: 'Explore' }, |
| 24 | + { href: '/jobs', label: 'Jobs' }, |
| 25 | + { href: '/job-similarity', label: 'Similarity' }, |
| 26 | + { |
| 27 | + href: 'https://github.com/jsonresume/jsonresume.org', |
| 28 | + label: 'Github', |
| 29 | + external: true, |
| 30 | + }, |
| 31 | + { href: 'https://discord.gg/GTZtn8pTXC', label: 'Discord', external: true }, |
| 32 | + ]; |
| 33 | + |
| 34 | + const authItems = [ |
| 35 | + ...(username |
| 36 | + ? [ |
| 37 | + { href: `/${username}/dashboard`, label: 'Profile' }, |
| 38 | + { href: '/editor', label: 'Editor' }, |
| 39 | + ] |
| 40 | + : []), |
| 41 | + session |
| 42 | + ? { onClick: signOut, label: 'Logout' } |
| 43 | + : { href: '/', label: 'Sign in' }, |
| 44 | + ]; |
| 45 | + |
16 | 46 | return ( |
17 | 47 | <div className="bg-accent-200 shadow-md"> |
18 | 48 | <Header |
19 | 49 | left={ |
20 | | - <div className="flex gap-8 items-center h-full p-5"> |
| 50 | + <div className="flex items-center justify-between w-full lg:w-auto p-4 lg:p-5"> |
21 | 51 | <Link |
22 | 52 | href="/" |
23 | 53 | className="text-2xl font-bold text-black hover:text-secondary-900 transition-colors duration-200" |
24 | 54 | > |
25 | 55 | JSON Resume Registry |
26 | 56 | </Link> |
27 | | - <Link |
28 | | - href="/explore" |
29 | | - className={`text-xl font-bold ${ |
30 | | - isActive('/explore') |
31 | | - ? 'text-secondary-900 underline' |
32 | | - : 'text-black' |
33 | | - } hover:text-secondary-900 transition-colors duration-200`} |
34 | | - > |
35 | | - Explore |
36 | | - </Link> |
37 | | - <Link |
38 | | - href="/jobs" |
39 | | - className={`text-xl font-bold ${ |
40 | | - isActive('/jobs') || pathname.startsWith('/jobs/') |
41 | | - ? 'text-secondary-900 underline' |
42 | | - : 'text-black' |
43 | | - } hover:text-secondary-900 transition-colors duration-200`} |
44 | | - > |
45 | | - Jobs |
46 | | - </Link> |
47 | | - <Link |
48 | | - href="/job-similarity" |
49 | | - className={`text-xl font-bold ${ |
50 | | - isActive('/job-similarity') |
51 | | - ? 'text-secondary-900 underline' |
52 | | - : 'text-black' |
53 | | - } hover:text-secondary-900 transition-colors duration-200`} |
54 | | - > |
55 | | - Similarity |
56 | | - </Link> |
57 | | - <a |
58 | | - href="https://github.com/jsonresume/jsonresume.org" |
59 | | - className="text-xl font-bold text-black hover:text-secondary-900 transition-colors duration-200" |
60 | | - > |
61 | | - Github |
62 | | - </a> |
63 | | - <a |
64 | | - href="https://discord.gg/GTZtn8pTXC" |
65 | | - className="text-xl font-bold text-black hover:text-secondary-900 transition-colors duration-200" |
| 57 | + <button |
| 58 | + onClick={toggleMenu} |
| 59 | + className="lg:hidden p-2 text-black hover:text-secondary-900" |
| 60 | + aria-label="Toggle menu" |
66 | 61 | > |
67 | | - Discord |
68 | | - </a> |
| 62 | + {isOpen ? <X size={24} /> : <MenuIcon size={24} />} |
| 63 | + </button> |
69 | 64 | </div> |
70 | 65 | } |
71 | 66 | right={ |
72 | | - <div className="flex gap-6 items-center h-full p-5"> |
73 | | - {username && ( |
74 | | - <Link |
75 | | - href={`/${username}/dashboard`} |
76 | | - className={`text-xl font-bold hover:text-secondary-900 transition-colors duration-200 ${ |
77 | | - isProfileActive |
78 | | - ? 'text-secondary-900 underline' |
79 | | - : 'text-black' |
80 | | - }`} |
81 | | - > |
82 | | - Profile |
83 | | - </Link> |
84 | | - )} |
85 | | - {session && username && ( |
86 | | - <Link |
87 | | - href="/editor" |
88 | | - className={`text-xl font-bold hover:text-secondary-900 transition-colors duration-200 ${ |
89 | | - isActive('/editor') |
90 | | - ? 'text-secondary-900 underline' |
91 | | - : 'text-black' |
92 | | - }`} |
93 | | - > |
94 | | - Editor |
95 | | - </Link> |
96 | | - )} |
97 | | - {session && ( |
98 | | - <button |
99 | | - onClick={signOut} |
100 | | - className="text-xl font-bold text-black hover:text-secondary-900 transition-colors duration-200" |
101 | | - > |
102 | | - Logout |
103 | | - </button> |
104 | | - )} |
105 | | - {!session && ( |
106 | | - <Link |
107 | | - href="/" |
108 | | - className={`text-xl font-bold hover:text-secondary-900 transition-colors duration-200 ${ |
109 | | - isActive('/') ? 'text-secondary-900 underline' : 'text-black' |
110 | | - }`} |
111 | | - > |
112 | | - Sign in |
113 | | - </Link> |
114 | | - )} |
| 67 | + <div |
| 68 | + className={`${ |
| 69 | + isOpen ? 'block' : 'hidden' |
| 70 | + } lg:flex lg:items-center lg:flex-1`} |
| 71 | + > |
| 72 | + <nav className="flex flex-col lg:flex-row lg:items-center lg:justify-end gap-4 p-4 lg:p-5"> |
| 73 | + {menuItems.map((item) => |
| 74 | + item.external ? ( |
| 75 | + <a |
| 76 | + key={item.href} |
| 77 | + href={item.href} |
| 78 | + className="text-lg lg:text-xl font-bold text-black hover:text-secondary-900 transition-colors duration-200 py-2 lg:py-0" |
| 79 | + > |
| 80 | + {item.label} |
| 81 | + </a> |
| 82 | + ) : ( |
| 83 | + <Link |
| 84 | + key={item.href} |
| 85 | + href={item.href} |
| 86 | + className={`text-lg lg:text-xl font-bold ${ |
| 87 | + isActive(item.href) || |
| 88 | + (item.href === '/jobs' && pathname.startsWith('/jobs/')) |
| 89 | + ? 'text-secondary-900 underline' |
| 90 | + : 'text-black' |
| 91 | + } hover:text-secondary-900 transition-colors duration-200 py-2 lg:py-0`} |
| 92 | + > |
| 93 | + {item.label} |
| 94 | + </Link> |
| 95 | + ) |
| 96 | + )} |
| 97 | + {authItems.map((item) => |
| 98 | + item.onClick ? ( |
| 99 | + <button |
| 100 | + key={item.label} |
| 101 | + onClick={item.onClick} |
| 102 | + className="text-lg lg:text-xl font-bold text-black hover:text-secondary-900 transition-colors duration-200 py-2 lg:py-0 text-left" |
| 103 | + > |
| 104 | + {item.label} |
| 105 | + </button> |
| 106 | + ) : ( |
| 107 | + <Link |
| 108 | + key={item.href} |
| 109 | + href={item.href} |
| 110 | + className={`text-lg lg:text-xl font-bold hover:text-secondary-900 transition-colors duration-200 py-2 lg:py-0 ${ |
| 111 | + (item.href === `/${username}/dashboard` && |
| 112 | + isProfileActive) || |
| 113 | + isActive(item.href) |
| 114 | + ? 'text-secondary-900 underline' |
| 115 | + : 'text-black' |
| 116 | + }`} |
| 117 | + > |
| 118 | + {item.label} |
| 119 | + </Link> |
| 120 | + ) |
| 121 | + )} |
| 122 | + </nav> |
115 | 123 | </div> |
116 | 124 | } |
117 | 125 | /> |
|
0 commit comments