From 763949be701dfe792e0556df4d6cccee9c90107e Mon Sep 17 00:00:00 2001 From: Sean Coughlin Date: Fri, 4 Apr 2025 14:58:51 -0400 Subject: [PATCH 1/6] Make header work on mobile --- components/layout/Header.tsx | 264 ++++++++++++++++++++++++++++------- 1 file changed, 214 insertions(+), 50 deletions(-) diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx index 600e178..ffa61fa 100644 --- a/components/layout/Header.tsx +++ b/components/layout/Header.tsx @@ -1,66 +1,112 @@ "use client"; +import { useState, useEffect } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; export default function Header() { const pathname = usePathname(); + const [isMenuOpen, setIsMenuOpen] = useState(false); + + // Close mobile menu when navigating between pages + useEffect(() => { + setIsMenuOpen(false); + }, [pathname]); + + // Close menu when clicking outside or pressing Escape + useEffect(() => { + const handleOutsideClick = (event: MouseEvent) => { + const target = event.target as HTMLElement; + if ( + !target.closest("#mobile-menu-button") && + !target.closest("#mobile-menu") && + isMenuOpen + ) { + setIsMenuOpen(false); + } + }; + + const handleEsc = (event: KeyboardEvent) => { + if (event.key === "Escape" && isMenuOpen) { + setIsMenuOpen(false); + } + }; + + document.addEventListener("mousedown", handleOutsideClick); + document.addEventListener("keydown", handleEsc); + + return () => { + document.removeEventListener("mousedown", handleOutsideClick); + document.removeEventListener("keydown", handleEsc); + }; + }, [isMenuOpen]); + + // Prevent scrolling when mobile menu is open + useEffect(() => { + if (isMenuOpen) { + document.body.style.overflow = "hidden"; + } else { + document.body.style.overflow = ""; + } + + return () => { + document.body.style.overflow = ""; + }; + }, [isMenuOpen]); return (
-
-
- - SQL Playground - -
- -
- + SQL Playground + +
+ + {/* Desktop navigation */} + + + {/* Mobile menu button */} +
+ + GitHub + +
+ + {/* Mobile menu, show/hide based on menu state */} +
+
+ + Home + + + Lessons + + + Sandbox + + + Visualizer + +
+
); } From 37ad7042867bad36fee3bebde387e473cb1baa1b Mon Sep 17 00:00:00 2001 From: Sean Coughlin Date: Fri, 4 Apr 2025 15:08:10 -0400 Subject: [PATCH 2/6] Improve header maintainability --- components/layout/Header.tsx | 255 ++++++++++++++--------------------- 1 file changed, 104 insertions(+), 151 deletions(-) diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx index ffa61fa..48b5fc8 100644 --- a/components/layout/Header.tsx +++ b/components/layout/Header.tsx @@ -4,6 +4,66 @@ import { useState, useEffect } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; +// Extracted icon components +const GitHubIcon = () => ( + +); + +const MenuIcon = () => ( + +); + +const CloseIcon = () => ( + +); + +// Navigation links configuration +const navLinks = [ + { href: "/", label: "Home" }, + { href: "/lessons", label: "Lessons" }, + { href: "/sandbox", label: "Sandbox" }, + { href: "/visualizer", label: "Visualizer" }, +]; + export default function Header() { const pathname = usePathname(); const [isMenuOpen, setIsMenuOpen] = useState(false); @@ -15,49 +75,49 @@ export default function Header() { // Close menu when clicking outside or pressing Escape useEffect(() => { + if (!isMenuOpen) return; + const handleOutsideClick = (event: MouseEvent) => { const target = event.target as HTMLElement; if ( !target.closest("#mobile-menu-button") && - !target.closest("#mobile-menu") && - isMenuOpen + !target.closest("#mobile-menu") ) { setIsMenuOpen(false); } }; const handleEsc = (event: KeyboardEvent) => { - if (event.key === "Escape" && isMenuOpen) { + if (event.key === "Escape") { setIsMenuOpen(false); } }; + // Prevent scrolling when mobile menu is open + document.body.style.overflow = "hidden"; + document.addEventListener("mousedown", handleOutsideClick); document.addEventListener("keydown", handleEsc); return () => { + document.body.style.overflow = ""; document.removeEventListener("mousedown", handleOutsideClick); document.removeEventListener("keydown", handleEsc); }; }, [isMenuOpen]); - // Prevent scrolling when mobile menu is open - useEffect(() => { - if (isMenuOpen) { - document.body.style.overflow = "hidden"; - } else { - document.body.style.overflow = ""; + const isActive = (path: string) => { + if (path === "/") { + return pathname === path; } - - return () => { - document.body.style.overflow = ""; - }; - }, [isMenuOpen]); + return pathname === path || pathname.startsWith(`${path}/`); + }; return (
+ {/* Logo */}
SQL Playground @@ -66,46 +126,19 @@ export default function Header() { {/* Desktop navigation */} @@ -137,18 +159,7 @@ export default function Header() { className="text-gray-500 hover:text-gray-700 mr-4" > GitHub - +
- {/* Mobile menu, show/hide based on menu state */} + {/* Mobile menu */}
- - Home - - - Lessons - - - Sandbox - - - Visualizer - + {navLinks.map((link) => ( + + {link.label} + + ))}
From 7a16ae0a3a6a024336f293ad7a7e59f4313dfc2b Mon Sep 17 00:00:00 2001 From: Sean Coughlin Date: Fri, 4 Apr 2025 15:13:53 -0400 Subject: [PATCH 3/6] Create svgs for header --- components/layout/Header.tsx | 83 ++++++++++++----------------------- public/images/Github-icon.svg | 3 ++ public/images/close-icon.svg | 4 ++ public/images/menu-icon.svg | 4 ++ 4 files changed, 39 insertions(+), 55 deletions(-) create mode 100644 public/images/Github-icon.svg create mode 100644 public/images/close-icon.svg create mode 100644 public/images/menu-icon.svg diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx index 48b5fc8..4446440 100644 --- a/components/layout/Header.tsx +++ b/components/layout/Header.tsx @@ -3,58 +3,7 @@ import { useState, useEffect } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; - -// Extracted icon components -const GitHubIcon = () => ( - -); - -const MenuIcon = () => ( - -); - -const CloseIcon = () => ( - -); +import Image from "next/image"; // Navigation links configuration const navLinks = [ @@ -146,7 +95,12 @@ export default function Header() { className="text-gray-500 hover:text-gray-700" > GitHub - + GitHub Icon @@ -159,7 +113,12 @@ export default function Header() { className="text-gray-500 hover:text-gray-700 mr-4" > GitHub - + GitHub Icon diff --git a/public/images/Github-icon.svg b/public/images/Github-icon.svg new file mode 100644 index 0000000..1980a16 --- /dev/null +++ b/public/images/Github-icon.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/public/images/close-icon.svg b/public/images/close-icon.svg new file mode 100644 index 0000000..3d898b4 --- /dev/null +++ b/public/images/close-icon.svg @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/public/images/menu-icon.svg b/public/images/menu-icon.svg new file mode 100644 index 0000000..0b8c44d --- /dev/null +++ b/public/images/menu-icon.svg @@ -0,0 +1,4 @@ + \ No newline at end of file From d25945c45c976a607cccee7ddc0a8d5dc22e5875 Mon Sep 17 00:00:00 2001 From: Sean Coughlin Date: Fri, 4 Apr 2025 15:18:17 -0400 Subject: [PATCH 4/6] Fix icons --- components/layout/Header.tsx | 4 ++-- public/images/Github-icon.svg | 4 ++-- public/images/close-icon.svg | 4 ++-- public/images/menu-icon.svg | 4 ---- public/images/open-icon.svg | 4 ++++ 5 files changed, 10 insertions(+), 10 deletions(-) delete mode 100644 public/images/menu-icon.svg create mode 100644 public/images/open-icon.svg diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx index 4446440..c220247 100644 --- a/components/layout/Header.tsx +++ b/components/layout/Header.tsx @@ -96,7 +96,7 @@ export default function Header() { > GitHub GitHub Icon GitHub - + \ No newline at end of file diff --git a/public/images/close-icon.svg b/public/images/close-icon.svg index 3d898b4..c39e202 100644 --- a/public/images/close-icon.svg +++ b/public/images/close-icon.svg @@ -1,4 +1,4 @@ - \ No newline at end of file diff --git a/public/images/menu-icon.svg b/public/images/menu-icon.svg deleted file mode 100644 index 0b8c44d..0000000 --- a/public/images/menu-icon.svg +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/public/images/open-icon.svg b/public/images/open-icon.svg new file mode 100644 index 0000000..4dcd0bd --- /dev/null +++ b/public/images/open-icon.svg @@ -0,0 +1,4 @@ + \ No newline at end of file From 2be7fe2b27d10ff053f4a53233d68d5ca92ef321 Mon Sep 17 00:00:00 2001 From: Sean Coughlin Date: Fri, 4 Apr 2025 15:19:02 -0400 Subject: [PATCH 5/6] Revert "Fix icons" This reverts commit d25945c45c976a607cccee7ddc0a8d5dc22e5875. --- components/layout/Header.tsx | 4 ++-- public/images/Github-icon.svg | 4 ++-- public/images/close-icon.svg | 4 ++-- public/images/menu-icon.svg | 4 ++++ public/images/open-icon.svg | 4 ---- 5 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 public/images/menu-icon.svg delete mode 100644 public/images/open-icon.svg diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx index c220247..4446440 100644 --- a/components/layout/Header.tsx +++ b/components/layout/Header.tsx @@ -96,7 +96,7 @@ export default function Header() { > GitHub GitHub Icon GitHub - + \ No newline at end of file diff --git a/public/images/close-icon.svg b/public/images/close-icon.svg index c39e202..3d898b4 100644 --- a/public/images/close-icon.svg +++ b/public/images/close-icon.svg @@ -1,4 +1,4 @@ - \ No newline at end of file diff --git a/public/images/menu-icon.svg b/public/images/menu-icon.svg new file mode 100644 index 0000000..0b8c44d --- /dev/null +++ b/public/images/menu-icon.svg @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/public/images/open-icon.svg b/public/images/open-icon.svg deleted file mode 100644 index 4dcd0bd..0000000 --- a/public/images/open-icon.svg +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file From 2cf0ba09904ad504094b76a34a1cd9594d98cc81 Mon Sep 17 00:00:00 2001 From: Sean Coughlin Date: Fri, 4 Apr 2025 15:19:13 -0400 Subject: [PATCH 6/6] Revert "Create svgs for header" This reverts commit 7a16ae0a3a6a024336f293ad7a7e59f4313dfc2b. --- components/layout/Header.tsx | 83 +++++++++++++++++++++++------------ public/images/Github-icon.svg | 3 -- public/images/close-icon.svg | 4 -- public/images/menu-icon.svg | 4 -- 4 files changed, 55 insertions(+), 39 deletions(-) delete mode 100644 public/images/Github-icon.svg delete mode 100644 public/images/close-icon.svg delete mode 100644 public/images/menu-icon.svg diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx index 4446440..48b5fc8 100644 --- a/components/layout/Header.tsx +++ b/components/layout/Header.tsx @@ -3,7 +3,58 @@ import { useState, useEffect } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; -import Image from "next/image"; + +// Extracted icon components +const GitHubIcon = () => ( + +); + +const MenuIcon = () => ( + +); + +const CloseIcon = () => ( + +); // Navigation links configuration const navLinks = [ @@ -95,12 +146,7 @@ export default function Header() { className="text-gray-500 hover:text-gray-700" > GitHub - GitHub Icon + @@ -113,12 +159,7 @@ export default function Header() { className="text-gray-500 hover:text-gray-700 mr-4" > GitHub - GitHub Icon + diff --git a/public/images/Github-icon.svg b/public/images/Github-icon.svg deleted file mode 100644 index 1980a16..0000000 --- a/public/images/Github-icon.svg +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/public/images/close-icon.svg b/public/images/close-icon.svg deleted file mode 100644 index 3d898b4..0000000 --- a/public/images/close-icon.svg +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/public/images/menu-icon.svg b/public/images/menu-icon.svg deleted file mode 100644 index 0b8c44d..0000000 --- a/public/images/menu-icon.svg +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file