-
-
Notifications
You must be signed in to change notification settings - Fork 169
Expand file tree
/
Copy pathNavDrawer.tsx
More file actions
173 lines (159 loc) · 5.15 KB
/
Copy pathNavDrawer.tsx
File metadata and controls
173 lines (159 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
"use client";
import { useEffect } from "react";
import Link from "next/link";
import Image from "next/image";
import { usePathname } from "next/navigation";
import { signIn } from "next-auth/react";
import { type Session } from "next-auth";
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
const FOOTER = [
{ name: "Privacy", href: "/privacy" },
{ name: "Code of conduct", href: "/code-of-conduct" },
{ name: "Advertise", href: "/advertise" },
{ name: "About", href: "/about" },
];
interface NavDrawerProps {
open: boolean;
onClose: () => void;
session: Session | null;
username: string | null;
}
/**
* Slide-out left drawer that replaces the left rail on ≤720px (opened by the
* top-bar hamburger). Mirrors LeftRail's nav + info-page footer, and closes on
* backdrop click, Esc, or any nav action. ("Your topics" lives in Settings on
* mobile.)
*/
export function NavDrawer({
open,
onClose,
session,
username,
}: NavDrawerProps) {
const pathname = usePathname();
useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [open, onClose]);
if (!open) return null;
// Jobs is flag-gated until launch (auto-on in dev).
const jobsEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
const nav = [
{ name: "Home", href: "/" },
{ name: "Discussions", href: "/discussions" },
...(jobsEnabled ? [{ name: "Jobs", href: "/jobs" }] : []),
...(session
? [
{ name: "Notifications", href: "/notifications" },
{ name: "Saved", href: "/saved" },
{ name: "Profile", href: `/${username || "settings"}` },
{ name: "My posts", href: "/my-posts" },
]
: []),
];
const isActive = (href: string) =>
href === "/" ? pathname === "/" : pathname?.startsWith(href);
return (
<div className="fixed inset-0 z-[60]">
<button
type="button"
aria-label="Close navigation"
onClick={onClose}
className="absolute inset-0 cursor-default"
style={{ background: "rgba(4,5,7,0.6)" }}
/>
<aside
role="dialog"
aria-modal="true"
aria-label="Navigation"
className="absolute bottom-0 left-0 top-0 flex w-[min(286px,84vw)] flex-col overflow-y-auto border-r border-strong bg-elevated px-3 pb-5 pt-4 shadow-lg"
style={{
transform: "translateX(0)",
transition: "transform 320ms ease-out",
}}
>
<div className="flex items-center justify-between px-2.5 pb-4">
<Link href="/" aria-label="Codú — home" onClick={onClose}>
<Image
src="/images/codu.png"
alt="Codú"
height={16}
width={64}
className="dark:invert-0"
/>
</Link>
<button
type="button"
onClick={onClose}
aria-label="Close navigation"
className="font-mono text-base leading-none text-faint hover:text-muted"
>
✕
</button>
</div>
{/* Logged-out auth CTAs live here on mobile — the top bar drops them to
make room for the search icon. */}
{!session && (
<div className="mb-3 flex flex-col gap-2 px-1">
<button
type="button"
onClick={() => {
onClose();
signIn();
}}
className="primary-button w-full justify-center"
>
Join free
</button>
<button
type="button"
onClick={() => {
onClose();
signIn();
}}
className="w-full rounded-md border border-strong px-3 py-2 text-center text-sm font-semibold text-fg transition-colors hover:bg-surface"
>
Log in
</button>
</div>
)}
<nav className="flex flex-col gap-0.5">
{nav.map((item) => {
const active = isActive(item.href);
return (
<Link
key={item.name}
href={item.href}
onClick={onClose}
aria-current={active ? "page" : undefined}
className={`block rounded-md px-3 py-2 text-sm transition-colors duration-base ease-out ${
active
? "bg-surface font-semibold text-fg"
: "font-medium text-muted hover:bg-elevated hover:text-fg"
}`}
>
{item.name}
</Link>
);
})}
</nav>
<div className="mt-auto flex flex-col items-start gap-1.5 px-3 pt-6">
{FOOTER.map((item) => (
<Link
key={item.name}
href={item.href}
onClick={onClose}
className="font-mono text-[11px] leading-normal text-faint transition-colors hover:text-muted"
>
{item.name}
</Link>
))}
</div>
</aside>
</div>
);
}