Skip to content

Commit 6db3383

Browse files
committed
Added functionalities to nbar tiles
1 parent ab3bb37 commit 6db3383

File tree

8 files changed

+392
-12
lines changed

8 files changed

+392
-12
lines changed

Diff for: public/hqdefault.jpg

16.1 KB
Loading

Diff for: public/three_dots.svg

+17
Loading

Diff for: src/components/BellTIle.tsx

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { useEffect, useRef, useState } from "react";
2+
3+
interface BellTileProps {
4+
setIsNotificationsOpen: React.Dispatch<React.SetStateAction<boolean>>;
5+
bellIconRef: React.RefObject<HTMLDivElement>;
6+
}
7+
8+
interface BellNotificationProps {
9+
channelIcon: string;
10+
channelTnail: string;
11+
text: string;
12+
}
13+
14+
export function BellTile({
15+
setIsNotificationsOpen,
16+
bellIconRef,
17+
}: BellTileProps) {
18+
const belltilediv = useRef(null);
19+
const [isVisible, setIsVisible] = useState(true);
20+
const BellNotification: React.FC<BellNotificationProps> = ({
21+
channelIcon,
22+
channelTnail,
23+
text,
24+
}) => (
25+
<div className="flex">
26+
<div className="flex gap-4 items-center">
27+
<img className="h-12 w-12 rounded-full " src={channelIcon} alt="" />
28+
<p>{text}</p>
29+
</div>
30+
31+
<div className="flex">
32+
<img className="h-24 w-44 p-5 rounded-xl" src={channelTnail} alt="" />
33+
<img src="three_dots.svg" alt="" />
34+
</div>
35+
</div>
36+
);
37+
const handlemousedown = (event: MouseEvent) => {
38+
if (
39+
belltilediv.current &&
40+
!(belltilediv.current as HTMLElement).contains(event.target as Node) &&
41+
bellIconRef.current &&
42+
!(bellIconRef.current as HTMLElement).contains(event.target as Node)
43+
) {
44+
setIsVisible(false);
45+
setIsNotificationsOpen(false);
46+
}
47+
};
48+
useEffect(() => {
49+
document.addEventListener("mousedown", handlemousedown);
50+
return () => {
51+
document.removeEventListener("mousedown", handlemousedown);
52+
};
53+
}, []);
54+
55+
if (!isVisible) return null;
56+
57+
return (
58+
<div
59+
ref={belltilediv}
60+
className="bg-[#282828] fixed rounded-xl top-[65px] right-16 z-50 "
61+
>
62+
<div className=" sticky -top-0 bg-[#282828] rounded-xl">
63+
<div className="py-2 px-4">
64+
<div className="flex justify-between ">
65+
<p>Notifications</p>
66+
<img className="" src="youtube_settings.svg" alt="" />
67+
</div>
68+
</div>
69+
<hr className="border-[#4E4E4E] my-2 " />
70+
</div>
71+
72+
<div className=" h-[642px] w-[482px] overflow-y-scroll scrollbar-thin scrollbar-thumb-[#5E5E5D] scrollbar-track-transparent">
73+
<div className="flex flex-col gap-2 items-center px-4 ">
74+
<BellNotification
75+
channelIcon="A.jpg"
76+
channelTnail="hqdefault.jpg"
77+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
78+
/>
79+
<BellNotification
80+
channelIcon="A.jpg"
81+
channelTnail="hqdefault.jpg"
82+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
83+
/>
84+
<BellNotification
85+
channelIcon="A.jpg"
86+
channelTnail="hqdefault.jpg"
87+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
88+
/>
89+
<BellNotification
90+
channelIcon="A.jpg"
91+
channelTnail="hqdefault.jpg"
92+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
93+
/>
94+
<BellNotification
95+
channelIcon="A.jpg"
96+
channelTnail="hqdefault.jpg"
97+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
98+
/>
99+
<BellNotification
100+
channelIcon="A.jpg"
101+
channelTnail="hqdefault.jpg"
102+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
103+
/>
104+
<BellNotification
105+
channelIcon="A.jpg"
106+
channelTnail="hqdefault.jpg"
107+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
108+
/>
109+
<BellNotification
110+
channelIcon="A.jpg"
111+
channelTnail="hqdefault.jpg"
112+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
113+
/>
114+
<BellNotification
115+
channelIcon="A.jpg"
116+
channelTnail="hqdefault.jpg"
117+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
118+
/>
119+
<BellNotification
120+
channelIcon="A.jpg"
121+
channelTnail="hqdefault.jpg"
122+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
123+
/>
124+
<BellNotification
125+
channelIcon="A.jpg"
126+
channelTnail="hqdefault.jpg"
127+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
128+
/>
129+
<BellNotification
130+
channelIcon="A.jpg"
131+
channelTnail="hqdefault.jpg"
132+
text="Lorem ipsum dolor sit amet consectetur adipisicing elit"
133+
/>
134+
</div>
135+
</div>
136+
</div>
137+
);
138+
}

