gaurv007 commited on
Commit
3c2e372
·
verified ·
1 Parent(s): 394fab8

v4.1: Nav — add Dashboard link, admin always visible, improved mobile menu

Browse files
Files changed (1) hide show
  1. web/components/nav.tsx +90 -34
web/components/nav.tsx CHANGED
@@ -2,23 +2,20 @@
2
 
3
  import Link from "next/link";
4
  import { usePathname } from "next/navigation";
5
- import { ShieldCheck, Menu, X, Crown, GitCompare, MessageSquare } from "lucide-react";
 
 
 
6
  import { useState, useEffect } from "react";
7
  import { createClient } from "@/lib/supabase/client";
8
 
9
- const links = [
10
- { href: "/#features", label: "Features" },
11
- { href: "/#pricing", label: "Pricing" },
12
- { href: "/dashboard-pages/analyze", label: "Scanner" },
13
- { href: "/dashboard-pages/compare", label: "Compare", icon: GitCompare },
14
- ];
15
-
16
  export function Nav() {
17
  const [open, setOpen] = useState(false);
18
  const [userEmail, setUserEmail] = useState<string | null>(null);
19
  const [userRole, setUserRole] = useState<string | null>(null);
 
20
  const pathname = usePathname();
21
- const isDashboard = pathname?.startsWith("/dashboard");
22
  const isAdmin = userRole === "admin";
23
 
24
  useEffect(() => {
@@ -34,69 +31,128 @@ export function Nav() {
34
  .single();
35
  setUserRole(profile?.role || "user");
36
  }
 
37
  });
38
  }, []);
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  return (
41
  <nav className="sticky top-0 z-50 bg-white/80 backdrop-blur-md border-b border-zinc-100">
42
  <div className="max-w-6xl mx-auto px-4 sm:px-5 h-14 flex items-center justify-between">
 
43
  <Link href="/" className="flex items-center gap-2">
44
  <ShieldCheck className="w-5 h-5 text-zinc-900" strokeWidth={2.2} />
45
  <span className="font-semibold text-[15px] tracking-tight text-zinc-900">ClauseGuard</span>
46
  <span className="hidden sm:inline text-[10px] font-medium text-zinc-400 ml-1 border border-zinc-200 px-1.5 py-0.5 rounded">v4.0</span>
47
  </Link>
48
 
 
49
  <div className="hidden md:flex items-center gap-1">
50
- {links.map((l) => (
51
- <a key={l.href} href={l.href}
52
- className="px-3 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50 transition-colors">
53
- {l.label}
54
- </a>
55
- ))}
 
 
 
 
 
 
 
56
 
 
57
  {isAdmin && (
58
  <Link href="/admin"
59
- className="px-3 py-1.5 text-[13px] text-amber-600 hover:text-amber-700 rounded-md hover:bg-amber-50 transition-colors flex items-center gap-1">
 
 
 
 
60
  <Crown className="w-3.5 h-3.5" /> Admin
61
  </Link>
62
  )}
63
 
64
  <div className="w-px h-4 bg-zinc-200 mx-2" />
65
 
66
- {isDashboard || userEmail ? (
67
- <Link href="/dashboard-pages/settings"
68
- className="px-3 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50">
69
- Settings
70
- </Link>
 
 
 
 
 
 
 
 
71
  ) : (
72
- <Link href="/auth/login"
73
- className="px-3 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50">
74
- Log in
75
- </Link>
 
 
 
 
 
 
 
 
76
  )}
77
- <Link href={isDashboard || userEmail ? "/dashboard-pages/analyze" : "/auth/signup"}
78
- className="ml-1 px-3.5 py-1.5 text-[13px] font-medium text-white bg-zinc-900 rounded-md hover:bg-zinc-800 transition-colors">
79
- {isDashboard || userEmail ? "New scan" : "Get started"}
80
- </Link>
81
  </div>
82
 
 
83
  <button className="md:hidden p-1.5 rounded-md hover:bg-zinc-100" onClick={() => setOpen(!open)}>
84
  {open ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
85
  </button>
86
  </div>
87
 
 
88
  {open && (
89
  <div className="md:hidden border-t border-zinc-100 bg-white px-5 py-3 space-y-1">
90
  {links.map((l) => (
91
- <a key={l.href} href={l.href} onClick={() => setOpen(false)}
92
- className="block px-3 py-2 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">{l.label}</a>
93
  ))}
94
  {isAdmin && (
95
  <Link href="/admin" onClick={() => setOpen(false)}
96
- className="block px-3 py-2 text-sm text-amber-600 rounded-md hover:bg-amber-50">Admin</Link>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  )}
98
- <Link href="/auth/login" onClick={() => setOpen(false)}
99
- className="block px-3 py-2 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">Log in</Link>
100
  </div>
101
  )}
102
  </nav>
 
2
 
3
  import Link from "next/link";
4
  import { usePathname } from "next/navigation";
5
+ import {
6
+ ShieldCheck, Menu, X, Crown, GitCompare, LayoutDashboard,
7
+ ScanText, Settings, LogIn, Zap
8
+ } from "lucide-react";
9
  import { useState, useEffect } from "react";
10
  import { createClient } from "@/lib/supabase/client";
11
 
 
 
 
 
 
 
 
12
  export function Nav() {
13
  const [open, setOpen] = useState(false);
14
  const [userEmail, setUserEmail] = useState<string | null>(null);
15
  const [userRole, setUserRole] = useState<string | null>(null);
16
+ const [loaded, setLoaded] = useState(false);
17
  const pathname = usePathname();
18
+ const isLoggedIn = !!userEmail;
19
  const isAdmin = userRole === "admin";
20
 
21
  useEffect(() => {
 
31
  .single();
32
  setUserRole(profile?.role || "user");
33
  }
34
+ setLoaded(true);
35
  });
36
  }, []);
