Implement breadcrumbs

This commit is contained in:
2025-07-03 21:02:16 +02:00
parent 5dc9c77c25
commit 287ef67c37
2 changed files with 82 additions and 33 deletions

View File

@ -1,30 +1,75 @@
"use client"; "use client"
import { ChevronRight, HomeIcon } from "lucide-react"; import {
import Link from "next/link"; FolderIcon,
FolderOpenIcon,
HomeIcon,
ImageIcon,
InfoIcon,
LayersIcon,
TagIcon,
UserIcon,
} from "lucide-react"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { Fragment, JSX } from "react"
export function Breadcrumbs({ const iconMap: Record<string, JSX.Element> = {
items, "about": <InfoIcon className="w-4 h-4" />,
}: { "artists": <UserIcon className="w-4 h-4" />,
items: { name: string; href?: string }[]; "categories": <LayersIcon className="w-4 h-4" />,
}) { "tags": <TagIcon className="w-4 h-4" />,
return ( "gallery": <FolderIcon className="w-4 h-4" />,
<nav className="flex items-center text-sm mb-4 text-muted-foreground"> "album": <FolderOpenIcon className="w-4 h-4" />,
<Link href="/" className="flex items-center gap-1 hover:text-foreground"> "image": <ImageIcon className="w-4 h-4" />,
<HomeIcon size={16} /> }
</Link>
{items.map((item, idx) => ( export default function Breadcrumbs() {
<span key={idx} className="flex items-center"> const pathname = usePathname()
<ChevronRight size={16} className="mx-1" /> const rawSegments = pathname.split("/").filter(Boolean)
{item.href ? (
<Link href={item.href} className="hover:text-foreground"> // If path is just "/", return nothing
{item.name} if (rawSegments.length === 0) return null
</Link>
) : ( // Special handling: remove "galleries" from breadcrumb trail
<span className="text-foreground">{item.name}</span> const segments = rawSegments.filter((seg, index) =>
)} !(seg === "galleries" && index === 0)
</span> )
))}
</nav> return (
); <div className="text-sm px-1 text-muted-foreground flex items-center flex-wrap gap-1">
<Link href="/" className="inline-flex items-center gap-1 hover:underline font-medium text-foreground">
<HomeIcon className="w-4 h-4" />
Home
</Link>
{segments.length > 0 && <span>{">"}</span>}
{segments.map((seg, i) => {
const href = "/" + rawSegments.slice(0, rawSegments.indexOf(seg) + 1).join("/")
const isLast = i === segments.length - 1
const icon = iconMap[rawSegments[0]] || null
return (
<Fragment key={href}>
{i > 0 && <span>{">"}</span>}
{isLast ? (
<span className="inline-flex items-center gap-1 font-medium text-foreground">
{i === 0 && icon}
{decodeURIComponent(seg)}
</span>
) : (
<Link
href={href}
className="inline-flex items-center gap-1 hover:underline"
>
{i === 0 && icon}
{decodeURIComponent(seg)}
</Link>
)}
</Fragment>
)
})}
</div>
)
} }

View File

@ -1,17 +1,21 @@
import AnimateToggle from "./AnimateToggle"; import AnimateToggle from "./AnimateToggle";
import Breadcrumbs from "./Breadcrumbs";
import ModeToggle from "./ModeToggle"; import ModeToggle from "./ModeToggle";
import NSFWToggle from "./NSFWToggle"; import NSFWToggle from "./NSFWToggle";
import TopNav from "./TopNav"; import TopNav from "./TopNav";
export default function Header() { export default function Header() {
return ( return (
<div className="flex items-center justify-between"> <div className="flex flex-col gap-4">
<TopNav /> <div className="flex items-center justify-between">
<div className="flex gap-4"> <TopNav />
<AnimateToggle /> <div className="flex gap-4">
<NSFWToggle /> <AnimateToggle />
<ModeToggle /> <NSFWToggle />
<ModeToggle />
</div>
</div> </div>
<Breadcrumbs />
</div> </div>
); );
} }