Skip to content

Commit ec8f4d6

Browse files
style: stylized navbar
1 parent b8de59f commit ec8f4d6

File tree

2 files changed

+215
-15
lines changed

2 files changed

+215
-15
lines changed

app/[locale]/header.tsx

Lines changed: 119 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ import { Button, HamburgerButton } from '~/components/buttons';
1010
import { CtrlLink } from '~/components/link';
1111
import LocaleSwitcher from '~/components/locale-switcher';
1212
import MaybeLink from '~/components/maybe-link';
13+
import {
14+
NavigationMenu,
15+
NavigationMenuCustomListItem,
16+
NavigationMenuItem,
17+
NavigationMenuLink,
18+
NavigationMenuList,
19+
navigationMenuTriggerStyle,
20+
} from '~/components/ui';
1321
import { getTranslations } from '~/i18n/translations';
1422
import { cn } from '~/lib/utils';
1523
import { getServerAuthSession } from '~/server/auth';
@@ -22,11 +30,84 @@ export default async function Header({ locale }: { locale: string }) {
2230
const isMacOS = agent.os.name === 'Mac OS';
2331

2432
const items = [
25-
{ label: text.institute, href: 'institute' },
26-
{ label: text.academics, href: 'academics' },
33+
{
34+
label: text.institute,
35+
href: 'institute',
36+
listItems: [
37+
{
38+
title: 'Institute Profile',
39+
href: '/institute/profile',
40+
description:
41+
'Get to know our institute’s vision, mission, and values.',
42+
},
43+
{
44+
title: 'Administration',
45+
href: '/institute/administration',
46+
description: 'Meet the leadership team guiding our institution.',
47+
},
48+
{
49+
title: 'Sections',
50+
href: '/institute/sections',
51+
description:
52+
'Explore the various sections that support campus life and academics.',
53+
},
54+
{
55+
title: 'Campus Infrastructure',
56+
href: '/institute/campus-infra',
57+
description:
58+
'Discover the state-of-the-art facilities and infrastructure on campus.',
59+
},
60+
],
61+
},
62+
{
63+
label: text.academics,
64+
href: 'academics',
65+
listItems: [
66+
{
67+
title: 'Departments',
68+
href: '/academics/departments',
69+
description:
70+
'Explore the diverse academic departments and their offerings.',
71+
},
72+
{
73+
title: 'Programmes',
74+
href: '/academics/programmes',
75+
description:
76+
'Discover our range of undergraduate and postgraduate programmes.',
77+
},
78+
{
79+
title: 'Courses & Curricula',
80+
href: '/academics/curricula',
81+
description: 'Browse through the detailed list of courses available.',
82+
},
83+
{
84+
title: 'Convocation',
85+
href: '/academics/convocation',
86+
description: 'Get information on upcoming convocation ceremonies.',
87+
},
88+
{
89+
title: 'Awards',
90+
href: '/academics/awards',
91+
description:
92+
'Recognizing excellence in academics, research, and beyond.',
93+
},
94+
{
95+
title: 'Scholarship',
96+
href: '/academics/scholarships',
97+
description:
98+
'Learn about scholarships, eligibility, and application details.',
99+
},
100+
{
101+
title: 'Academic Notifications',
102+
href: '/academics/notifications',
103+
description:
104+
'Stay updated with the latest academic announcements and deadlines.',
105+
},
106+
],
107+
},
27108
{ label: text.faculty, href: 'faculty-and-staff' },
28109
{ label: text.placement, href: 'training-and-placement' },
29-
{ label: text.alumni, href: 'alumni' },
110+
// { label: text.alumni, href: 'alumni' },
30111
{ label: text.activities, href: 'student-activities' },
31112
];
32113

@@ -48,16 +129,43 @@ export default async function Header({ locale }: { locale: string }) {
48129
src="assets/nitlogo.png"
49130
/>
50131
</Link>
132+
<NavigationMenu>
133+
<NavigationMenuList
134+
className={cn('hidden grow lg:flex', 'gap-4 xl:gap-5 2xl:gap-6')}
135+
>
136+
{items.map(({ label, href, listItems }, index) => (
137+
<NavigationMenuCustomListItem
138+
key={index}
139+
triggerName={label}
140+
locale={locale}
141+
listItems={listItems}
142+
href={href}
143+
imageDetails={{
144+
src: `${href}/image01.jpg`,
145+
alt: label,
146+
href: href,
147+
}}
148+
/>
149+
))}
51150

52-
<ol className={cn('hidden grow lg:flex', 'gap-4 xl:gap-5 2xl:gap-6')}>
53-
{items.map(({ label, href }, index) => (
54-
<li className="my-auto min-h-fit" key={index}>
55-
<Link href={`/${locale}/${href}`} prefetch>
56-
{label}
151+
{/* <NavigationMenuCustomListItem
152+
triggerName={items[0].label}
153+
imageDetails={{
154+
src: 'https://s3-alpha-sig.figma.com/img/054e/19b7/43c945f2ee30e43f797f944b1c02fe2e?Expires=1728259200&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=TjH6LvDVUoTwEvUvc02-8DAwccrJ9YRqDqTy5h-0O0cYSVWG03it8-zr5OSBcjGVuu5TMnV7ZlnEiM3CIHQ3mQAy7Z3~Bv2sbCL8plMbE0GDxzmjpaVkKPAfgbMpuyofWABnyQjH4cda6qWEzeBuGEw~KQfFxVuAA-wHYTA6GL~B776fRbfdfzNxtSqucrIEqfGG1nUMFEdxvTLMPCqXTjErPikIs2rDXtAZ3K3U4suPFFqLRyBQ9H0B3DAGDzxZ64CIVLkAaE~ALCRy1BBUDyXrU24E1~BeTobiCoR0q1WcnBOPMKpnUb0c2qTyaDz8BxMe9hMMI9vGnv4fxdqGBA__',
155+
alt: items[0].label,
156+
href: items[0].href,
157+
}}
158+
listItems={components}
159+
/> */}
160+
{/* <NavigationMenuItem>
161+
<Link href="/docs" legacyBehavior passHref>
162+
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
163+
Documentation
164+
</NavigationMenuLink>
57165
</Link>
58-
</li>
59-
))}
60-
</ol>
166+
</NavigationMenuItem> */}
167+
</NavigationMenuList>
168+
</NavigationMenu>
61169

62170
<ol className="inline-flex h-10 gap-2">
63171
<li className="flex h-full rounded-xl border border-neutral-500 bg-neutral-50">

components/ui/navigation-menu.tsx

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import * as React from 'react';
22
import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu';
33
import { cva } from 'class-variance-authority';
44
import { RxChevronDown } from 'react-icons/rx';
5+
import Link from 'next/link';
6+
import Image from 'next/image';
57

68
import { cn } from '~/lib/utils';
79

@@ -47,13 +49,13 @@ const navigationMenuTriggerStyle = cva(
4749
const NavigationMenuTrigger = React.forwardRef<
4850
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
4951
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
50-
>(({ className, children, title, ...props }, ref) => (
52+
>(({ className, children, ...props }, ref) => (
5153
<NavigationMenuPrimitive.Trigger
5254
ref={ref}
5355
className={cn(navigationMenuTriggerStyle(), 'group', className)}
5456
{...props}
5557
>
56-
<p className="w-fit min-w-0 text-pretty text-left">{children}</p>
58+
<p className="w-fit min-w-0 text-pretty text-left text-base">{children}</p>
5759
<RxChevronDown
5860
className="relative top-[1px] my-auto ml-1 w-5 transition duration-200 group-data-[state=open]:rotate-180"
5961
aria-hidden="true"
@@ -86,7 +88,7 @@ const NavigationMenuViewport = React.forwardRef<
8688
<div className={cn('absolute left-0 top-full flex justify-center')}>
8789
<NavigationMenuPrimitive.Viewport
8890
className={cn(
89-
'origin-top-center border-gray-200 bg-white text-gray-950 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]',
91+
'origin-top-center text-neutral-950 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-xl border border-neutral-200 bg-shade-light shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]',
9092
className
9193
)}
9294
ref={ref}
@@ -109,17 +111,107 @@ const NavigationMenuIndicator = React.forwardRef<
109111
)}
110112
{...props}
111113
>
112-
<div className="bg-gray-200 relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
114+
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-neutral-200 shadow-md" />
113115
</NavigationMenuPrimitive.Indicator>
114116
));
115117
NavigationMenuIndicator.displayName =
116118
NavigationMenuPrimitive.Indicator.displayName;
117119

120+
const NavigationMenuCustomListItem = React.forwardRef<
121+
React.ElementRef<typeof NavigationMenuPrimitive.Item>,
122+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Item> & {
123+
locale: string;
124+
triggerName: string;
125+
listItems?: {
126+
title: string;
127+
description: string;
128+
href: string;
129+
}[];
130+
imageDetails?: {
131+
src: string;
132+
alt: string;
133+
href: string;
134+
};
135+
href?: string;
136+
}
137+
>(({ imageDetails, listItems, triggerName, href, locale, ...props }, ref) => {
138+
if (!listItems) {
139+
return (
140+
<NavigationMenuItem {...props} ref={ref}>
141+
<Link href={`/${locale}/${href}`} legacyBehavior passHref>
142+
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
143+
{triggerName}
144+
</NavigationMenuLink>
145+
</Link>
146+
</NavigationMenuItem>
147+
);
148+
}
149+
const imageHeight = listItems.length > 4 ? 4 : listItems.length;
150+
return (
151+
<NavigationMenuItem {...props} ref={ref}>
152+
<NavigationMenuTrigger>{triggerName}</NavigationMenuTrigger>
153+
<NavigationMenuContent className="flex gap-4 p-6 xl:gap-6 2xl:gap-8">
154+
{imageDetails && (
155+
<Link href={imageDetails.href} passHref legacyBehavior>
156+
<NavigationMenuLink
157+
className="group relative flex select-none flex-col justify-end overflow-hidden rounded-xl no-underline outline-none"
158+
style={{ minWidth: `${70 * imageHeight}px` }}
159+
>
160+
<Image
161+
className="absolute inset-0 z-0 h-full w-full object-cover transition-transform duration-500 ease-in-out group-hover:scale-125"
162+
alt=""
163+
src={imageDetails.src}
164+
width={0}
165+
height={0}
166+
/>
167+
<section className="relative z-30 flex h-full w-full flex-col justify-end rounded-xl bg-gradient-to-b from-primary-500/0 to-primary-500 p-2 focus:shadow-md">
168+
<h5 className="!mb-0 origin-bottom-left text-shade-light transition-transform duration-500 ease-in-out group-hover:scale-150">
169+
{imageDetails.alt + '→'}
170+
</h5>
171+
</section>
172+
</NavigationMenuLink>
173+
</Link>
174+
)}
175+
<ul
176+
className={cn(
177+
'grid grid-flow-col auto-rows-max gap-4 xl:gap-6 2xl:gap-8'
178+
)}
179+
style={{
180+
gridTemplateRows: `repeat(${imageHeight}, minmax(0, 1fr))`,
181+
}}
182+
>
183+
{listItems.map(({ title, description, href }, index) => (
184+
<li key={index}>
185+
<NavigationMenuLink asChild>
186+
<Link
187+
className={cn(
188+
'group block w-56 select-none space-y-1 rounded-xl p-3 leading-none no-underline outline-none transition-colors transition-transform duration-500 ease-in-out hover:scale-110 hover:bg-neutral-50 focus:bg-neutral-50'
189+
)}
190+
href={`/${locale}/${href}`}
191+
>
192+
<h6 className="font-sans font-semibold leading-none text-shade-dark group-hover:text-primary-500 group-focus:text-primary-500">
193+
{title}
194+
</h6>
195+
<p className="line-clamp-3 text-sm leading-snug text-neutral-700 group-hover:text-primary-500 group-focus:text-primary-500">
196+
{description}
197+
</p>
198+
</Link>
199+
</NavigationMenuLink>
200+
</li>
201+
))}
202+
</ul>
203+
</NavigationMenuContent>
204+
</NavigationMenuItem>
205+
);
206+
});
207+
NavigationMenuCustomListItem.displayName = 'NavigationMenuCustomListItem';
208+
118209
export {
119210
navigationMenuTriggerStyle,
120211
NavigationMenu,
121212
NavigationMenuList,
122213
NavigationMenuItem,
214+
NavigationMenuCustomListItem,
123215
NavigationMenuContent,
124216
NavigationMenuTrigger,
125217
NavigationMenuLink,

0 commit comments

Comments
 (0)