37
 
38
+ // Build links dynamically based on auth state
39
+ const publicLinks = [
40
+ { href: "/#features", label: "Features" },
41
+ { href: "/#pricing", label: "Pricing" },
42
+ ];
43
+
44
+ const appLinks = [
45
+ { href: "/dashboard-pages/dashboard", label: "Dashboard", icon: LayoutDashboard },
46
+ { href: "/dashboard-pages/analyze", label: "Scanner", icon: ScanText },
47
+ { href: "/dashboard-pages/compare", label: "Compare", icon: GitCompare },
48
+ ];
49
+
50
+ const links = isLoggedIn ? appLinks : publicLinks;
51
+
52
  return (
53
  <nav className="sticky top-0 z-50 bg-white/80 backdrop-blur-md border-b border-zinc-100">
54
  <div className="max-w-6xl mx-auto px-4 sm:px-5 h-14 flex items-center justify-between">
55
+ {/* Logo */}
56
  <Link href="/" className="flex items-center gap-2">
57
  <ShieldCheck className="w-5 h-5 text-zinc-900" strokeWidth={2.2} />
58
  <span className="font-semibold text-[15px] tracking-tight text-zinc-900">ClauseGuard</span>
59
  <span className="hidden sm:inline text-[10px] font-medium text-zinc-400 ml-1 border border-zinc-200 px-1.5 py-0.5 rounded">v4.0</span>
60
  </Link>
61
 
62
+ {/* Desktop Nav */}
63
  <div className="hidden md:flex items-center gap-1">
64
+ {links.map((l) => {
65
+ const Icon = "icon" in l ? l.icon : null;
66
+ const isActive = pathname === l.href;
67
+ return (
68
+ <Link key={l.href} href={l.href}
69
+ className={`flex items-center gap-1.5 px-3 py-1.5 text-[13px] rounded-md transition-colors ${
70
+ isActive ? "text-zinc-900 bg-zinc-100 font-medium" : "text-zinc-500 hover:text-zinc-900 hover:bg-zinc-50"
71
+ }`}>
72
+ {Icon && <Icon className="w-3.5 h-3.5" />}
73
+ {l.label}
74
+ </Link>
75
+ );
76
+ })}
77
 
78
+ {/* Admin link — always visible for admins */}
79
  {isAdmin && (
80
  <Link href="/admin"
81
+ className={`flex items-center gap-1.5 px-3 py-1.5 text-[13px] rounded-md transition-colors ${
82
+ pathname === "/admin"
83
+ ? "text-amber-700 bg-amber-50 font-medium"
84
+ : "text-amber-600 hover:text-amber-700 hover:bg-amber-50"
85
+ }`}>
86
  <Crown className="w-3.5 h-3.5" /> Admin
87
  </Link>
88
  )}
89
 
90
  <div className="w-px h-4 bg-zinc-200 mx-2" />
91
 
92
+ {isLoggedIn ? (
93
+ <>
94
+ <Link href="/dashboard-pages/settings"
95
+ className={`flex items-center gap-1.5 px-3 py-1.5 text-[13px] rounded-md transition-colors ${
96
+ pathname?.includes("settings") ? "text-zinc-900 bg-zinc-100" : "text-zinc-500 hover:text-zinc-900 hover:bg-zinc-50"
97
+ }`}>
98
+ <Settings className="w-3.5 h-3.5" /> Settings
99
+ </Link>
100
+ <Link href="/dashboard-pages/analyze"
101
+ className="ml-1 px-3.5 py-1.5 text-[13px] font-medium text-white bg-zinc-900 rounded-md hover:bg-zinc-800 transition-colors flex items-center gap-1.5">
102
+ <Zap className="w-3.5 h-3.5" /> New scan
103
+ </Link>
104
+ </>
105
  ) : (
106
+ <>
107
+ {!isLoggedIn && loaded && (
108
+ <Link href="/auth/login"
109
+ className="flex items-center gap-1.5 px-3 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50 transition-colors">
110
+ <LogIn className="w-3.5 h-3.5" /> Log in
111
+ </Link>
112
+ )}
113
+ <Link href="/auth/signup"
114
+ className="ml-1 px-3.5 py-1.5 text-[13px] font-medium text-white bg-zinc-900 rounded-md hover:bg-zinc-800 transition-colors">
115
+ Get started
116
+ </Link>
117
+ </>
118
  )}
 
 
 
 
119
  </div>
120
 
121
+ {/* Mobile hamburger */}
122
  <button className="md:hidden p-1.5 rounded-md hover:bg-zinc-100" onClick={() => setOpen(!open)}>
123
  {open ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
124
  </button>
125
  </div>
126
 
127
+ {/* Mobile Menu */}
128
  {open && (
129
  <div className="md:hidden border-t border-zinc-100 bg-white px-5 py-3 space-y-1">
130
  {links.map((l) => (
131
+ <Link key={l.href} href={l.href} onClick={() => setOpen(false)}
132
+ className="block px-3 py-2.5 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">{l.label}</Link>
133
  ))}
134
  {isAdmin && (
135
  <Link href="/admin" onClick={() => setOpen(false)}
136
+ className="block px-3 py-2.5 text-sm text-amber-600 rounded-md hover:bg-amber-50 flex items-center gap-2">
137
+ <Crown className="w-4 h-4" /> Admin Panel
138
+ </Link>
139
+ )}
140
+ <div className="h-px bg-zinc-100 my-2" />
141
+ {isLoggedIn ? (
142
+ <>
143
+ <Link href="/dashboard-pages/settings" onClick={() => setOpen(false)}
144
+ className="block px-3 py-2.5 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">Settings</Link>
145
+ <Link href="/dashboard-pages/analyze" onClick={() => setOpen(false)}
146
+ className="block px-3 py-2.5 text-sm font-medium text-white bg-zinc-900 rounded-lg text-center hover:bg-zinc-800">New Scan</Link>
147
+ </>
148
+ ) : (
149
+ <>
150
+ <Link href="/auth/login" onClick={() => setOpen(false)}
151
+ className="block px-3 py-2.5 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">Log in</Link>
152
+ <Link href="/auth/signup" onClick={() => setOpen(false)}
153
+ className="block px-3 py-2.5 text-sm font-medium text-white bg-zinc-900 rounded-lg text-center hover:bg-zinc-800">Get started</Link>
154
+ </>
155
  )}
 
 
156
  </div>
157
  )}
158
  </nav>