diff --git a/components/artist-portfolio.tsx b/components/artist-portfolio.tsx index b06c345ee..8d08025e4 100644 --- a/components/artist-portfolio.tsx +++ b/components/artist-portfolio.tsx @@ -7,6 +7,10 @@ import { Badge } from "@/components/ui/badge" import Link from "next/link" import { ArrowLeft, Instagram, ExternalLink, Loader2, DollarSign } from "lucide-react" import { useArtist } from "@/hooks/use-artist-data" +import { useIsMobile } from "@/hooks/use-mobile" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { Carousel, CarouselContent, CarouselItem } from "@/components/ui/carousel" +import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area" interface ArtistPortfolioProps { artistId: string @@ -16,6 +20,8 @@ export function ArtistPortfolio({ artistId }: ArtistPortfolioProps) { const [selectedCategory, setSelectedCategory] = useState("All") const [selectedImage, setSelectedImage] = useState(null) const [scrollY, setScrollY] = useState(0) + const [mobileView, setMobileView] = useState<"grid" | "carousel">("grid") + const isMobile = useIsMobile() // Fetch artist data from API const { data: artist, isLoading, error } = useArtist(artistId) @@ -25,10 +31,12 @@ export function ArtistPortfolio({ artistId }: ArtistPortfolioProps) { const closeButtonRef = useRef(null) useEffect(() => { + // Enable parallax only on desktop to avoid jank on mobile + if (isMobile) return const handleScroll = () => setScrollY(window.scrollY) window.addEventListener("scroll", handleScroll) return () => window.removeEventListener("scroll", handleScroll) - }, []) + }, [isMobile]) // Derived lists (safe when `artist` is undefined during initial renders) const portfolioImages = artist?.portfolioImages || [] @@ -135,22 +143,10 @@ export function ArtistPortfolio({ artistId }: ArtistPortfolioProps) { return (
- {/* Back Button */} -
- -
+ {/* Removed Back to Artists button per request */} - {/* Hero Section with Split Screen */} -
+ {/* Hero Section with Split Screen (Desktop only) */} +
{/* Left Side - Artist Image */}
@@ -242,8 +238,49 @@ export function ArtistPortfolio({ artistId }: ArtistPortfolioProps) {
- {/* Portfolio Section with Split Screen Layout */} -
+ {/* Hero Section - Mobile stacked */} +
+
+ {artist.name} +
+
+
+
+ + {artist.isActive ? "Available" : "Unavailable"} + + {artist.hourlyRate && ( +
+ + Starting at ${artist.hourlyRate}/hr +
+ )} +
+

{artist.name}

+

{artist.specialties.join(", ")}

+

{artist.bio}

+
+ + +
+
+
+ + {/* Portfolio Section with Split Screen Layout (Desktop only) */} +
{/* Left Side - Portfolio Grid */}
@@ -358,6 +395,124 @@ export function ArtistPortfolio({ artistId }: ArtistPortfolioProps) {
+ {/* Mobile Portfolio: Tabs + Filters */} +
+
+ {/* Category Filter - horizontal pills */} + {categories.length > 1 && ( +
+ +
+ {categories.map((category) => { + const count = category === "All" + ? portfolioImages.length + : portfolioImages.filter((img) => img.tags.includes(category)).length + const isActive = selectedCategory === category + return ( + + ) + })} +
+ +
+
+ )} +
+ + {/* Tabs: Grid | Carousel */} +
+ setMobileView(v as any)} className="w-full"> + + Grid + Carousel + + + + {filteredPortfolio.length === 0 ? ( +
+

No portfolio images available

+
+ ) : ( +
+ {filteredPortfolio.map((item) => ( +
{ + openImageFromElement(item.id, (e.currentTarget as HTMLElement) || null) + }} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault() + openImageFromElement(item.id, e.currentTarget as HTMLElement) + } + }} + > +
+ {item.caption +
+
+ ))} +
+ )} +
+ + + {filteredPortfolio.length === 0 ? ( +
+

No portfolio images available

+
+ ) : ( +
+ + + {filteredPortfolio.map((item) => ( + +
+ {item.caption +
+
) + )} +
+
+
+ {filteredPortfolio.length} pieces +
+
+ )} +
+
+
+
+ {/* Contact Section */}