Changed a lot of things

This commit is contained in:
2025-07-27 12:26:00 +02:00
parent 4260a990e8
commit 4d6ef3c832
15 changed files with 671 additions and 192 deletions

View File

@ -4,11 +4,9 @@ import TopNav from "./TopNav";
export default function Header() {
return (
<div className="flex items-center justify-between w-full">
<div className="flex items-center gap-2">
<div className="w-full">
<div className="flex items-center justify-between px-4 md:px-8 py-2">
<TopNav />
</div>
<div>
<ModeToggle />
</div>
</div>

View File

@ -9,8 +9,9 @@ import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "../u
const links = [
{ href: "/", label: "Home" },
{ href: "/portfolio", label: "Art Portfolio" },
{ href: "/miniatures", label: "Miniatures" },
{ href: "/portfolio/art", label: "Artworks" },
{ href: "/portfolio/artfight", label: "Artfight" },
{ href: "/portfolio/minis", label: "Miniatures" },
{ href: "/commissions", label: "Commissions" },
{ href: "/ych", label: "YCH / Custom offers" },
{ href: "/tos", label: "Terms of Service" },

View File

@ -54,7 +54,7 @@ export function ImageCard(props: ImageCardProps) {
? `/api/image/thumbnail/${props.image.fileKey}.webp`
: props.image.url;
console.log(props.image);
// console.log(props.image);
return (
<Link href={`/portfolio/${props.image.id}`}>

View File

@ -0,0 +1,192 @@
"use client";
import { getPortfolioFilters } from "@/actions/portfolio/getPortfolioFilters";
import { Button } from "@/components/ui/button";
import clsx from "clsx";
import { CalendarIcon, ImagesIcon } from "lucide-react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
interface Album {
id: string;
name: string;
}
export default function PortfolioSubNav({
onFilterSelect,
}: {
onFilterSelect?: (value: string) => void;
}) {
const pathname = usePathname();
const router = useRouter();
const searchParams = useSearchParams();
const [mode, setMode] = useState<"year" | "album">("year");
const [selectedYear, setSelectedYear] = useState<string | null>(null);
const [selectedAlbum, setSelectedAlbum] = useState<string | null>(null);
const [years, setYears] = useState<string[]>([]);
const [albums, setAlbums] = useState<Album[]>([]);
// useEffect(() => {
// const year = searchParams.get("year");
// const album = searchParams.get("album");
// if (year) {
// setMode("year");
// setSelectedYear(year);
// } else if (album) {
// setMode("album");
// setSelectedAlbum(album);
// }
// }, [searchParams]);
useEffect(() => {
const fetchFilters = async () => {
const { years, albums } = await getPortfolioFilters();
setYears(years);
setAlbums(albums);
const urlYear = searchParams.get("year");
const urlAlbum = searchParams.get("album");
if (urlYear) {
setMode("year");
setSelectedYear(urlYear);
onFilterSelect?.(urlYear);
} else if (urlAlbum) {
setMode("album");
setSelectedAlbum(urlAlbum);
onFilterSelect?.(urlAlbum);
} else if (years.length > 0) {
const defaultYear = years[0];
setMode("year");
setSelectedYear(defaultYear);
const params = new URLSearchParams(searchParams.toString());
params.set("year", defaultYear);
router.replace(`${pathname}?${params.toString()}`, { scroll: false });
onFilterSelect?.(defaultYear);
}
};
fetchFilters();
}, [onFilterSelect, pathname, router, searchParams]);
const handleSelect = (value: string) => {
const params = new URLSearchParams(searchParams.toString());
if (mode === "year") {
setSelectedYear(value);
setSelectedAlbum(null);
params.set("year", value);
params.delete("album");
} else {
setSelectedAlbum(value);
setSelectedYear(null);
params.set("album", value);
params.delete("year");
}
router.push(`${pathname}?${params.toString()}`, { scroll: false });
onFilterSelect?.(value);
};
const activeList =
mode === "year"
? years.map((y) => ({ id: y, name: y }))
: albums.map((a) => ({ id: a.id, name: a.name }));
const selected = mode === "year" ? selectedYear : selectedAlbum;
return (
<div className="w-full">
<div className="flex items-center gap-4 px-4 md:px-8 py-2 overflow-x-auto">
{/* Toggle icons */}
<div className="flex items-center gap-1 shrink-0">
<ModeButton
icon={<CalendarIcon className="w-4 h-4" />}
isActive={mode === "year"}
onClick={() => setMode("year")}
label="Filter by year"
/>
<ModeButton
icon={<ImagesIcon className="w-4 h-4" />}
isActive={mode === "album"}
onClick={() => setMode("album")}
label="Filter by album"
/>
</div>
{/* Divider */}
<div className="h-5 w-px bg-border" />
{/* Filter buttons */}
<div className="flex items-center gap-1 flex-wrap">
{activeList.map((item) => (
<FilterButton
key={item.id}
label={item.name}
isActive={selected === item.id}
onClick={() => handleSelect(item.id)}
/>
))}
</div>
</div>
</div>
);
}
function ModeButton({
icon,
isActive,
onClick,
label,
}: {
icon: React.ReactNode;
isActive: boolean;
onClick: () => void;
label: string;
}) {
return (
<Button
variant="ghost"
size="icon"
onClick={onClick}
aria-label={label}
className={clsx(
"transition-colors",
isActive ? "bg-secondary text-secondary-foreground" : "hover:bg-muted"
)}
>
{icon}
</Button>
);
}
function FilterButton({
label,
isActive,
onClick,
}: {
label: string;
isActive: boolean;
onClick: () => void;
}) {
return (
<Button
variant="ghost"
size="sm"
onClick={onClick}
className={clsx(
"text-sm px-3 py-1 transition-colors",
isActive
? "bg-secondary text-secondary-foreground"
: "hover:bg-muted text-muted-foreground"
)}
>
{label}
</Button>
);
}