Skip to content

Commit e0499e0

Browse files
committed
feat: connect menu
1 parent 866b13c commit e0499e0

File tree

4 files changed

+173
-59
lines changed

4 files changed

+173
-59
lines changed

frontend/src/components/Header/HeaderDialog.tsx

Lines changed: 94 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
import {MenuItemsQuery} from "@/__generated__/graphql"
2-
31
import Image from "next/image"
42
import Link from "next/link"
3+
import {motion} from "framer-motion"
54

65
import CloseIcon from "public/icons/x-close.svg"
76
import LanguageToggle from "./LanguageToggle"
8-
import {TSiteData} from "../Layout"
97
import {useLocaleContext} from "@/context/LocaleContext"
108
import {twMerge} from "tailwind-merge"
9+
import {DownIcon} from "./NavItem"
10+
import {useState} from "react"
11+
import { MenuItem, MenuChildItem } from "@/utils/buildMenuTree"
1112

1213
type Props = {
13-
menu: TSiteData["menus"]
14-
navIsOpen: boolean
14+
menu: MenuItem[];
15+
navIsOpen: boolean;
1516
setNavIsOpen: (navIsOpen: boolean) => void
1617
}
1718

@@ -50,26 +51,11 @@ const HeaderDialog = ({menu, navIsOpen, setNavIsOpen}: Props) => {
5051

5152
<nav className="flex grow flex-col justify-between gap-y-10 overflow-y-auto py-[15%]">
5253
<ul className="flex flex-col items-center space-y-4">
53-
{menu &&
54-
menu?.menuItems.nodes.map((item) => {
55-
const isActive =
56-
asPath !== "/" && item?.uri?.includes(asPath || "")
57-
return (
58-
<li key={item?.uri}>
59-
<Link
60-
href={item?.uri ?? "#"}
61-
locale={locale}
62-
className={twMerge(
63-
"text-[20px] font-semibold uppercase leading-[200%] transition-all duration-300",
64-
65-
isActive && "text-primary-blue-300",
66-
!isActive && "text-secondary-offWhite-white"
67-
)}>
68-
{item?.label}
69-
</Link>
70-
</li>
71-
)
72-
})}
54+
{menu?.map((item: MenuItem) => {
55+
const isActive =
56+
asPath !== "/" && item?.uri?.includes(asPath || "")
57+
return <NavItem key={item?.uri} item={item} />
58+
})}
7359
</ul>
7460
<div className="flex justify-center">
7561
<LanguageToggle />
@@ -79,4 +65,87 @@ const HeaderDialog = ({menu, navIsOpen, setNavIsOpen}: Props) => {
7965
)
8066
}
8167

68+
const NavItem = ({item}: { item: MenuItem }) => {
69+
const {locale} = useLocaleContext()
70+
const [open, setOpen] = useState<boolean>(false)
71+
72+
return (
73+
<li key={item?.uri}>
74+
<Link
75+
href={item?.uri ?? "#"}
76+
locale={locale}
77+
className={twMerge(
78+
"relative flex items-center justify-center gap-x-1 text-[20px] font-semibold uppercase leading-[200%] transition-all duration-300",
79+
"text-secondary-offWhite-white",
80+
item?.childItems?.nodes && "ml-5"
81+
)}>
82+
{item?.label}
83+
{item?.childItems?.nodes && (
84+
<span
85+
onClick={() => {
86+
setOpen(!open)
87+
}}
88+
className={` transition-all duration-300 ${
89+
open ? "rotate-180" : ""
90+
}`}
91+
>
92+
<DownIcon
93+
className={
94+
`cursor-pointer transition-all ${
95+
open ? "rotate-180" : ""
96+
}` as string
97+
}
98+
/>
99+
</span>
100+
)}
101+
</Link>
102+
{open && (
103+
<motion.div
104+
// onMouseEnter={() => setOpen(true)}
105+
initial={{ opacity: 0, scale: 0.95, y: -10 }}
106+
animate={{
107+
opacity: 1,
108+
scale: 1,
109+
y: 0,
110+
transition: {
111+
type: "spring",
112+
stiffness: 200,
113+
damping: 25,
114+
mass: 1,
115+
duration: 0.3
116+
}
117+
}}
118+
exit={{ opacity: 0, scale: 0.95, y: -5 }}
119+
transition={{
120+
duration: 0.2,
121+
ease: "easeOut"
122+
}}
123+
124+
style={{
125+
z: 100,
126+
127+
minHeight: "95px",
128+
boxShadow: "0px 4px 30px 0px #0F172A66",
129+
}}
130+
className="rounded-[10px] border-[0.5px] border-none bg-white">
131+
<ul className="flex list-none flex-col">
132+
{item?.childItems?.nodes &&
133+
item?.childItems?.nodes?.map((ele: MenuChildItem, id: number) => {
134+
return (
135+
<Link
136+
className={twMerge(
137+
"p-4 pb-2 pr-[34px] text-base uppercase leading-none text-primary-midBlue-main"
138+
)}
139+
key={id}
140+
href={ele?.uri || ""}>
141+
{ele?.label || "Empty label"}
142+
</Link>
143+
)
144+
})}
145+
</ul>
146+
</motion.div>
147+
)}
148+
</li>
149+
)
150+
}
82151
export default HeaderDialog

frontend/src/components/Header/NavItem.tsx

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import React, {useState} from "react"
44
import {twMerge} from "tailwind-merge"
55
import {motion} from "framer-motion"
66

