Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 039d4d443f | |||
| 0982256263 | |||
| e44af68f84 | |||
| 5e177dc51f | |||
| da343a2ad0 | |||
| d67b3030f1 | |||
| 2256fe81f7 | |||
| e9b57f9f68 | |||
| ff4f97d7b2 |
206
src/app/page.tsx
206
src/app/page.tsx
@@ -1,25 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen';
|
||||
import HeroBillboardRotatedCarousel from '@/components/sections/hero/HeroBillboardRotatedCarousel';
|
||||
import SocialProofOne from '@/components/sections/socialProof/SocialProofOne';
|
||||
import FeatureBorderGlow from '@/components/sections/feature/featureBorderGlow/FeatureBorderGlow';
|
||||
import ProductCardOne from '@/components/sections/product/ProductCardOne';
|
||||
import InlineImageSplitTextAbout from '@/components/sections/about/InlineImageSplitTextAbout';
|
||||
import TestimonialCardFifteen from '@/components/sections/testimonial/TestimonialCardFifteen';
|
||||
import BlogCardOne from '@/components/sections/blog/BlogCardOne';
|
||||
import MetricCardTwo from '@/components/sections/metrics/MetricCardTwo';
|
||||
import ContactSplitForm from '@/components/sections/contact/ContactSplitForm';
|
||||
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
|
||||
import { Zap, Wind, Flame, Heart } from 'lucide-react';
|
||||
import NavbarStyleFullscreen from "@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen";
|
||||
import HeroBillboardRotatedCarousel from "@/components/sections/hero/HeroBillboardRotatedCarousel";
|
||||
import SocialProofOne from "@/components/sections/socialProof/SocialProofOne";
|
||||
import FeatureBorderGlow from "@/components/sections/feature/featureBorderGlow/FeatureBorderGlow";
|
||||
import ProductCardOne from "@/components/sections/product/ProductCardOne";
|
||||
import InlineImageSplitTextAbout from "@/components/sections/about/InlineImageSplitTextAbout";
|
||||
import TestimonialCardFifteen from "@/components/sections/testimonial/TestimonialCardFifteen";
|
||||
import BlogCardOne from "@/components/sections/blog/BlogCardOne";
|
||||
import MetricCardTwo from "@/components/sections/metrics/MetricCardTwo";
|
||||
import ContactSplitForm from "@/components/sections/contact/ContactSplitForm";
|
||||
import FooterBaseReveal from "@/components/sections/footer/FooterBaseReveal";
|
||||
import { Star, Zap, Shield, TrendingUp, Users, Globe, CheckCircle, Sparkles } from "lucide-react";
|
||||
|
||||
export default function Home() {
|
||||
const navItems = [
|
||||
{ name: "Home", id: "/" },
|
||||
{ name: "Menu", id: "#pizzas" },
|
||||
{ name: "Story", id: "#story" },
|
||||
{ name: "Visit", id: "#visit" }
|
||||
{ name: "About", id: "story" },
|
||||
{ name: "Experience", id: "experience" },
|
||||
{ name: "Contact", id: "cta" },
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -38,169 +38,183 @@ export default function Home() {
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarStyleFullscreen
|
||||
navItems={navItems}
|
||||
brandName="Vito's"
|
||||
bottomLeftText="Downtown Székesfehérvár"
|
||||
bottomRightText="hello@vitosnapoleotana.hu"
|
||||
logoText="Pizzeria"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroBillboardRotatedCarousel
|
||||
title="Vito's Napoletana Pizzéria"
|
||||
description="Authentic Neapolitan pizza. Crafted with fire, passion, and Italian tradition."
|
||||
background={{ variant: "plain" }}
|
||||
tag="⭐ Rated 4.7 by locals"
|
||||
title="Authentic Italian Pizza Experience"
|
||||
description="Savor the taste of Italy with our handcrafted pizzas made from the finest ingredients"
|
||||
background={{ variant: "circleGradient" }}
|
||||
tag="Premium Quality"
|
||||
tagAnimation="slide-up"
|
||||
buttonAnimation="slide-up"
|
||||
buttons={[
|
||||
{ text: "View Menu", href: "#pizzas" },
|
||||
{ text: "Visit Us Tonight", href: "#visit" }
|
||||
{ text: "Order Now", href: "pizzas" },
|
||||
{ text: "Menu", href: "experience" }
|
||||
]}
|
||||
carouselItems={[
|
||||
{ id: "carousel-1", videoSrc: "http://img.b2bpic.net/free-photo/high-angle-chef-baking-pizza-wood-fired-oven_52683-106696.jpg" },
|
||||
{ id: "carousel-2", imageSrc: "http://img.b2bpic.net/free-photo/neapolitan-pizza-with-ham-cheese-arugula-basil-tomatoes-sprinkled-with-cheese-wooden-board-tablecloth-cell_78826-2352.jpg", imageAlt: "fresh neapolitan pizza slice detail closeup" },
|
||||
{ id: "carousel-3", imageSrc: "http://img.b2bpic.net/free-photo/half-view-margarita-pizza-garnished-with-basil_140725-8731.jpg", imageAlt: "margherita pizza san marzano tomato fresh" },
|
||||
{ id: "carousel-4", imageSrc: "http://img.b2bpic.net/free-photo/pizza-with-tomato-slices-garlic-lemon-chili-pepper-corn-mint-leaves-pizza-board-gray-wooden-background-high-angle-view_176474-4612.jpg", imageAlt: "spicy calabrese pizza salami chili" },
|
||||
{ id: "carousel-5", imageSrc: "http://img.b2bpic.net/free-photo/hawaiian-pizza_74190-7223.jpg", imageAlt: "prosciutto arugula pizza fresh pesto" },
|
||||
{ id: "carousel-6", imageSrc: "http://img.b2bpic.net/free-photo/front-view-delicious-mushroom-pizza-with-tomatoes-olives-mushrooms-with-ropes-grey-surface_140725-20486.jpg", imageAlt: "vegetarian pizza grilled vegetables pesto" }
|
||||
{ id: "1", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Margherita Pizza" },
|
||||
{ id: "2", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Pepperoni Pizza" },
|
||||
{ id: "3", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Vegetarian Pizza" },
|
||||
{ id: "4", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Quattro Formaggi" },
|
||||
{ id: "5", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Prosciutto Pizza" },
|
||||
{ id: "6", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Truffle Pizza" }
|
||||
]}
|
||||
autoPlay={true}
|
||||
autoPlayInterval={5000}
|
||||
ariaLabel="Vito's Napoletana Pizzéria hero section with pizza showcase"
|
||||
autoPlayInterval={4000}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="social-proof" data-section="social-proof">
|
||||
<SocialProofOne
|
||||
title="Loved by Locals in Székesfehérvár"
|
||||
description="Authentic Neapolitan dough, fast friendly service, affordable artisan pizza"
|
||||
names={["Milano Pizzeria", "Naples Kitchen", "Roma Ristorante", "Venice Dining", "Florence Eats"]}
|
||||
title="Trusted by Premium Restaurants"
|
||||
description="Join the finest establishments serving authentic Italian cuisine"
|
||||
textboxLayout="default"
|
||||
useInvertedBackground={false}
|
||||
names={["⭐ Authentic Neapolitan Dough", "⭐ Fast Friendly Service", "⭐ Affordable Artisan Pizza", "⭐ Fresh Pizza Under 10 Minutes", "⭐ Downtown Location", "⭐ Community Focused"]}
|
||||
speed={50}
|
||||
showCard={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="experience" data-section="experience">
|
||||
<FeatureBorderGlow
|
||||
title="Real Neapolitan Pizza"
|
||||
description="At Vito's, pizza is not fast food. It's craft. Our dough is slow-fermented, stretched by hand, and baked in a blazing hot oven to create the signature light, airy Neapolitan crust."
|
||||
title="The Pizza Experience"
|
||||
description="Discover what makes our pizzas extraordinary"
|
||||
textboxLayout="default"
|
||||
animationType="slide-up"
|
||||
useInvertedBackground={false}
|
||||
animationType="slide-up"
|
||||
features={[
|
||||
{ icon: Zap, title: "Soft Center", description: "Perfectly fermented dough creates a tender, pillowy crumb" },
|
||||
{ icon: Wind, title: "Airy Crust", description: "Hand-stretched and wood-fired for authentic texture" },
|
||||
{ icon: Flame, title: "Bold Toppings", description: "Fresh San Marzano tomatoes and premium Italian ingredients" },
|
||||
{ icon: Heart, title: "Unforgettable Flavor", description: "Just like in Naples—authentic tradition in every slice" }
|
||||
{ icon: Star, title: "Premium Ingredients", description: "Imported directly from Italy for authentic flavor" },
|
||||
{ icon: Zap, title: "Wood-Fired Oven", description: "Traditional ovens heated to 900 degrees" },
|
||||
{ icon: Shield, title: "Quality Assured", description: "Every pizza meets our strict quality standards" },
|
||||
{ icon: TrendingUp, title: "Award Winning", description: "Recognized by international pizza competitions" }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="pizzas" data-section="pizzas">
|
||||
<ProductCardOne
|
||||
title="Signature Pizzas"
|
||||
description="Each pizza is carefully crafted with the finest ingredients and traditional Neapolitan techniques."
|
||||
title="Our Signature Pizzas"
|
||||
description="Hand-tossed pizzas with the finest toppings"
|
||||
textboxLayout="default"
|
||||
animationType="slide-up"
|
||||
useInvertedBackground={false}
|
||||
gridVariant="uniform-all-items-equal"
|
||||
gridVariant="three-columns-all-equal-width"
|
||||
animationType="slide-up"
|
||||
products={[
|
||||
{ id: "margherita", name: "Margherita Classica", price: "2,000 Ft", imageSrc: "http://img.b2bpic.net/free-photo/half-view-margarita-pizza-garnished-with-basil_140725-8731.jpg", imageAlt: "Margherita Classica pizza with tomato, mozzarella, and basil" },
|
||||
{ id: "calabrese", name: "Calabrese", price: "2,500 Ft", imageSrc: "http://img.b2bpic.net/free-photo/pizza-with-tomato-slices-garlic-lemon-chili-pepper-corn-mint-leaves-pizza-board-gray-wooden-background-high-angle-view_176474-4612.jpg", imageAlt: "Calabrese pizza with spicy salami and chili oil" },
|
||||
{ id: "vito-special", name: "Vito's Special", price: "3,000 Ft", imageSrc: "http://img.b2bpic.net/free-photo/hawaiian-pizza_74190-7223.jpg", imageAlt: "Vito's Special pizza with prosciutto, arugula, and parmesan" },
|
||||
{ id: "vegetarian", name: "Vegetarian Garden", price: "2,200 Ft", imageSrc: "http://img.b2bpic.net/free-photo/front-view-delicious-mushroom-pizza-with-tomatoes-olives-mushrooms-with-ropes-grey-surface_140725-20486.jpg", imageAlt: "Vegetarian Garden pizza with grilled vegetables and pesto" }
|
||||
{ id: "1", name: "Margherita", price: "$14.99", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Margherita Pizza" },
|
||||
{ id: "2", name: "Pepperoni", price: "$15.99", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Pepperoni Pizza" },
|
||||
{ id: "3", name: "Quattro Formaggi", price: "$16.99", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Quattro Formaggi Pizza" }
|
||||
]}
|
||||
buttons={[{ text: "See Full Menu", href: "#" }]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="story" data-section="story">
|
||||
<InlineImageSplitTextAbout
|
||||
heading={[{ type: "text", content: "Built With Passion" }]}
|
||||
heading={[
|
||||
{ type: "text", content: "Our Story: A Family Tradition Since 1995" },
|
||||
{ type: "image", src: "/placeholders/placeholder1.webp", alt: "Family pizzeria" }
|
||||
]}
|
||||
useInvertedBackground={false}
|
||||
buttons={[{ text: "Visit Us", href: "#visit" }]}
|
||||
buttons={[
|
||||
{ text: "Learn More", href: "experience" }
|
||||
]}
|
||||
buttonAnimation="slide-up"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="community" data-section="community">
|
||||
<TestimonialCardFifteen
|
||||
testimonial="The children loved the pizzas very much. 5 stars for humanity and the pizza tasted heavenly."
|
||||
testimonial="The best pizza I've ever had. Authentic Italian flavors combined with exceptional service. Highly recommend!"
|
||||
rating={5}
|
||||
author="Parent & Community Member"
|
||||
author="Marco Rossi"
|
||||
avatars={[
|
||||
{ src: "/placeholders/placeholder1.webp", alt: "Marco" }
|
||||
]}
|
||||
ratingAnimation="slide-up"
|
||||
avatarsAnimation="slide-up"
|
||||
useInvertedBackground={false}
|
||||
avatars={[
|
||||
{ src: "http://img.b2bpic.net/free-photo/blond-businessman-happy-expression_1194-3673.jpg", alt: "Vito's pizzeria owner" },
|
||||
{ src: "http://img.b2bpic.net/free-photo/side-view-couple-having-lunch_23-2150598339.jpg", alt: "Pizzeria interior" },
|
||||
{ src: "http://img.b2bpic.net/free-photo/neapolitan-pizza-with-ham-cheese-arugula-basil-tomatoes-sprinkled-with-cheese-wooden-board-tablecloth-cell_78826-2352.jpg", alt: "Authentic pizza" }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="atmosphere" data-section="atmosphere">
|
||||
<BlogCardOne
|
||||
title="Small Place. Big Flavor."
|
||||
description="Our pizzeria is cozy, lively, and full of energy. Perfect for quick lunch, relaxed dinner, or gathering with friends and family."
|
||||
textboxLayout="default"
|
||||
animationType="slide-up"
|
||||
useInvertedBackground={false}
|
||||
carouselMode="buttons"
|
||||
blogs={[
|
||||
{ id: "terrace", category: "Dining", title: "Outdoor Terrace", excerpt: "Enjoy pizza on our terrace in the city center with a relaxed, friendly atmosphere", imageSrc: "http://img.b2bpic.net/free-photo/new-year-background-with-champagne_23-2148002051.jpg", imageAlt: "Pizzeria outdoor terrace seating", authorName: "Vito's Team", authorAvatar: "http://img.b2bpic.net/free-photo/blond-businessman-happy-expression_1194-3673.jpg", date: "Year-round" },
|
||||
{ id: "oven", category: "Craft", title: "The Heart of Vito's", excerpt: "Our wood-fired oven bakes authentic Neapolitan pizza at perfect temperatures", imageSrc: "http://img.b2bpic.net/free-photo/italian-chef-is-putting-gourmet-freshly-made-pizza-stone-oven_613910-14121.jpg", imageAlt: "Traditional wood-fired pizza oven", authorName: "Vito's Team", authorAvatar: "http://img.b2bpic.net/free-photo/blond-businessman-happy-expression_1194-3673.jpg", date: "Daily" },
|
||||
{ id: "quality", category: "Ingredients", title: "Premium Quality", excerpt: "Fresh ingredients and traditional techniques create unforgettable flavor in every bite", imageSrc: "http://img.b2bpic.net/free-photo/top-view-pizza-stand-with-tomatoes-olives-rolling-pin-flour-black-table_141793-13177.jpg", imageAlt: "Pizza detail with fresh ingredients", authorName: "Vito's Team", authorAvatar: "http://img.b2bpic.net/free-photo/blond-businessman-happy-expression_1194-3673.jpg", date: "Always" },
|
||||
{ id: "craft", category: "Process", title: "Handmade Excellence", excerpt: "Each pizza is stretched and prepared with care by our experienced pizza makers", imageSrc: "http://img.b2bpic.net/free-photo/medium-shot-chef-preparing-pizza_23-2150235778.jpg", imageAlt: "Pizza chef preparing dough", authorName: "Vito's Team", authorAvatar: "http://img.b2bpic.net/free-photo/blond-businessman-happy-expression_1194-3673.jpg", date: "Every Day" },
|
||||
{ id: "interior", category: "Ambiance", title: "Warm & Welcoming", excerpt: "A cozy interior designed for comfortable dining and memorable moments", imageSrc: "http://img.b2bpic.net/free-photo/side-view-couple-having-lunch_23-2150598339.jpg", imageAlt: "Pizzeria cozy interior with warm lighting", authorName: "Vito's Team", authorAvatar: "http://img.b2bpic.net/free-photo/blond-businessman-happy-expression_1194-3673.jpg", date: "Every Moment" }
|
||||
{ id: "1", category: "Food Culture", title: "The Art of Pizza Making", excerpt: "Learn the techniques that make Italian pizza special", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Pizza making", authorName: "Chef Antonio", authorAvatar: "/placeholders/placeholder1.webp", date: "Jan 15, 2025" },
|
||||
{ id: "2", category: "Dining Experience", title: "Pizza Pairing with Wine", excerpt: "Discover perfect wine pairings for every pizza", imageSrc: "/placeholders/placeholder1.webp", imageAlt: "Wine pairing", authorName: "Sommelier Luigi", authorAvatar: "/placeholders/placeholder1.webp", date: "Jan 10, 2025" }
|
||||
]}
|
||||
title="Pizza Stories"
|
||||
description="Explore the culture and traditions of Italian pizza"
|
||||
textboxLayout="default"
|
||||
useInvertedBackground={false}
|
||||
animationType="slide-up"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="reviews" data-section="reviews">
|
||||
<MetricCardTwo
|
||||
title="What Our Customers Say"
|
||||
description="Real reviews from locals who love Vito's authentic Neapolitan pizza"
|
||||
title="By The Numbers"
|
||||
description="Our commitment to excellence"
|
||||
textboxLayout="default"
|
||||
animationType="slide-up"
|
||||
useInvertedBackground={false}
|
||||
gridVariant="uniform-all-items-equal"
|
||||
animationType="slide-up"
|
||||
metrics={[
|
||||
{ id: "review-1", value: "⭐⭐⭐⭐⭐", description: "Super good Calabrian pizza. Very fast and responsive service. — Rafał" },
|
||||
{ id: "review-2", value: "⭐⭐⭐⭐⭐", description: "Very delicious pizza, prepared quickly and the staff was very nice. — Kata" },
|
||||
{ id: "review-3", value: "⭐⭐⭐⭐⭐", description: "Cozy little pizzeria with authentic Italian-style pizzas. — Péter" },
|
||||
{ id: "review-4", value: "⭐⭐⭐⭐⭐", description: "Best pizza in Székesfehérvár! Authentic taste and friendly service. — Local Favorite" }
|
||||
{ id: "1", value: "10K+", description: "Happy customers served annually" },
|
||||
{ id: "2", value: "30+", description: "Years of pizza-making excellence" }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="cta" data-section="cta">
|
||||
<ContactSplitForm
|
||||
title="Get Special Offers"
|
||||
description="Subscribe to our newsletter for exclusive deals and new pizza launches"
|
||||
inputs={[
|
||||
{ name: "email", type: "email", placeholder: "Your email", required: true },
|
||||
{ name: "name", type: "text", placeholder: "Your name", required: true }
|
||||
]}
|
||||
useInvertedBackground={false}
|
||||
mediaAnimation="slide-up"
|
||||
buttonText="Subscribe"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="visit" data-section="visit">
|
||||
<ContactSplitForm
|
||||
title="Visit Vito's"
|
||||
description="Downtown Székesfehérvár • Dine-in & Terrace Seating • Fast Service — Most Pizzas Ready in Under 10 Minutes. Parking available nearby."
|
||||
useInvertedBackground={false}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/young-delivery-woman-wearing-orange-polo-shirt-red-cap-medical-protective-mask-pointing-stack-pizza-boxes-other-hand-looking-confident-isolated-blue-background_141793-19892.jpg"
|
||||
imageAlt="Delicious pizza delivery"
|
||||
mediaAnimation="slide-up"
|
||||
mediaPosition="right"
|
||||
buttonText="Get Directions"
|
||||
title="Visit Us"
|
||||
description="Find our location and reserve a table for your next pizza night"
|
||||
inputs={[
|
||||
{ name: "name", type: "text", placeholder: "Your Name", required: true },
|
||||
{ name: "email", type: "email", placeholder: "Email", required: true }
|
||||
{ name: "date", type: "date", placeholder: "Date", required: true },
|
||||
{ name: "time", type: "time", placeholder: "Time", required: true }
|
||||
]}
|
||||
textarea={{ name: "message", placeholder: "Tell us about your visit or reservation request", rows: 4, required: false }}
|
||||
useInvertedBackground={false}
|
||||
mediaAnimation="slide-up"
|
||||
buttonText="Reserve Table"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterBaseReveal
|
||||
columns={[
|
||||
{ title: "Menu", items: [{ label: "View Full Menu", href: "#pizzas" }, { label: "Signature Pizzas", href: "#pizzas" }, { label: "Prices", href: "#pizzas" }] },
|
||||
{ title: "Experience", items: [{ label: "Our Story", href: "#story" }, { label: "Atmosphere", href: "#atmosphere" }, { label: "Reviews", href: "#reviews" }] },
|
||||
{ title: "Contact", items: [{ label: "Get Directions", href: "#visit" }, { label: "Call Now", href: "tel:+36123456789" }, { label: "Email Us", href: "mailto:hello@vitosnapoleotana.hu" }] }
|
||||
{
|
||||
title: "Quick Links", items: [
|
||||
{ label: "Home", href: "/" },
|
||||
{ label: "Menu", href: "#experience" },
|
||||
{ label: "About", href: "#story" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Contact", items: [
|
||||
{ label: "Email", href: "mailto:info@pizzeria.com" },
|
||||
{ label: "Phone", href: "tel:+1234567890" },
|
||||
{ label: "Address", href: "#" }
|
||||
]
|
||||
}
|
||||
]}
|
||||
copyrightText="© 2025 Vito's Napoletana Pizzéria | Downtown Székesfehérvár"
|
||||
copyrightText="© 2025 Pizzeria. All rights reserved."
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
127
src/components/floating/FloatingContactButtons.tsx
Normal file
127
src/components/floating/FloatingContactButtons.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { LucideIcon } from 'lucide-react';
|
||||
|
||||
interface FloatingContactButtonsProps {
|
||||
phoneNumber: string;
|
||||
mapsUrl: string;
|
||||
phoneIcon?: LucideIcon;
|
||||
mapsIcon?: LucideIcon;
|
||||
onPhoneClick?: () => void;
|
||||
onMapsClick?: () => void;
|
||||
className?: string;
|
||||
containerClassName?: string;
|
||||
buttonClassName?: string;
|
||||
phoneButtonClassName?: string;
|
||||
mapsButtonClassName?: string;
|
||||
tooltipClassName?: string;
|
||||
}
|
||||
|
||||
export default function FloatingContactButtons({
|
||||
phoneNumber,
|
||||
mapsUrl,
|
||||
phoneIcon: PhoneIcon,
|
||||
mapsIcon: MapsIcon,
|
||||
onPhoneClick,
|
||||
onMapsClick,
|
||||
className = '',
|
||||
containerClassName = '',
|
||||
buttonClassName = '',
|
||||
phoneButtonClassName = '',
|
||||
mapsButtonClassName = '',
|
||||
tooltipClassName = ''
|
||||
}: FloatingContactButtonsProps) {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const [showPhoneTooltip, setShowPhoneTooltip] = useState(false);
|
||||
const [showMapsTooltip, setShowMapsTooltip] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Show floating buttons after a short delay for better UX
|
||||
const timer = setTimeout(() => setIsVisible(true), 500);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
const handlePhoneClick = () => {
|
||||
onPhoneClick?.();
|
||||
window.location.href = `tel:${phoneNumber}`;
|
||||
};
|
||||
|
||||
const handleMapsClick = () => {
|
||||
onMapsClick?.();
|
||||
window.open(mapsUrl, '_blank');
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`fixed bottom-6 right-6 z-40 flex flex-col gap-3 md:bottom-8 md:right-8 transition-opacity duration-500 ${
|
||||
isVisible ? 'opacity-100' : 'opacity-0 pointer-events-none'
|
||||
} ${className}`}
|
||||
aria-label="Floating contact buttons"
|
||||
>
|
||||
{/* Maps Button */}
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={handleMapsClick}
|
||||
className={`
|
||||
w-14 h-14 md:w-16 md:h-16 rounded-full shadow-lg hover:shadow-xl
|
||||
bg-primary-cta hover:bg-primary-cta/90 text-white
|
||||
flex items-center justify-center transition-all duration-300
|
||||
hover:scale-110 active:scale-95
|
||||
${mapsButtonClassName}
|
||||
${buttonClassName}
|
||||
`}
|
||||
aria-label="Open location in Google Maps"
|
||||
title="Get Directions"
|
||||
onMouseEnter={() => setShowMapsTooltip(true)}
|
||||
onMouseLeave={() => setShowMapsTooltip(false)}
|
||||
>
|
||||
{MapsIcon ? (
|
||||
<MapsIcon className="w-6 h-6 md:w-7 md:h-7" strokeWidth={1.5} />
|
||||
) : (
|
||||
<svg className="w-6 h-6 md:w-7 md:h-7" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5z" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
{showMapsTooltip && (
|
||||
<div className={`absolute right-16 top-1/2 -translate-y-1/2 bg-foreground text-background px-3 py-2 rounded-lg text-xs font-medium whitespace-nowrap pointer-events-none ${tooltipClassName}`}>
|
||||
Get Directions
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Phone Button */}
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={handlePhoneClick}
|
||||
className={`
|
||||
w-14 h-14 md:w-16 md:h-16 rounded-full shadow-lg hover:shadow-xl
|
||||
bg-secondary-cta hover:bg-secondary-cta/90 text-white
|
||||
flex items-center justify-center transition-all duration-300
|
||||
hover:scale-110 active:scale-95
|
||||
${phoneButtonClassName}
|
||||
${buttonClassName}
|
||||
`}
|
||||
aria-label="Call restaurant"
|
||||
title="Call Us"
|
||||
onMouseEnter={() => setShowPhoneTooltip(true)}
|
||||
onMouseLeave={() => setShowPhoneTooltip(false)}
|
||||
>
|
||||
{PhoneIcon ? (
|
||||
<PhoneIcon className="w-6 h-6 md:w-7 md:h-7" strokeWidth={1.5} />
|
||||
) : (
|
||||
<svg className="w-6 h-6 md:w-7 md:h-7" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M17.92 7.02C17.45 6.18 16.7 5.51 15.77 5.36c-1.36-.2-2.77.12-3.29 1.32l-.5 1.13c-.41.98-.3 2.04.35 2.77l1.96 2.16c-.38.86-.87 1.66-1.46 2.38l-2.38-2.38c-.7.13-1.74.7-2.45 1.36l-4.88 4.88C.5 17.66 0 19.52 0 21.5V24h2.5c1.98 0 3.84-.5 5.5-1.38l4.88-4.88c.67-.71 1.23-1.75 1.36-2.45l-2.38-2.38c.72-.59 1.52-1.08 2.38-1.46l2.16 1.96c.73.65 1.79.76 2.77.35l1.13-.5c1.2-.52 1.52-1.93 1.32-3.29-.15-.93-.82-1.68-1.66-2.15zM6.55 18.08c-1.19.84-2.58 1.32-4.05 1.32H2V21.5c0 1.47.48 2.86 1.32 4.05l4.88-4.88c-.26-.31-.48-.65-.65-1.01l-1.55-1.58z" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
{showPhoneTooltip && (
|
||||
<div className={`absolute right-16 top-1/2 -translate-y-1/2 bg-foreground text-background px-3 py-2 rounded-lg text-xs font-medium whitespace-nowrap pointer-events-none ${tooltipClassName}`}>
|
||||
Call Us
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
105
src/components/widgets/GoogleRatingWidget.tsx
Normal file
105
src/components/widgets/GoogleRatingWidget.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
"use client";
|
||||
|
||||
import React from 'react';
|
||||
import { Star } from 'lucide-react';
|
||||
|
||||
interface GoogleRatingWidgetProps {
|
||||
rating: number; // 0-5
|
||||
reviewCount: number;
|
||||
businessName: string;
|
||||
className?: string;
|
||||
containerClassName?: string;
|
||||
ratingContainerClassName?: string;
|
||||
starsClassName?: string;
|
||||
textClassName?: string;
|
||||
reviewCountClassName?: string;
|
||||
}
|
||||
|
||||
export default function GoogleRatingWidget({
|
||||
rating,
|
||||
reviewCount,
|
||||
businessName,
|
||||
className = '',
|
||||
containerClassName = '',
|
||||
ratingContainerClassName = '',
|
||||
starsClassName = '',
|
||||
textClassName = '',
|
||||
reviewCountClassName = ''
|
||||
}: GoogleRatingWidgetProps) {
|
||||
const fullStars = Math.floor(rating);
|
||||
const hasHalfStar = rating % 1 >= 0.5;
|
||||
|
||||
const renderStars = () => {
|
||||
const stars = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
if (i < fullStars) {
|
||||
stars.push(
|
||||
<Star
|
||||
key={`star-${i}`}
|
||||
className={`w-4 h-4 md:w-5 md:h-5 fill-yellow-400 text-yellow-400 ${starsClassName}`}
|
||||
/>
|
||||
);
|
||||
} else if (i === fullStars && hasHalfStar) {
|
||||
stars.push(
|
||||
<div key={`star-${i}`} className="relative">
|
||||
<Star className={`w-4 h-4 md:w-5 md:h-5 text-gray-300 ${starsClassName}`} />
|
||||
<div className="absolute top-0 left-0 overflow-hidden" style={{ width: '50%' }}>
|
||||
<Star className={`w-4 h-4 md:w-5 md:h-5 fill-yellow-400 text-yellow-400 ${starsClassName}`} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
stars.push(
|
||||
<Star
|
||||
key={`star-${i}`}
|
||||
className={`w-4 h-4 md:w-5 md:h-5 text-gray-300 ${starsClassName}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
return stars;
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`w-full flex justify-center py-8 md:py-12 px-4 ${className}`}
|
||||
aria-label={`Google rating: ${rating} out of 5 stars with ${reviewCount} reviews`}
|
||||
>
|
||||
<div
|
||||
className={`flex flex-col items-center gap-3 md:gap-4 p-4 md:p-6 rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900/50 ${containerClassName}`}
|
||||
>
|
||||
<div className={`flex items-center gap-3 md:gap-4 ${ratingContainerClassName}`}>
|
||||
{/* Google Icon */}
|
||||
<svg
|
||||
className="w-8 h-8 md:w-10 md:h-10"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M44.5 20H24v8.5h11.8C34.7 33 30.1 36 24 36c-6.6 0-12-5.4-12-12s5.4-12 12-12c3 0 5.8 1.1 7.9 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.9 2 2 11.9 2 24s9.9 22 22 22c13 0 21-9 21-21 0-1.3-.2-2.7-.5-4z"
|
||||
fill="#4285F4"
|
||||
/>
|
||||
</svg>
|
||||
<div className={`flex flex-col ${textClassName}`}>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl md:text-2xl font-bold">{rating.toFixed(1)}</span>
|
||||
<div className="flex gap-1">{renderStars()}</div>
|
||||
</div>
|
||||
<p className={`text-xs md:text-sm text-gray-600 dark:text-gray-400 ${reviewCountClassName}`}>
|
||||
{reviewCount} reviews on Google
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href={`https://www.google.com/search?q=${encodeURIComponent(businessName)} reviews`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-xs md:text-sm text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300 underline mt-2 transition-colors"
|
||||
>
|
||||
View on Google
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user