Untitled
unknown
plain_text
2 months ago
14 kB
3
Indexable
"use client" import React, { useState, useRef } from "react" import { motion, useScroll, useMotionValueEvent } from "framer-motion" import { Slider } from "@/components/ui/slider" import { Button } from "@/components/ui/button" import { Image, Moon, Sun, List, X, ChevronUp, ZoomIn, ZoomOut, UserRound, Mail, Instagram, Filter, Heart, Check } from "lucide-react" import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover" interface ToolbarProps { gridSize: number; setGridSize: (value: number) => void; sections: { title: string; description?: string; }[]; inView?: boolean; clientConfig: any; favorites: {[key: string]: boolean}; showFavoritesOnly: boolean; setShowFavoritesOnly: (value: boolean) => void; } export const ScrollToolbar = ({ gridSize, setGridSize, sections, inView = false, clientConfig, favorites, showFavoritesOnly, setShowFavoritesOnly }: ToolbarProps) => { const [variant, setVariant] = useState("hidden") const { scrollY } = useScroll() const scrollToSection = (sectionTitle: string) => { const element = document.getElementById(`section-${sectionTitle}`) if (element) { element.scrollIntoView({ behavior: "smooth" }) } } const scrollToTop = () => { window.scrollTo({ top: 0, behavior: "smooth" }) } useMotionValueEvent(scrollY, "change", (latest) => { if (inView) return setVariant("absolute") if (latest > 300) setVariant("visible") else setVariant("hidden") }) // Calculate the number of favorited images const favoriteCount = Object.values(favorites).filter(Boolean).length; return ( <motion.div variants={{ hidden: { position: 'fixed', bottom: "-100px", left: 0, right: 0 }, visible: { position: 'fixed', bottom: '20px', left: 0, right: 0 }, absolute: { position: 'absolute', bottom: '20px', left: 0, right: 0 } }} animate={variant} transition={{ duration: 0.3, ease: "easeInOut" }} className="z-40 flex w-full justify-center pointer-events-none" > <div className="rounded-full bg-zinc-900/90 backdrop-blur-sm flex px-4 py-4 border-zinc-800 border shadow-lg pointer-events-auto"> {/* Image Size Adjustment */} <Popover> <PopoverTrigger asChild> <div className="px-3 md:px-4 flex items-center justify-center cursor-pointer hover:bg-zinc-800 rounded-full transition-colors"> <Image className="h-5 w-5 text-zinc-300" /> </div> </PopoverTrigger> <PopoverContent className="w-72 p-4 bg-zinc-900 border-zinc-800 text-zinc-300" sideOffset={16} side="top" align="center" > <div className="space-y-4"> <h4 className="font-medium text-sm">Fotogröße anpassen</h4> <div className="flex items-center gap-3"> <ZoomIn className="h-4 w-4 text-zinc-400" /> <Slider value={[gridSize]} min={1} max={6} step={1} onValueChange={(value) => setGridSize(value[0])} className="flex-1" /> <ZoomOut className="h-4 w-4 text-zinc-400" /> </div> </div> </PopoverContent> </Popover> <div className="h-6 w-px bg-zinc-700 mx-2" /> {/* Filter Options */} <Popover> <PopoverTrigger asChild> <div className={` px-3 md:px-4 flex items-center justify-center cursor-pointer ${showFavoritesOnly ? 'bg-pink-500/20 text-pink-400' : 'hover:bg-zinc-800 text-zinc-300'} rounded-full transition-colors relative `}> <Filter className="h-5 w-5" /> {favoriteCount > 0 && showFavoritesOnly && ( <span className="absolute top-0 right-1 flex h-3 w-3"> <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-pink-400 opacity-40"></span> <span className="relative inline-flex rounded-full h-3 w-3 bg-pink-500"></span> </span> )} </div> </PopoverTrigger> <PopoverContent className="w-72 p-4 bg-zinc-900 border-zinc-800 text-zinc-300" sideOffset={16} side="top" align="center" > <div className="space-y-4"> <h4 className="font-medium text-sm">Filter Optionen</h4> <div className="space-y-2"> <div className="flex items-center gap-3 p-2 rounded-md hover:bg-zinc-800 cursor-pointer transition-colors" onClick={() => setShowFavoritesOnly(!showFavoritesOnly)} > <div className={`p-1.5 rounded-full ${showFavoritesOnly ? 'bg-pink-500/20' : 'bg-zinc-800'}`}> <Heart className={`h-4 w-4 ${showFavoritesOnly ? 'text-pink-500' : 'text-zinc-400'}`} fill={showFavoritesOnly ? 'currentColor' : 'none'} /> </div> <span className="text-sm flex-1">Nur Favoriten anzeigen</span> <div className={`w-4 h-4 rounded-full border ${showFavoritesOnly ? 'bg-pink-500 border-pink-600' : 'border-zinc-600'} flex items-center justify-center`}> {showFavoritesOnly && <Check className="h-3 w-3 text-white" />} </div> </div> {favoriteCount > 0 && ( <div className="flex items-center gap-3 p-2 text-xs text-zinc-400 italic"> {favoriteCount} {favoriteCount === 1 ? 'Favorit' : 'Favoriten'} ausgewählt </div> )} {favoriteCount === 0 && ( <div className="flex items-center gap-3 p-2 text-xs text-zinc-400 italic"> Keine Favoriten ausgewählt </div> )} </div> </div> </PopoverContent> </Popover> <div className="h-6 w-px bg-zinc-700 mx-2" /> {/* Dark/Light Mode Toggle */} <div className="px-3 md:px-4 flex items-center justify-center cursor-pointer hover:bg-zinc-800 rounded-full transition-colors"> <Sun className="h-5 w-5 text-zinc-300" /> </div> <div className="h-6 w-px bg-zinc-700 mx-2" /> {/* Table of Contents */} <Popover> <PopoverTrigger asChild> <div className="px-3 md:px-4 flex items-center justify-center cursor-pointer hover:bg-zinc-800 rounded-full transition-colors"> <List className="h-5 w-5 text-zinc-300" /> </div> </PopoverTrigger> <PopoverContent className="w-72 p-0 bg-zinc-900 border-zinc-800 text-zinc-300 max-h-96 overflow-y-auto" sideOffset={16} side="top" align="center" > <div className="p-3 border-b border-zinc-800"> <h4 className="font-medium">Inhaltsverzeichnis</h4> </div> <div className="p-2"> {sections.map((section, index) => ( <div key={index} onClick={() => scrollToSection(section.title)} className="p-2 hover:bg-zinc-800 rounded cursor-pointer transition-colors" > {section.title} </div> ))} </div> </PopoverContent> </Popover> <div className="h-6 w-px bg-zinc-700 mx-2" /> {/* Personal Info */} <Popover> <PopoverTrigger asChild> <div className="px-3 md:px-4 flex items-center justify-center cursor-pointer hover:bg-zinc-800 rounded-full transition-colors"> <UserRound className="h-5 w-5 text-zinc-300" /> </div> </PopoverTrigger> <PopoverContent className="w-80 p-0 bg-zinc-900/95 border-zinc-800 text-zinc-300 shadow-xl" sideOffset={16} side="top" align="center" > <div className="overflow-hidden rounded-md"> {/* Card header with background image */} <div className="relative p-6"> {/* Background image - dark overlay applied */} <div className="absolute inset-0 z-0"> <div className="absolute inset-0 bg-gradient-to-r from-zinc-900/80 to-zinc-900/10"></div> <img src="/background-image.jpg" alt="Background" className="w-full h-full object-cover object-center opacity-90" /> </div> {/* Circular avatar image */} <div className="w-16 h-16 rounded-full bg-zinc-800 flex items-center justify-center mb-3 ring-2 ring-white/20 shadow-lg overflow-hidden relative z-10"> <img src="/avatar.jpg" alt="Avatar" className="w-full h-full object-cover object-center" onError={(e) => { // Fallback if image fails to load e.currentTarget.style.display = 'none'; e.currentTarget.parentElement.innerHTML = '<span class="text-white text-xl font-bold">P</span>'; }} /> </div> <h3 className="font-bold text-white text-xl relative z-10"> {clientConfig?.photographerName || "Fotograf"} </h3> <div className="flex items-center gap-2 mt-1 relative z-10"> <div className="h-1 w-6 bg-indigo-400 rounded-full"></div> <p className="text-white/90 text-sm font-medium"> {clientConfig?.photographerCredit || "Professionelle Fotografie"} </p> </div> </div> {/* Card body */} <div className="p-4 space-y-4 bg-gradient-to-b from-zinc-900 to-zinc-950"> {/* Contact details with null checks */} <div className="space-y-3 pt-1"> <div className="flex items-center gap-3 text-zinc-300 p-2 rounded-md hover:bg-zinc-800/50 transition-colors"> <div className="bg-indigo-800/30 p-2 rounded-md"> <Mail className="h-4 w-4 text-indigo-300" /> </div> <a href={`mailto:${clientConfig?.photographerEmail || "info@example.com"}`} className="text-sm hover:text-indigo-300 transition-colors flex-1" > {clientConfig?.photographerEmail || "info@example.com"} </a> </div> <div className="flex items-center gap-3 text-zinc-300 p-2 rounded-md hover:bg-zinc-800/50 transition-colors"> <div className="bg-indigo-800/30 p-2 rounded-md"> <Instagram className="h-4 w-4 text-indigo-300" /> </div> <a href={clientConfig?.photographerInstagram || "#"} target="_blank" rel="noopener noreferrer" className="text-sm hover:text-indigo-300 transition-colors flex-1" > Instagram </a> </div> </div> {/* Decorated separator */} <div className="relative flex items-center py-2"> <div className="flex-grow border-t border-zinc-800"></div> <span className="flex-shrink mx-3 text-zinc-500 text-xs">FOTOGRAF</span> <div className="flex-grow border-t border-zinc-800"></div> </div> {/* Brief description */} <p className="text-sm text-zinc-400 italic"> "Hallo, mein Name ist Justin Faltus, ich bin ein Perfektionistischer Fotograf, ansässig in Heidenheim, Baden-Württemberg. Meine Liebe zur Fotografie wurde durch zauberhafte Augenblicke und Andenken geprägt. Ich lege stets Professionalität und Perfektionismus in meine Arbeit, mit dem Ziel, Ihnen atemberaubende Bilder zu liefern, die für immer in Erinnerung bleiben." </p> {/* Contact button with gradient */} <Button className="w-full mt-2 bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-700 hover:to-purple-700 border-0 text-indigo-100" onClick={() => window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' })} > Kontaktieren </Button> </div> </div> </PopoverContent> </Popover> <div className="h-6 w-px bg-zinc-700 mx-2" /> {/* Scroll to Top */} <div className="px-3 md:px-4 flex items-center justify-center cursor-pointer hover:bg-zinc-800 rounded-full transition-colors" onClick={scrollToTop} > <ChevronUp className="h-5 w-5 text-zinc-300" /> </div> </div> </motion.div> ) } export default ScrollToolbar
Editor is loading...
Leave a Comment