Skip to content

Commit 34887c6

Browse files
merge
2 parents 2b8851b + 2bc9441 commit 34887c6

5 files changed

Lines changed: 354 additions & 96 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"dependencies": {
1313
"@radix-ui/react-accordion": "^1.2.4",
1414
"@radix-ui/react-dialog": "^1.1.7",
15+
"@radix-ui/react-dropdown-menu": "^2.1.16",
1516
"@radix-ui/react-icons": "^1.3.2",
1617
"@radix-ui/react-popover": "^1.1.7",
1718
"@radix-ui/react-select": "^2.1.7",

src/components/CatalogueContent.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ import Error from "./Error";
1717
import { Filter } from "lucide-react";
1818
import { Sheet, SheetContent, SheetTrigger } from "./ui/sheet";
1919
import { Pin } from "lucide-react";
20+
21+
import Link from "next/link";
2022
import {
2123
getSecureUrl,
2224
generateFileName,
2325
downloadFile,
2426
} from "@/util/download_paper";
25-
import Link from "next/link";
2627

2728
const CatalogueContent = () => {
2829
const router = useRouter();

src/components/FloatingNavbar.tsx

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,67 @@
11
"use client";
22

3+
import { useState } from "react";
34
import { usePathname } from "next/navigation";
45
import Link from "next/link";
5-
import { ArrowUpRight, Pin, UploadIcon } from "lucide-react";
6+
import { ArrowUpRight, Pin, UploadIcon, ChevronDown } from "lucide-react";
67
import ModeToggle from "./toggle-theme";
7-
import { Button } from "./ui/button";
88

99
interface Props {
1010
onNavigate: () => void;
1111
}
1212

1313
export default function FloatingNavbar({ onNavigate }: Props) {
1414
const pathname = usePathname();
15+
const [isOpen, setIsOpen] = useState(false);
1516

1617
return (
17-
<div className="fixed right-6 top-12 z-50 flex flex-col items-end">
18-
<div className="flex flex-col items-center gap-4 rounded-3xl bg-[#110F18] px-6 py-6 shadow-xl ring-1 ring-white/5">
19-
<Link
20-
href={pathname === "/upload" ? "/" : "/upload"}
21-
onClick={onNavigate}
22-
>
23-
<div className="flex items-center gap-2 rounded-full border border-[#3A3745] px-4 py-2 text-sm font-semibold text-white transition hover:bg-[#1A1823]">
24-
<UploadIcon className="h-4 w-4" />
25-
<span>
26-
{pathname === "/upload" ? "Search Papers" : "Upload Papers"}
27-
</span>
28-
</div>
29-
</Link>
18+
<div className="fixed right-6 top-0 z-50 flex flex-col items-end h-full pointer-events-none">
19+
{}
20+
<button
21+
className="mt-[1.25rem] flex h-10 w-10 items-center justify-center rounded-full bg-[#4B22D1] text-white shadow-lg transition-transform duration-200 hover:scale-105 active:scale-95 pointer-events-auto"
22+
onClick={() => setIsOpen(prev => !prev)}
23+
aria-label={isOpen ? "Close menu" : "Open menu"}
24+
>
25+
<ChevronDown
26+
className={`h-5 w-5 transition-transform duration-200 ${isOpen ? "rotate-180" : ""}`}
27+
/>
28+
</button>
3029

31-
<Link href="/pinned" onClick={onNavigate}>
32-
<div className="flex items-center gap-2 rounded-full border border-[#3A3745] px-4 py-2 text-sm font-semibold text-white transition hover:bg-[#1A1823]">
33-
<Pin className="h-4 w-4" />
34-
<span>Pinned Subjects</span>
35-
</div>
36-
</Link>
37-
<div className="px-4 py-2">
38-
<Link href="/request" onClick={onNavigate}>
30+
{}
31+
{isOpen && (
32+
<div className="mt-2 flex flex-col items-center gap-4 rounded-3xl bg-[#110F18] px-6 py-6 shadow-xl ring-1 ring-white/5 pointer-events-auto">
33+
<Link
34+
href={pathname === "/upload" ? "/" : "/upload"}
35+
onClick={() => {
36+
setIsOpen(false);
37+
onNavigate();
38+
}}
39+
>
40+
<div className="flex items-center gap-2 rounded-full border border-[#3A3745] px-4 py-2 text-sm font-semibold text-white transition hover:bg-[#1A1823]">
41+
<UploadIcon className="h-4 w-4" />
42+
<span>{pathname === "/upload" ? "Search Papers" : "Upload Papers"}</span>
43+
</div>
44+
</Link>
45+
46+
<Link href="/pinned" onClick={() => { setIsOpen(false); onNavigate(); }}>
47+
<div className="flex items-center gap-2 rounded-full border border-[#3A3745] px-4 py-2 text-sm font-semibold text-white transition hover:bg-[#1A1823]">
48+
<Pin className="h-4 w-4" />
49+
<span>Pinned Subjects</span>
50+
</div>
51+
</Link>
52+
53+
<Link href="/request" onClick={() => { setIsOpen(false); onNavigate(); }}>
3954
<div className="flex items-center gap-2 rounded-full border border-[#3A3745] px-4 py-2 text-sm font-semibold text-white transition hover:bg-[#1A1823] w-full justify-center">
4055
<ArrowUpRight className="h-4 w-4" />
41-
Paper Request
56+
<span>Paper Request</span>
4257
</div>
4358
</Link>
59+
60+
<div className="rounded-full border border-[#3A3745] p-1">
61+
<ModeToggle />
62+
</div>
4463
</div>
45-
<div className="rounded-full border border-[#3A3745] p-1">
46-
<ModeToggle />
47-
</div>
48-
</div>
64+
)}
4965
</div>
5066
);
5167
}

src/components/Navbar.tsx

Lines changed: 107 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,78 @@
11
"use client";
22

3-
import { useState, useRef, useEffect } from "react";
4-
import Image from "next/image";
3+
import { useState, useEffect } from "react";
4+
import Image, { StaticImageData } from "next/image";
55
import Link from "next/link";
66
import { usePathname } from "next/navigation";
77
import ccLogo from "../assets/codechef_logo.svg";
88
import ModeToggle from "@/components/toggle-theme";
9-
import { Button } from "@/components/ui/button";
10-
import { ArrowDownLeftIcon, Pin, ArrowUpRight } from "lucide-react";
11-
import NavDropdownButton from "./NavDropdownButton";
9+
import { ArrowDownLeftIcon, Pin, ArrowUpRight, ChevronDown } from "lucide-react";
1210
import FloatingNavbar from "./FloatingNavbar";
1311
import PWAInstallButton from "./ui/PWAInstallButton";
12+
import SearchBarChild from "./Searchbar/searchbar-child";
13+
import type { ICourses } from "@/interface";
14+
import {
15+
DropdownMenu,
16+
DropdownMenuTrigger,
17+
DropdownMenuContent,
18+
DropdownMenuItem,
19+
} from "@/components/ui/dropdown-menu";
1420

1521
function Navbar() {
16-
const pathname = usePathname();
17-
const [open, setOpen] = useState(false);
18-
const dropdownContainerRef = useRef<HTMLDivElement>(null);
22+
const pathname: string = usePathname() ?? "/";
23+
const [subjects, setSubjects] = useState<string[]>([]);
24+
const [dropdownOpen, setDropdownOpen] = useState<boolean>(false);
1925

2026
useEffect(() => {
21-
function handleClickOutside(event: MouseEvent) {
22-
if (
23-
dropdownContainerRef.current &&
24-
!dropdownContainerRef.current.contains(event.target as Node)
25-
) {
26-
setOpen(false);
27-
}
28-
}
27+
if (pathname !== "/catalogue") return;
28+
29+
const getSubjects = async () => {
30+
try {
31+
const res = await fetch("/api/course-list");
32+
if (!res.ok) return;
2933

30-
if (open) {
31-
document.addEventListener("mousedown", handleClickOutside);
32-
}
34+
const json: unknown = await res.json();
3335

34-
return () => {
35-
document.removeEventListener("mousedown", handleClickOutside);
36+
if (Array.isArray(json)) {
37+
const filtered = json
38+
.filter((item): item is ICourses => typeof item === "object" && item !== null && "name" in item)
39+
.map(item => item.name);
40+
setSubjects(filtered);
41+
} else {
42+
console.error("Invalid data returned from API:", json);
43+
}
44+
} catch (err) {
45+
console.error("Failed to fetch courses", err);
46+
}
3647
};
37-
}, [open]);
48+
49+
void getSubjects();
50+
}, [pathname]);
51+
52+
const renderHomePageButtons = () => (
53+
<>
54+
<Link href="/pinned" className="ml-2">
55+
<div className="flex items-center gap-2 rounded-full border bg-[#e8e9ff] dark:bg-black border-[#3A3745] px-4 py-2 text-sm font-semibold dark:text-white transition hover:bg-slate-50 text-gray-700 dark:hover:bg-[#1A1823] h-10">
56+
<Pin className="h-4 w-4" />
57+
Pinned Subjects
58+
</div>
59+
</Link>
60+
<Link href="/request" className="ml-2">
61+
<div className="flex items-center gap-2 rounded-full border bg-[#e8e9ff] dark:bg-black border-[#3A3745] px-4 py-2 text-sm font-semibold dark:text-white transition hover:bg-slate-50 text-gray-700 dark:hover:bg-[#1A1823] h-10">
62+
<ArrowUpRight className="h-4 w-4" />
63+
Paper Request
64+
</div>
65+
</Link>
66+
</>
67+
);
3868

3969
return (
4070
<div className="sticky top-0 z-10 w-full bg-[#B2B8FF] px-4 py-4 dark:bg-[#130E1F] md:px-8 md:py-5">
4171
<div className="flex items-center justify-between">
42-
<div className="flex items-center gap-4">
43-
<Link href="https://www.codechefvit.com/" target="_blank">
44-
<Image
45-
src={ccLogo as HTMLImageElement}
46-
alt="codechef-logo"
47-
height={60}
48-
width={60}
49-
/>
72+
{}
73+
<div className="flex items-center gap-4 relative">
74+
<Link href="https://www.codechefvit.com/" target="_blank">
75+
<Image src={ccLogo as StaticImageData} alt="codechef-logo" height={60} width={60} />
5076
</Link>
5177

5278
<Link
@@ -56,62 +82,76 @@ function Navbar() {
5682
Papers
5783
</Link>
5884

59-
<div className="mt-3 hidden md:flex">
60-
<Link href="/pinned">
61-
<div className="ml-2 flex items-center gap-2 rounded-full border bg-[#e8e9ff] dark:bg-black border-[#3A3745] px-4 py-2 text-sm font-semibold dark:text-white transition hover:bg-slate-50 text-gray-700 dark:hover:bg-[#1A1823]">
62-
<Pin className="h-4 w-4" />
63-
Pinned Subjects
64-
</div>
65-
</Link>
66-
<div className="ml-2 hidden md:flex">
67-
<Link href="/request">
68-
<div className="ml-2 flex items-center gap-2 rounded-full border bg-[#e8e9ff] dark:bg-black border-[#3A3745] px-4 py-2 text-sm font-semibold dark:text-white transition hover:bg-slate-50 text-gray-700 dark:hover:bg-[#1A1823]">
69-
<ArrowUpRight className="h-4 w-4" />
70-
Paper Request
71-
</div>
72-
</Link>
73-
</div>
74-
</div>
85+
{pathname === "/catalogue" ? (
86+
<div className="ml-4 hidden md:block relative">
87+
<DropdownMenu open={dropdownOpen} onOpenChange={setDropdownOpen}>
88+
<DropdownMenuTrigger asChild>
89+
<button
90+
className="flex h-10 w-10 items-center justify-center rounded-full bg-[#4B22D1] text-white shadow-lg transition-transform duration-200 hover:scale-105 active:scale-95"
91+
aria-label="Toggle dropdown"
92+
>
93+
<ChevronDown
94+
className={`h-5 w-5 transition-transform duration-200 ${dropdownOpen ? "rotate-180" : ""}`}
95+
/>
96+
</button>
97+
</DropdownMenuTrigger>
7598

76-
{/* Desktop: Create Paper Request button */}
99+
<DropdownMenuContent
100+
className="w-56 rounded-2xl bg-[#4B22D1] text-white border border-[rgba(255,255,255,0.1)] shadow-2xl backdrop-blur-sm"
101+
align="start"
102+
>
103+
<DropdownMenuItem asChild>
104+
<Link href="/pinned" className="flex items-center gap-3">
105+
<Pin className="h-4 w-4" />
106+
<span className="font-medium">Pinned Subjects</span>
107+
</Link>
108+
</DropdownMenuItem>
109+
<DropdownMenuItem asChild>
110+
<Link href="/request" className="flex items-center gap-3">
111+
<ArrowUpRight className="h-4 w-4" />
112+
<span className="font-medium">Paper Request</span>
113+
</Link>
114+
</DropdownMenuItem>
115+
</DropdownMenuContent>
116+
</DropdownMenu>
117+
</div>
118+
) : (
119+
<div className="hidden md:flex items-center h-10">{renderHomePageButtons()}</div>
120+
)}
77121
</div>
78122

123+
{}
124+
{pathname === "/catalogue" && (
125+
<div className="hidden md:flex flex-1 justify-center mx-4">
126+
<div className="w-full max-w-[700px]">
127+
<SearchBarChild initialSubjects={subjects} />
128+
</div>
129+
</div>
130+
)}
131+
132+
{}
79133
<div className="hidden items-center gap-4 md:flex">
80134
<div className="rounded-full border border-[#3A3745] p-1">
81135
<ModeToggle />
82136
</div>
83-
84137
<div className="hidden max-w-[200px] md:block">
85138
<PWAInstallButton />
86139
</div>
87-
88140
<Link href={pathname === "/upload" ? "/" : "/upload"}>
89-
<div className="flex items-center gap-2 rounded-full border bg-[#e8e9ff] dark:bg-black border-[#3A3745] px-4 py-2 text-sm font-semibold dark:text-white transition hover:bg-slate-50 text-gray-700 dark:hover:bg-[#1A1823]">
141+
<div className="flex items-center gap-2 rounded-full border bg-[#e8e9ff] dark:bg-black border-[#3A3745] px-4 py-2 text-sm font-semibold dark:text-white transition hover:bg-slate-50 text-gray-700 dark:hover:bg-[#1A1823] h-10">
90142
<ArrowDownLeftIcon className="h-4 w-4 rotate-90" />
91-
<span>
92-
{pathname === "/upload" ? "Search Papers" : "Upload Papers"}
93-
</span>
143+
<span>{pathname === "/upload" ? "Search Papers" : "Upload Papers"}</span>
94144
</div>
95145
</Link>
96146
</div>
97147

98-
{/* Mobile: Create Paper Request button inside dropdown */}
99-
<div className="md:hidden" ref={dropdownContainerRef}>
100-
<NavDropdownButton
101-
isOpen={open}
102-
onClick={() => setOpen((prev) => !prev)}
103-
/>
104-
<div
105-
className={`transition-all duration-300 ease-in-out ${
106-
open ? "block" : "hidden"
107-
}`}
108-
>
109-
<FloatingNavbar onNavigate={() => setOpen(false)} />
110-
</div>
148+
{}
149+
<div className="md:hidden">
150+
<FloatingNavbar onNavigate={() => void 0} />
111151
</div>
112152
</div>
113153
</div>
114154
);
115155
}
116156

117-
export default Navbar;
157+
export default Navbar;

0 commit comments

Comments
 (0)