diff --git a/src/components/Navigation/Navigation.astro b/src/components/Navigation/Navigation.astro index 88af9075e..88880fc70 100644 --- a/src/components/Navigation/Navigation.astro +++ b/src/components/Navigation/Navigation.astro @@ -4,6 +4,7 @@ import Icon from '../AstroIcon.astro'; import { NavigationDropdown } from '../NavigationDropdown'; import { AccountDropdown } from './AccountDropdown'; import NewIndicator from './NewIndicator.astro'; +import { RoadmapDropdownMenu } from '../RoadmapDropdownMenu/RoadmapDropdownMenu'; ---
@@ -19,7 +20,7 @@ import NewIndicator from './NewIndicator.astro'; Teams @@ -35,32 +36,18 @@ import NewIndicator from './NewIndicator.astro'; - diff --git a/src/components/NavigationDropdown.tsx b/src/components/NavigationDropdown.tsx index 4d7fb8faa..31e9978a5 100644 --- a/src/components/NavigationDropdown.tsx +++ b/src/components/NavigationDropdown.tsx @@ -2,22 +2,34 @@ import { BookOpenText, CheckSquare, FileQuestion, + FolderKanban, Menu, Shirt, Video, Waypoints, } from 'lucide-react'; -import { useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { cn } from '../lib/classname.ts'; import { useOutsideClick } from '../hooks/use-outside-click.ts'; +import { + navigationDropdownOpen, + roadmapsDropdownOpen, +} from '../stores/page.ts'; +import { useStore } from '@nanostores/react'; const links = [ { link: '/roadmaps', - label: 'Roadmaps', - description: 'Step by step learning paths', + label: 'Official Roadmaps', + description: 'Made by subject matter experts', Icon: Waypoints, }, + { + link: '/backend/projects', + label: 'Projects', + description: 'Skill-up with real-world projects', + Icon: FolderKanban, + }, { link: '/best-practices', label: 'Best Practices', @@ -54,21 +66,30 @@ const links = [ export function NavigationDropdown() { const dropdownRef = useRef(null); - const [isOpen, setIsOpen] = useState(false); + + const $navigationDropdownOpen = useStore(navigationDropdownOpen); + const $roadmapsDropdownOpen = useStore(roadmapsDropdownOpen); useOutsideClick(dropdownRef, () => { - setIsOpen(false); + navigationDropdownOpen.set(false); }); + useEffect(() => { + if ($roadmapsDropdownOpen) { + navigationDropdownOpen.set(false); + } + }, [$roadmapsDropdownOpen]); + return (
@@ -76,9 +97,11 @@ export function NavigationDropdown() { className={cn( 'pointer-events-none invisible absolute left-0 top-full z-[999] mt-2 w-48 min-w-[320px] -translate-y-1 rounded-lg bg-slate-800 py-2 opacity-0 shadow-xl transition-all duration-100', { - 'pointer-events-auto visible translate-y-2.5 opacity-100': isOpen, + 'pointer-events-auto visible translate-y-2.5 opacity-100': + $navigationDropdownOpen, }, )} + role="menu" > {links.map((link) => ( diff --git a/src/components/RoadmapDropdownMenu/RoadmapDropdownMenu.tsx b/src/components/RoadmapDropdownMenu/RoadmapDropdownMenu.tsx new file mode 100644 index 000000000..209404e32 --- /dev/null +++ b/src/components/RoadmapDropdownMenu/RoadmapDropdownMenu.tsx @@ -0,0 +1,93 @@ +import { ChevronDown, Globe, Menu, Sparkles, Waypoints } from 'lucide-react'; +import { useEffect, useRef, useState } from 'react'; +import { useOutsideClick } from '../../hooks/use-outside-click'; +import { cn } from '../../lib/classname'; +import { + navigationDropdownOpen, + roadmapsDropdownOpen, +} from '../../stores/page.ts'; +import { useStore } from '@nanostores/react'; + +const links = [ + { + link: '/roadmaps', + label: 'Official Roadmaps', + description: 'Made by subject matter experts', + Icon: Waypoints, + }, + { + link: '/ai/explore', + label: 'AI Roadmaps', + description: 'Generate roadmaps with AI', + Icon: Sparkles, + }, + { + link: '/community', + label: 'Community Roadmaps', + description: 'Made by community members', + Icon: Globe, + }, +]; + +export function RoadmapDropdownMenu() { + const dropdownRef = useRef(null); + + const $roadmapsDropdownOpen = useStore(roadmapsDropdownOpen); + const $navigationDropdownOpen = useStore(navigationDropdownOpen); + + useOutsideClick(dropdownRef, () => { + roadmapsDropdownOpen.set(false); + }); + + useEffect(() => { + if ($navigationDropdownOpen) { + roadmapsDropdownOpen.set(false); + } + }, [$navigationDropdownOpen]); + + return ( +
+ +
+ {links.map((link) => ( + + + + + + + {link.label} + + {link.description} + + + ))} +
+
+ ); +} diff --git a/src/stores/page.ts b/src/stores/page.ts index 137450ea2..3d507c736 100644 --- a/src/stores/page.ts +++ b/src/stores/page.ts @@ -2,3 +2,6 @@ import { atom } from 'nanostores'; export const pageProgressMessage = atom(undefined); export const sponsorHidden = atom(false); + +export const roadmapsDropdownOpen = atom(false); +export const navigationDropdownOpen = atom(false); \ No newline at end of file