Diff for: src/components/BigSideBar.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function BigSideBar({ isOpen, setIsOpen }: BigSideBarProps) {
2323
return (
2424
<div
2525
className={`${
26-
isOpen ? "w-0" : "w-[240px] "
26+
isOpen ? "w-240" : "w-[240px] "
2727
} fixed top-16 z-20 md:static md:z-0 bg-[#0F0F0F] md:bg-transparent`}
2828
>
2929
<div
@@ -83,7 +83,7 @@ export function BigSideBar({ isOpen, setIsOpen }: BigSideBarProps) {
8383
))}
8484
</div>
8585

86-
<div className="flex gap-6 p-[12px] pl-[15px] self-start hover:bg-[#2E2E2E] rounded-lg">
86+
<div className="flex gap-6 p-[12px] pl-[15px] self-start ">
8787
<img src="subscriptions_down_arrow.svg" alt="" />
8888
<button
8989
className="text-sm text-gray-300 "

Diff for: src/components/NavBar.tsx

+41-6
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,38 @@
11
import { SideBar } from "@/components/SideBar";
22
import { BigSideBar } from "./BigSideBar";
3-
import { useEffect, useState } from "react";
3+
import { useEffect, useRef, useState } from "react";
44
interface NavBarProps {
55
isOpen: boolean;
66
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
77
isSearchOpen: boolean;
88
setIsSearchOpen: React.Dispatch<React.SetStateAction<boolean>>;
9+
isVideoOpen: boolean;
10+
setIsVideoOpen: React.Dispatch<React.SetStateAction<boolean>>;
11+
isProfileTileOpen: boolean;
12+
setIsProfileTileOpen: React.Dispatch<React.SetStateAction<boolean>>;
13+
isNotificationsOpen: boolean;
14+
setIsNotificationsOpen: React.Dispatch<React.SetStateAction<boolean>>;
15+
videoIconRef: React.RefObject<HTMLDivElement>;
16+
bellIconRef: React.RefObject<HTMLDivElement>;
17+
profileIconRef: React.RefObject<HTMLDivElement>;
918
}
1019
export function NavBar({
1120
isOpen,
1221
setIsOpen,
1322
isSearchOpen,
1423
setIsSearchOpen,
24+
isVideoOpen,
25+
setIsVideoOpen,
26+
isProfileTileOpen,
27+
setIsProfileTileOpen,
28+
isNotificationsOpen,
29+
setIsNotificationsOpen,
30+
videoIconRef,
31+
bellIconRef,
32+
profileIconRef,
1533
}: NavBarProps) {
1634
const [isSearchOpen2, setIsSearchOpen2] = useState(false);
17-
const [isInputFocused, setIsInputFocused] = useState(false); // Track input focus
35+
const [isInputFocused, setIsInputFocused] = useState(false);
1836

1937
useEffect(() => {
2038
const handleResize = () => {
@@ -199,8 +217,12 @@ export function NavBar({
199217
</div>
200218
</div>
201219

202-
<div className="flex gap-4 justify-between items-center">
203-
<div className="w-6 hidden md:block">
220+
<div className="flex gap-4 justify-between items-center ">
221+
<div
222+
className="w-6 md:block "
223+
onClick={() => setIsVideoOpen(!isVideoOpen)}
224+
ref={videoIconRef}
225+
>
204226
<svg
205227
xmlns="http://www.w3.org/2000/svg"
206228
fill="none"
@@ -218,7 +240,13 @@ export function NavBar({
218240
</div>
219241

220242
{isSearchOpen == false && (
221-
<div className="w-6">
243+
<div
244+
className="w-6"
245+
onClick={() => {
246+
setIsNotificationsOpen(!isNotificationsOpen);
247+
}}
248+
ref={bellIconRef}
249+
>
222250
<svg
223251
xmlns="http://www.w3.org/2000/svg"
224252
fill="none"
@@ -237,7 +265,14 @@ export function NavBar({
237265
)}
238266

239267
{isSearchOpen == false && (
240-
<img className="w-8 h-8 rounded-full" src="/A.jpg " alt="" />
268+
<div ref={profileIconRef}>
269+
<img
270+
className="w-8 h-8 rounded-full"
271+
src="/A.jpg "
272+
alt=""
273+
onClick={() => setIsProfileTileOpen(!isProfileTileOpen)}
274+
/>
275+
</div>
241276
)}
242277
</div>
243278
</div>

Diff for: src/components/ProfileTile.tsx

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { useEffect, useRef, useState } from "react";
2+
3+
interface SubProfileTileProps {
4+
icon: string;
5+
text: string;
6+
}
7+
8+
interface ProfileTileProps {
9+
setIsProfileTileOpen: React.Dispatch<React.SetStateAction<boolean>>;
10+
profileIconRef: React.RefObject<HTMLDivElement>;
11+
}
12+
13+
export function ProfileTile({
14+
setIsProfileTileOpen,
15+
profileIconRef,
16+
}: ProfileTileProps) {
17+
const profiletilediv = useRef(null);
18+
const [isVisible, setIsVisible] = useState(true);
19+
20+
const handlemousedown = (event: MouseEvent) => {
21+
if (
22+
profiletilediv.current &&
23+
!(profiletilediv.current as HTMLElement).contains(event.target as Node) &&
24+
profileIconRef.current &&
25+
!(profileIconRef.current as HTMLElement).contains(event.target as Node)
26+
) {
27+
setIsVisible(false);
28+
setIsProfileTileOpen(false)
29+
}
30+
};
31+
useEffect(() => {
32+
document.addEventListener("mousedown", handlemousedown);
33+
return () => {
34+
document.removeEventListener("mousedown", handlemousedown);
35+
};
36+
}, []);
37+
const SubProfileTile: React.FC<SubProfileTileProps> = ({ icon, text }) => (
38+
<div className="flex gap-4">
39+
<img src={icon} alt="" />
40+
<p className="text-sm text-gray-300">{text}</p>
41+
</div>
42+
);
43+
if (!isVisible) return null;
44+
return (
45+
<div
46+
ref={profiletilediv}
47+
className="flex flex-col gap-3 w-[300px] h-[700px] rounded-xl bg-[#282828] fixed p-3 top-[60px] right-5 z-40"
48+
>
49+
<div className="flex flex-col items-center">
50+
<SubProfileTile
51+
icon=""
52+
text=" Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nisi
53+
eum debitis?"
54+
/>
55+
</div>
56+
57+
<hr className="border-[#4E4E4E]" />
58+
59+
<div className="flex flex-col gap-3">
60+
<SubProfileTile icon="you_your_Channel.svg" text="Google Account" />
61+
<SubProfileTile icon="you_your_Channel.svg" text="Switch account" />
62+
<SubProfileTile icon="you_your_Channel.svg" text="Sign out" />
63+
</div>
64+
<hr className="border-[#4E4E4E]" />
65+
66+
<div className="flex flex-col gap-5">
67+
<SubProfileTile icon="you_your_Channel.svg" text="YouTube Studio" />
68+
<SubProfileTile
69+
icon="you_your_Channel.svg"
70+
text="Purchases and memberships"
71+
/>
72+
</div>
73+
<hr className="border-[#4E4E4E]" />
74+
75+
<div className="flex flex-col gap-5">
76+
<SubProfileTile
77+
icon="you_your_Channel.svg"
78+
text="Your data in YouTube"
79+
/>
80+
<SubProfileTile
81+
icon="you_your_Channel.svg"
82+
text="Appearance: Device theme"
83+
/>
84+
<SubProfileTile icon="you_your_Channel.svg" text="Language: English" />
85+
<SubProfileTile
86+
icon="you_your_Channel.svg"
87+
text="Restricted Mode: off"
88+
/>
89+
<SubProfileTile icon="you_your_Channel.svg" text="Location: India" />
90+
<SubProfileTile icon="you_your_Channel.svg" text="Keyboard shortcuts" />
91+
</div>
92+
<hr className="border-[#4E4E4E]" />
93+
94+
<div className="flex flex-col gap-5">
95+
<SubProfileTile icon="you_your_Channel.svg" text="Settings" />
96+
</div>
97+
<hr className="border-[#4E4E4E]" />
98+
99+
<div className="flex flex-col gap-5">
100+
<SubProfileTile icon="you_your_Channel.svg" text="Help" />
101+
<SubProfileTile icon="you_your_Channel.svg" text="Send feedback" />
102+
</div>
103+
</div>
104+
);
105+
}

0 commit comments

Comments
 (0)