Changed a lot of things
This commit is contained in:
@ -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>
|
||||
|
||||
@ -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" },
|
||||
|
||||
@ -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}`}>
|
||||
|
||||
192
src/components/portfolio/PortfolioSubNav.tsx
Normal file
192
src/components/portfolio/PortfolioSubNav.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user