From 51ff6c1adeda8d15176ef4a0e98e96dffa385e1e Mon Sep 17 00:00:00 2001 From: Citali Date: Thu, 3 Jul 2025 21:44:02 +0200 Subject: [PATCH] Implemented breadcrumbs --- src/actions/breadcrumbs.ts | 130 +++++++++++++++++++++ src/components/global/Breadcrumbs.tsx | 102 ++++++++-------- src/components/global/Footer.tsx | 4 +- src/components/global/Header.tsx | 4 +- src/components/global/TopNav.tsx | 4 +- src/components/images/ImageMetadataBox.tsx | 4 +- 6 files changed, 187 insertions(+), 61 deletions(-) create mode 100644 src/actions/breadcrumbs.ts diff --git a/src/actions/breadcrumbs.ts b/src/actions/breadcrumbs.ts new file mode 100644 index 0000000..d35f0cf --- /dev/null +++ b/src/actions/breadcrumbs.ts @@ -0,0 +1,130 @@ +"use server" + +import prisma from "@/lib/prisma"; + +export async function getBreadcrumbLabels(path: string) { + const segments = path.split("/").filter(Boolean) + + const breadcrumbs: { label: string; href: string; icon: string }[] = [ + { label: "Home", href: "/", icon: "home" } + ] + + let base = "" + let i = 0 + + while (i < segments.length) { + const segment = segments[i] + + switch (segment) { + case "galleries": { + const gallerySlug = segments[i + 1] + const gallery = await prisma.gallery.findUnique({ where: { slug: gallerySlug } }) + + if (gallery) { + base += `/galleries/${gallerySlug}` + breadcrumbs.push({ + label: gallery.name, + href: base, + icon: "gallery" + }) + + // Check if there's an album + const albumSlug = segments[i + 2] + if (albumSlug) { + const album = await prisma.album.findFirst({ + where: { slug: albumSlug, galleryId: gallery.id } + }) + if (album) { + base += `/${albumSlug}` + breadcrumbs.push({ + label: album.name, + href: base, + icon: "album" + }) + + // Check for image ID + const imageId = segments[i + 3] + if (imageId) { + const image = await prisma.image.findUnique({ + where: { id: imageId } + }) + if (image) { + base += `/${imageId}` + breadcrumbs.push({ + label: image.imageName, + href: base, + icon: "image" + }) + } + } + } + } + } + i += 4 + break + } + + case "artists": { + const slug = segments[i + 1] + const artist = await prisma.artist.findUnique({ where: { slug } }) + if (artist) { + base += `/artists/${slug}` + breadcrumbs.push({ + label: artist.displayName, + href: base, + icon: "artist" + }) + } + i += 2 + break + } + + case "categories": { + const id = segments[i + 1] + const category = await prisma.category.findUnique({ where: { id } }) + if (category) { + base += `/categories/${id}` + breadcrumbs.push({ + label: category.name, + href: base, + icon: "category" + }) + } + i += 2 + break + } + + case "tags": { + const id = segments[i + 1] + const tag = await prisma.tag.findUnique({ where: { id } }) + if (tag) { + base += `/tags/${id}` + breadcrumbs.push({ + label: tag.name, + href: base, + icon: "tag" + }) + } + i += 2 + break + } + + case "about": { + base += `/about` + breadcrumbs.push({ + label: "About", + href: base, + icon: "about" + }) + i++ + break + } + + default: + i++ + break + } + } + + return breadcrumbs +} diff --git a/src/components/global/Breadcrumbs.tsx b/src/components/global/Breadcrumbs.tsx index 1b02ef5..472bc6b 100644 --- a/src/components/global/Breadcrumbs.tsx +++ b/src/components/global/Breadcrumbs.tsx @@ -1,75 +1,69 @@ "use client" -import { - FolderIcon, - FolderOpenIcon, - HomeIcon, - ImageIcon, - InfoIcon, - LayersIcon, - TagIcon, - UserIcon, -} from "lucide-react" +import { getBreadcrumbLabels } from "@/actions/breadcrumbs" +import { cn } from "@/lib/utils" +import { GalleryHorizontalEndIcon, HomeIcon, ImageIcon, ImagesIcon, InfoIcon, LayersIcon, TagIcon, UserIcon } from "lucide-react" import Link from "next/link" import { usePathname } from "next/navigation" -import { Fragment, JSX } from "react" +import { JSX, useEffect, useState } from "react" const iconMap: Record = { - "about": , - "artists": , - "categories": , - "tags": , - "gallery": , - "album": , - "image": , + home: , + gallery: , + album: , + category: , + image: , + tag: , + artist: , + about: , +} + +type Crumb = { + label: string + href: string + icon: keyof typeof iconMap } export default function Breadcrumbs() { const pathname = usePathname() - const rawSegments = pathname.split("/").filter(Boolean) + const [labels, setLabels] = useState([]) - // If path is just "/", return nothing - if (rawSegments.length === 0) return null + useEffect(() => { + async function fetchLabels() { + const data = await getBreadcrumbLabels(pathname) + setLabels(data) + } + fetchLabels() + }, [pathname]) - // Special handling: remove "galleries" from breadcrumb trail - const segments = rawSegments.filter((seg, index) => - !(seg === "galleries" && index === 0) - ) + if (!labels.length) return null return ( -
- - - Home - +
+ ) } diff --git a/src/components/global/Footer.tsx b/src/components/global/Footer.tsx index 4abff76..a052351 100644 --- a/src/components/global/Footer.tsx +++ b/src/components/global/Footer.tsx @@ -1,5 +1,7 @@ export default function Footer() { return ( -
Footer
+
+ © 2025 Fellies Art +
); } \ No newline at end of file diff --git a/src/components/global/Header.tsx b/src/components/global/Header.tsx index 2471ef0..91395db 100644 --- a/src/components/global/Header.tsx +++ b/src/components/global/Header.tsx @@ -8,14 +8,14 @@ export default function Header() { return (
- +
+
-
); } \ No newline at end of file diff --git a/src/components/global/TopNav.tsx b/src/components/global/TopNav.tsx index bf33502..5d866a4 100644 --- a/src/components/global/TopNav.tsx +++ b/src/components/global/TopNav.tsx @@ -7,11 +7,11 @@ export default function TopNav() { return ( - + {/* Home - + */} About diff --git a/src/components/images/ImageMetadataBox.tsx b/src/components/images/ImageMetadataBox.tsx index cfd578e..9ae88fb 100644 --- a/src/components/images/ImageMetadataBox.tsx +++ b/src/components/images/ImageMetadataBox.tsx @@ -1,7 +1,7 @@ "use client" import { Album, Category, Gallery, Tag } from "@/generated/prisma" -import { CalendarDaysIcon, FolderIcon, LayersIcon, QuoteIcon, TagIcon } from "lucide-react" +import { CalendarDaysIcon, ImagesIcon, LayersIcon, QuoteIcon, TagIcon } from "lucide-react" import Link from "next/link" type Props = { @@ -62,7 +62,7 @@ export default function ImageMetadataBox({ {album && (
- + {album.name}