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 (
+
+
+
+
+ );
+}
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