Initial Commit
This commit is contained in:
89
components/layout/mobile-nav.tsx
Normal file
89
components/layout/mobile-nav.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { curriculum } from "@/lib/curriculum";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useState } from "react";
|
||||
|
||||
const unitColorMap = {
|
||||
"unit-1": "text-unit-1-dark",
|
||||
"unit-2": "text-unit-2-dark",
|
||||
"unit-3": "text-unit-3-dark",
|
||||
"unit-4": "text-unit-4-dark",
|
||||
};
|
||||
|
||||
const unitDotColor = {
|
||||
"unit-1": "bg-unit-1",
|
||||
"unit-2": "bg-unit-2",
|
||||
"unit-3": "bg-unit-3",
|
||||
"unit-4": "bg-unit-4",
|
||||
};
|
||||
|
||||
export function MobileNav() {
|
||||
const pathname = usePathname();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="lg:hidden">
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="flex items-center gap-2 rounded-xl border border-border/60 bg-surface px-3.5 py-2 text-sm font-medium shadow-[var(--shadow-sm)] transition-all hover:shadow-[var(--shadow-md)]"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
{isOpen ? (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
) : (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M4 6h16M4 12h16M4 18h16" />
|
||||
)}
|
||||
</svg>
|
||||
Topics
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div className="absolute left-0 right-0 top-full z-40 max-h-[70vh] overflow-y-auto border-b border-border/60 bg-surface p-4 shadow-[var(--shadow-lg)]">
|
||||
<Link
|
||||
href="/lessons"
|
||||
onClick={() => setIsOpen(false)}
|
||||
className="mb-4 flex items-center gap-2 rounded-xl px-3 py-2 text-sm font-medium text-muted transition-colors hover:bg-background hover:text-foreground"
|
||||
>
|
||||
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M4 6h16M4 10h16M4 14h16M4 18h16" />
|
||||
</svg>
|
||||
All Topics
|
||||
</Link>
|
||||
<div className="mb-3 h-px bg-border/60" />
|
||||
{curriculum.map((unit) => (
|
||||
<div key={unit.slug} className="mb-4">
|
||||
<p className={cn("mb-1.5 flex items-center gap-2 px-3 text-xs font-bold uppercase tracking-wider", unitColorMap[unit.color])}>
|
||||
<span className={cn("h-2 w-2 rounded-full", unitDotColor[unit.color])} />
|
||||
Unit {unit.number}: {unit.title}
|
||||
</p>
|
||||
<div className="space-y-0.5">
|
||||
{unit.topics.map((topic) => {
|
||||
const href = `/lessons/${unit.slug}/${topic.slug}`;
|
||||
return (
|
||||
<Link
|
||||
key={topic.slug}
|
||||
href={href}
|
||||
onClick={() => setIsOpen(false)}
|
||||
className={cn(
|
||||
"block rounded-lg px-3 py-1.5 text-sm transition-colors",
|
||||
pathname === href
|
||||
? "bg-foreground text-background font-medium"
|
||||
: "text-muted hover:bg-background hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
{topic.shortTitle}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user