7-
8-
const DownIcon = (className: any) => {
7+
export const DownIcon = (className: any) => {
98
return (
109
<svg
1110
xmlns="http://www.w3.org/2000/svg"
@@ -23,8 +22,7 @@ const DownIcon = (className: any) => {
2322
)
2423
}
2524
function NavItem({item, index}: any) {
26-
27-
const subMenu:any = {
25+
const subMenu: any = {
2826
1: [
2927
{
3028
title: "recyclingtechnik",
@@ -65,14 +63,19 @@ const subMenu:any = {
6563
"text-secondary-offWhite-white"
6664
)}>
6765
{item?.label}
68-
{(index === 1 || index === 2) && (
69-
<DownIcon
70-
className={
71-
`-translate-y-[0px] cursor-pointer transition-all ${
72-
open ? "rotate-180" : ""
73-
}` as string
74-
}
75-
/>
66+
{item?.children && (
67+
<span
68+
className={` transition-all duration-100 origin-center ${
69+
open ? "rotate-180" : ""
70+
}`}>
71+
<DownIcon
72+
className={
73+
`-translate-y-[0px] cursor-pointer transition-all ${
74+
open ? "rotate-180" : ""
75+
}` as string
76+
}
77+
/>
78+
</span>
7679
)}
7780
</Link>
7881
{open && (
@@ -109,18 +112,19 @@ const subMenu:any = {
109112
}}
110113
className="rounded-[10px] border-[0.5px] border-none bg-eerie-black">
111114
<ul className="flex list-none flex-col">
112-
{subMenu?.[index]?.map((ele: any, id: any) => {
113-
return (
114-
<Link
115-
className={twMerge(
116-
"p-4 pr-[34px] text-base uppercase leading-none hover:text-primary-blue-main"
117-
)}
118-
key={id}
119-
href={ele.link}>
120-
{ele.title}
121-
</Link>
122-
)
123-
})}
115+
{item?.children &&
116+
item?.children?.map((ele: any, id: any) => {
117+
return (
118+
<Link
119+
className={twMerge(
120+
"p-4 pr-[34px] text-base uppercase leading-none hover:text-primary-blue-main"
121+
)}
122+
key={id}
123+
href={ele?.uri || ""}>
124+
{ele?.label || "Empty label"}
125+
</Link>
126+
)
127+
})}
124128
</ul>
125129
</motion.div>
126130
)}

frontend/src/components/Header/index.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import dynamic from "next/dynamic"
44
import { useEffect, useState } from "react"
55
import { TSiteData } from "../Layout"
66
import NavItem from "./NavItem"
7+
import buildMenuTree from "@/utils/buildMenuTree"
78

89
const Link = dynamic(() => import("next/link"))
910
const HamburgerMenu = dynamic(() => import("public/icons/hamburger-menu.svg"))
@@ -17,7 +18,7 @@ type Props = {
1718
}
1819

1920
const Header = (props: Props) => {
20-
21+
const menuItems = props?.menu ? buildMenuTree(props.menu) : []
2122
const [navIsOpen, setNavIsOpen] = useState(false)
2223
const {locale, asPath} = useLocaleContext()
2324

@@ -61,14 +62,13 @@ const Header = (props: Props) => {
6162

6263
{!isMobile && (
6364
<nav className=" hidden items-center space-x-2 lg:flex xl:space-x-4">
64-
{props.menu &&
65-
props?.menu.menuItems?.nodes?.map((item, index) => {
66-
const isActive =
67-
asPath !== "/" && item?.uri?.includes(asPath || "")
68-
return (
69-
<NavItem key={item?.uri} item={item} index={index}/>
70-
)
71-
})}
65+
{menuItems?.map((item, index) => {
66+
const isActive =
67+
asPath !== "/" && item?.uri?.includes(asPath || "")
68+
return (
69+
<NavItem key={item?.uri} item={item} index={index}/>
70+
)
71+
})}
7272
</nav>
7373
)}
7474
{!isMobile && (
@@ -91,7 +91,7 @@ const Header = (props: Props) => {
9191
</div>
9292
{isMobile && (
9393
<HeaderDialog
94-
menu={props.menu}
94+
menu={menuItems}
9595
navIsOpen={navIsOpen}
9696
setNavIsOpen={setNavIsOpen}
9797
/>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { TSiteData } from "@/components/Layout";
2+
3+
export interface MenuChildItem {
4+
__typename: string;
5+
title: null | string;
6+
uri: string;
7+
label: string;
8+
}
9+
10+
export interface MenuItem {
11+
__typename: string;
12+
uri: string;
13+
label: string;
14+
title: null | string;
15+
parentId: string | null;
16+
id: string;
17+
target: null | string;
18+
childItems: {
19+
__typename: string;
20+
nodes: MenuChildItem[];
21+
};
22+
}
23+
24+
interface MenuData {
25+
__typename: string;
26+
locations: string[];
27+
menuItems: {
28+
__typename: string;
29+
nodes: MenuItem[];
30+
};
31+
}
32+
33+
function buildMenuTree(menu: MenuData | undefined) {
34+
if (!menu?.menuItems?.nodes) {
35+
return [];
36+
}
37+
38+
return menu.menuItems.nodes;
39+
}
40+
41+
export default buildMenuTree;

0 commit comments

Comments
 (0)