Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d754f819fe | |||
| 94b4dd965f | |||
| f3e10ff3cf | |||
| 97a0490bcd | |||
| 6b97199ca0 | |||
| 0991eb0079 | |||
| 114861d2b1 | |||
| 75aa00692f | |||
| c4e469a5ee |
1439
src/app/layout.tsx
1439
src/app/layout.tsx
File diff suppressed because it is too large
Load Diff
283
src/app/page.tsx
283
src/app/page.tsx
@@ -11,9 +11,28 @@ import FaqBase from "@/components/sections/faq/FaqBase";
|
||||
import ContactFaq from "@/components/sections/contact/ContactFaq";
|
||||
import FooterMedia from "@/components/sections/footer/FooterMedia";
|
||||
import Link from "next/link";
|
||||
import { Award, Star, MapPin, CheckCircle, TrendingUp, MessageCircle, HelpCircle, Phone, Wrench } from "lucide-react";
|
||||
import { Award, Star, MapPin, CheckCircle, TrendingUp, MessageCircle, HelpCircle, Phone, Wrench, Download, Settings, Zap } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function HomePage() {
|
||||
const [videoUrl, setVideoUrl] = useState("");
|
||||
const [selectedFormat, setSelectedFormat] = useState("mp4");
|
||||
const [selectedQuality, setSelectedQuality] = useState("1080p");
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
|
||||
const handleDownload = () => {
|
||||
if (!videoUrl) {
|
||||
alert("Please enter a video URL");
|
||||
return;
|
||||
}
|
||||
setIsDownloading(true);
|
||||
// Simulated download logic
|
||||
setTimeout(() => {
|
||||
setIsDownloading(false);
|
||||
alert(`Downloading: ${selectedFormat.toUpperCase()} @ ${selectedQuality}`);
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="text-shift"
|
||||
@@ -38,7 +57,8 @@ export default function HomePage() {
|
||||
{ name: "Contact", id: "#contact" },
|
||||
]}
|
||||
button={{
|
||||
text: "Call (813) 479-5578", href: "tel:+18134795578"}}
|
||||
text: "Call (813) 479-5578", href: "tel:+18134795578"
|
||||
}}
|
||||
brandName="PB&J Plumbing"
|
||||
/>
|
||||
</div>
|
||||
@@ -53,32 +73,145 @@ export default function HomePage() {
|
||||
tagAnimation="slide-up"
|
||||
buttons={[
|
||||
{
|
||||
text: "Call (813) 479-5578", href: "tel:+18134795578"},
|
||||
text: "Call (813) 479-5578", href: "tel:+18134795578"
|
||||
},
|
||||
{
|
||||
text: "Get a Free Estimate", href: "#contact"},
|
||||
text: "Get a Free Estimate", href: "#contact"
|
||||
},
|
||||
]}
|
||||
buttonAnimation="slide-up"
|
||||
background={{
|
||||
variant: "plain"}}
|
||||
variant: "plain"
|
||||
}}
|
||||
carouselItems={[
|
||||
{
|
||||
id: "1", imageSrc: "http://img.b2bpic.net/free-photo/man-cleaning-his-bathroom-talking-by-mobile-phone_329181-20780.jpg", imageAlt: "Professional plumber at work"},
|
||||
id: "1", imageSrc: "http://img.b2bpic.net/free-photo/man-cleaning-his-bathroom-talking-by-mobile-phone_329181-20780.jpg", imageAlt: "Professional plumber at work"
|
||||
},
|
||||
{
|
||||
id: "2", imageSrc: "http://img.b2bpic.net/free-photo/empty-bathroom-with-hand-wash-basin_107420-63637.jpg?_wi=1", imageAlt: "Bathroom plumbing renovation"},
|
||||
id: "2", imageSrc: "http://img.b2bpic.net/free-photo/empty-bathroom-with-hand-wash-basin_107420-63637.jpg?_wi=1", imageAlt: "Bathroom plumbing renovation"
|
||||
},
|
||||
{
|
||||
id: "3", imageSrc: "http://img.b2bpic.net/free-photo/side-view-man-working-as-plumber_23-2150746306.jpg?_wi=1", imageAlt: "Full repipe system installation"},
|
||||
id: "3", imageSrc: "http://img.b2bpic.net/free-photo/side-view-man-working-as-plumber_23-2150746306.jpg?_wi=1", imageAlt: "Full repipe system installation"
|
||||
},
|
||||
{
|
||||
id: "4", imageSrc: "http://img.b2bpic.net/free-photo/woman-relaxing-spa_23-2148001076.jpg?_wi=1", imageAlt: "Steam generator installation"},
|
||||
id: "4", imageSrc: "http://img.b2bpic.net/free-photo/woman-relaxing-spa_23-2148001076.jpg?_wi=1", imageAlt: "Steam generator installation"
|
||||
},
|
||||
{
|
||||
id: "5", imageSrc: "http://img.b2bpic.net/free-photo/man-installs-heating-system-house-checks-pipes-with-wrench_169016-53677.jpg?_wi=1", imageAlt: "General plumbing repair"},
|
||||
id: "5", imageSrc: "http://img.b2bpic.net/free-photo/man-installs-heating-system-house-checks-pipes-with-wrench_169016-53677.jpg?_wi=1", imageAlt: "General plumbing repair"
|
||||
},
|
||||
{
|
||||
id: "6", imageSrc: "http://img.b2bpic.net/free-photo/father-kid-taking-selfies_23-2148947322.jpg", imageAlt: "PB&J Plumbing experienced team"},
|
||||
id: "6", imageSrc: "http://img.b2bpic.net/free-photo/father-kid-taking-selfies_23-2148947322.jpg", imageAlt: "PB&J Plumbing experienced team"
|
||||
},
|
||||
]}
|
||||
autoPlay={true}
|
||||
autoPlayInterval={4000}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Video Download Functionality Section */}
|
||||
<div id="video-download" data-section="video-download" className="py-20 px-4 md:px-8">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-4xl md:text-5xl font-bold mb-4 flex items-center justify-center gap-3">
|
||||
<Download className="w-8 h-8 md:w-10 md:h-10" />
|
||||
Video Download Tool
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 mb-2">Download videos in your preferred format and quality</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-xl shadow-lg p-8 border border-gray-200">
|
||||
{/* URL Input */}
|
||||
<div className="mb-8">
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-3">
|
||||
Video URL
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={videoUrl}
|
||||
onChange={(e) => setVideoUrl(e.target.value)}
|
||||
placeholder="Enter video URL (e.g., https://...)"
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Format Selection */}
|
||||
<div className="mb-8">
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2">
|
||||
<Settings className="w-4 h-4" />
|
||||
Video Format
|
||||
</label>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
{["mp4", "avi", "mkv", "webm"].map((format) => (
|
||||
<button
|
||||
key={format}
|
||||
onClick={() => setSelectedFormat(format)}
|
||||
className={`py-2 px-4 rounded-lg font-medium transition ${
|
||||
selectedFormat === format
|
||||
? "bg-blue-500 text-white"
|
||||
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
|
||||
}`}
|
||||
>
|
||||
{format.toUpperCase()}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quality Settings */}
|
||||
<div className="mb-8">
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2">
|
||||
<Zap className="w-4 h-4" />
|
||||
Video Quality
|
||||
</label>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
{["360p", "480p", "720p", "1080p"].map((quality) => (
|
||||
<button
|
||||
key={quality}
|
||||
onClick={() => setSelectedQuality(quality)}
|
||||
className={`py-2 px-4 rounded-lg font-medium transition ${
|
||||
selectedQuality === quality
|
||||
? "bg-green-500 text-white"
|
||||
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
|
||||
}`}
|
||||
>
|
||||
{quality}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Download Button */}
|
||||
<div className="flex gap-4">
|
||||
<button
|
||||
onClick={handleDownload}
|
||||
disabled={isDownloading || !videoUrl}
|
||||
className="flex-1 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white font-bold py-3 px-6 rounded-lg transition flex items-center justify-center gap-2"
|
||||
>
|
||||
<Download className="w-5 h-5" />
|
||||
{isDownloading ? "Downloading..." : "Download Video"}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setVideoUrl("");
|
||||
setSelectedFormat("mp4");
|
||||
setSelectedQuality("1080p");
|
||||
}}
|
||||
className="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-3 px-6 rounded-lg transition"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Info Box */}
|
||||
<div className="mt-8 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
||||
<p className="text-sm text-gray-700">
|
||||
<strong>Note:</strong> Selected format: <span className="font-semibold text-blue-600">{selectedFormat.toUpperCase()}</span> | Quality: <span className="font-semibold text-green-600">{selectedQuality}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Services Section */}
|
||||
<div id="services" data-section="services">
|
||||
<FeatureCardTwentyFour
|
||||
@@ -90,29 +223,36 @@ export default function HomePage() {
|
||||
features={[
|
||||
{
|
||||
id: "repipe", title: "Full Repipe Systems", author: "Expert Installation", description: "Complete home repiping with modern materials. We assess your system and replace outdated pipes with durable, high-quality alternatives to ensure lasting reliability.", tags: ["Home Upgrade", "Quality Materials"],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/side-view-man-working-as-plumber_23-2150746306.jpg?_wi=2", imageAlt: "Full repipe system installation"},
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/side-view-man-working-as-plumber_23-2150746306.jpg?_wi=2", imageAlt: "Full repipe system installation"
|
||||
},
|
||||
{
|
||||
id: "bathroom", title: "Bathroom Remodels", author: "Design & Installation", description: "Transform your bathroom with our comprehensive remodeling services. We handle plumbing layout, fixtures, and installations to create the bathroom of your dreams.", tags: ["Design", "Installation"],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/empty-bathroom-with-hand-wash-basin_107420-63637.jpg?_wi=2", imageAlt: "Luxury bathroom remodel"},
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/empty-bathroom-with-hand-wash-basin_107420-63637.jpg?_wi=2", imageAlt: "Luxury bathroom remodel"
|
||||
},
|
||||
{
|
||||
id: "toilet", title: "In-Wall Toilet Systems", author: "Modern Installation", description: "Sleek, space-saving in-wall toilet systems that give your bathroom a contemporary look. Expert installation with concealed tanks and smooth operation.", tags: ["Modern Design", "Space Saving"],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/toilet-seat_1203-3742.jpg", imageAlt: "In-wall toilet system"},
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/toilet-seat_1203-3742.jpg", imageAlt: "In-wall toilet system"
|
||||
},
|
||||
{
|
||||
id: "steam", title: "Steam Generator Installation", author: "Luxury Addition", description: "Install a personal steam shower system for ultimate relaxation. Complete plumbing integration and professional setup for safe, reliable operation.", tags: ["Luxury", "Wellness"],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/woman-relaxing-spa_23-2148001076.jpg?_wi=2", imageAlt: "Steam shower installation"},
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/woman-relaxing-spa_23-2148001076.jpg?_wi=2", imageAlt: "Steam shower installation"
|
||||
},
|
||||
{
|
||||
id: "master", title: "Master Remodels", author: "Full-Service Renovation", description: "Complete master suite and bathroom renovations. We coordinate all plumbing aspects of your major remodel project with precision and professionalism.", tags: ["Comprehensive", "Expert Coordination"],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/side-view-man-working-as-plumber_23-2150746322.jpg", imageAlt: "Master bathroom renovation"},
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/side-view-man-working-as-plumber_23-2150746322.jpg", imageAlt: "Master bathroom renovation"
|
||||
},
|
||||
{
|
||||
id: "general", title: "General Plumbing Repairs", author: "Quick Solutions", description: "Fast response to leaks, clogs, and emergency repairs. Available for residential plumbing issues—from minor fixes to urgent problems that can't wait.", tags: ["Emergency", "Reliable"],
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/man-installs-heating-system-house-checks-pipes-with-wrench_169016-53677.jpg?_wi=2", imageAlt: "General plumbing repair service"},
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/man-installs-heating-system-house-checks-pipes-with-wrench_169016-53677.jpg?_wi=2", imageAlt: "General plumbing repair service"
|
||||
},
|
||||
]}
|
||||
animationType="slide-up"
|
||||
textboxLayout="default"
|
||||
useInvertedBackground={false}
|
||||
buttons={[
|
||||
{
|
||||
text: "Request Free Estimate", href: "#contact"},
|
||||
text: "Request Free Estimate", href: "#contact"
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -123,16 +263,20 @@ export default function HomePage() {
|
||||
metrics={[
|
||||
{
|
||||
id: "1", icon: Award,
|
||||
title: "Years Experience", value: "27+"},
|
||||
title: "Years Experience", value: "27+"
|
||||
},
|
||||
{
|
||||
id: "2", icon: Star,
|
||||
title: "5-Star Rating", value: "100%"},
|
||||
title: "5-Star Rating", value: "100%"
|
||||
},
|
||||
{
|
||||
id: "3", icon: MapPin,
|
||||
title: "Service Area", value: "Local"},
|
||||
title: "Service Area", value: "Local"
|
||||
},
|
||||
{
|
||||
id: "4", icon: CheckCircle,
|
||||
title: "Licensed & Insured", value: "Yes"},
|
||||
title: "Licensed & Insured", value: "Yes"
|
||||
},
|
||||
]}
|
||||
title="Why Choose PB&J Plumbing"
|
||||
description="Proven expertise and customer satisfaction. Our numbers speak to our commitment to quality service."
|
||||
@@ -150,17 +294,23 @@ export default function HomePage() {
|
||||
<TestimonialCardTen
|
||||
testimonials={[
|
||||
{
|
||||
id: "1", title: "Professional & Punctual", quote: "PB&J Plumbing fixed our burst pipe in an emergency and did an excellent job. They were professional, on time, and fair priced. Highly recommend!", name: "Robert Martinez", role: "Homeowner, Spring Hill", imageSrc: "http://img.b2bpic.net/free-photo/young-blonde-woman-wearing-casual-blue-shirt-success-sign-doing-positive-gesture-with-hand-thumbs-up-smiling-happy-cheerful-expression-winner-gesture_839833-2022.jpg", imageAlt: "Robert Martinez"},
|
||||
id: "1", title: "Professional & Punctual", quote: "PB&J Plumbing fixed our burst pipe in an emergency and did an excellent job. They were professional, on time, and fair priced. Highly recommend!", name: "Robert Martinez", role: "Homeowner, Spring Hill", imageSrc: "http://img.b2bpic.net/free-photo/young-blonde-woman-wearing-casual-blue-shirt-success-sign-doing-positive-gesture-with-hand-thumbs-up-smiling-happy-cheerful-expression-winner-gesture_839833-2022.jpg", imageAlt: "Robert Martinez"
|
||||
},
|
||||
{
|
||||
id: "2", title: "Transformed Our Bathroom", quote: "We hired them for a full bathroom remodel and they exceeded our expectations. Great craftsmanship, attention to detail, and friendly team. Best decision!", name: "Jennifer Thompson", role: "Homeowner, Palm Harbor", imageSrc: "http://img.b2bpic.net/free-photo/portrait-woman-business-embrace-confidence-posing-beauty-black-african-american-isolated-gray-background_640221-39.jpg", imageAlt: "Jennifer Thompson"},
|
||||
id: "2", title: "Transformed Our Bathroom", quote: "We hired them for a full bathroom remodel and they exceeded our expectations. Great craftsmanship, attention to detail, and friendly team. Best decision!", name: "Jennifer Thompson", role: "Homeowner, Palm Harbor", imageSrc: "http://img.b2bpic.net/free-photo/portrait-woman-business-embrace-confidence-posing-beauty-black-african-american-isolated-gray-background_640221-39.jpg", imageAlt: "Jennifer Thompson"
|
||||
},
|
||||
{
|
||||
id: "3", title: "Reliable & Trustworthy", quote: "27 years of experience shows in their work. They explained everything clearly, no surprises on the bill, and the quality is outstanding. Worth every penny.", name: "David Chen", role: "Homeowner, Spring Hill", imageSrc: "http://img.b2bpic.net/free-photo/front-view-smiley-woman-home_23-2150062545.jpg", imageAlt: "David Chen"},
|
||||
id: "3", title: "Reliable & Trustworthy", quote: "27 years of experience shows in their work. They explained everything clearly, no surprises on the bill, and the quality is outstanding. Worth every penny.", name: "David Chen", role: "Homeowner, Spring Hill", imageSrc: "http://img.b2bpic.net/free-photo/front-view-smiley-woman-home_23-2150062545.jpg", imageAlt: "David Chen"
|
||||
},
|
||||
{
|
||||
id: "4", title: "Emergency Service Hero", quote: "Clogged main line at midnight and they answered! Arrived within 30 minutes, diagnosed the issue, and fixed it professionally. Thank you PB&J!", name: "Margaret Sullivan", role: "Homeowner, Surrounding Area", imageSrc: "http://img.b2bpic.net/free-photo/portrait-attractive-young-businesswoman_329181-15813.jpg", imageAlt: "Margaret Sullivan"},
|
||||
id: "4", title: "Emergency Service Hero", quote: "Clogged main line at midnight and they answered! Arrived within 30 minutes, diagnosed the issue, and fixed it professionally. Thank you PB&J!", name: "Margaret Sullivan", role: "Homeowner, Surrounding Area", imageSrc: "http://img.b2bpic.net/free-photo/portrait-attractive-young-businesswoman_329181-15813.jpg", imageAlt: "Margaret Sullivan"
|
||||
},
|
||||
{
|
||||
id: "5", title: "Outstanding Craftsmanship", quote: "Completed our whole-house repipe project on schedule and within budget. The team was respectful of our home and did pristine work. Highly satisfied!", name: "Thomas Anderson", role: "Homeowner, Palm Harbor", imageSrc: "http://img.b2bpic.net/free-photo/young-woman-sitting-library_273609-15845.jpg", imageAlt: "Thomas Anderson"},
|
||||
id: "5", title: "Outstanding Craftsmanship", quote: "Completed our whole-house repipe project on schedule and within budget. The team was respectful of our home and did pristine work. Highly satisfied!", name: "Thomas Anderson", role: "Homeowner, Palm Harbor", imageSrc: "http://img.b2bpic.net/free-photo/young-woman-sitting-library_273609-15845.jpg", imageAlt: "Thomas Anderson"
|
||||
},
|
||||
{
|
||||
id: "6", title: "Local & Personal Service", quote: "I appreciate that they're locally owned and operated. They treat you like a neighbor, not a number. Professional service with a personal touch. Five stars!", name: "Patricia Rodriguez", role: "Homeowner, Spring Hill", imageSrc: "http://img.b2bpic.net/free-photo/positive-businesswoman-work_1098-3861.jpg", imageAlt: "Patricia Rodriguez"},
|
||||
id: "6", title: "Local & Personal Service", quote: "I appreciate that they're locally owned and operated. They treat you like a neighbor, not a number. Professional service with a personal touch. Five stars!", name: "Patricia Rodriguez", role: "Homeowner, Spring Hill", imageSrc: "http://img.b2bpic.net/free-photo/positive-businesswoman-work_1098-3861.jpg", imageAlt: "Patricia Rodriguez"
|
||||
},
|
||||
]}
|
||||
title="Trusted by Our Community"
|
||||
description="Read what homeowners in Spring Hill and Palm Harbor say about our plumbing services."
|
||||
@@ -181,9 +331,11 @@ export default function HomePage() {
|
||||
tagIcon={CheckCircle}
|
||||
tagAnimation="slide-up"
|
||||
names={[
|
||||
"Google Reviews", "HomeAdvisor", "Angi", "Local Community"]}
|
||||
"Google Reviews", "HomeAdvisor", "Angi", "Local Community"
|
||||
]}
|
||||
logos={[
|
||||
"http://img.b2bpic.net/free-photo/letter-z-white-paper-keyboard-white-marble-textured-background_23-2148061544.jpg", "http://img.b2bpic.net/free-photo/home-insurance-coverage-estate-residential_53876-121259.jpg", "http://img.b2bpic.net/free-vector/round-technology-logo_1051-868.jpg"]}
|
||||
"http://img.b2bpic.net/free-photo/letter-z-white-paper-keyboard-white-marble-textured-background_23-2148061544.jpg", "http://img.b2bpic.net/free-photo/home-insurance-coverage-estate-residential_53876-121259.jpg", "http://img.b2bpic.net/free-vector/round-technology-logo_1051-868.jpg"
|
||||
]}
|
||||
textboxLayout="default"
|
||||
useInvertedBackground={false}
|
||||
speed={40}
|
||||
@@ -196,17 +348,23 @@ export default function HomePage() {
|
||||
<FaqBase
|
||||
faqs={[
|
||||
{
|
||||
id: "1", title: "Do you offer free estimates?", content: "Yes! We provide free, no-obligation estimates for all plumbing services. We'll assess your needs, explain the work required, and give you a fair, transparent quote before any work begins."},
|
||||
id: "1", title: "Do you offer free estimates?", content: "Yes! We provide free, no-obligation estimates for all plumbing services. We'll assess your needs, explain the work required, and give you a fair, transparent quote before any work begins."
|
||||
},
|
||||
{
|
||||
id: "2", title: "Are you licensed and insured?", content: "Absolutely. PB&J Plumbing is fully licensed and insured. We comply with all local codes and regulations. Your peace of mind and protection are important to us."},
|
||||
id: "2", title: "Are you licensed and insured?", content: "Absolutely. PB&J Plumbing is fully licensed and insured. We comply with all local codes and regulations. Your peace of mind and protection are important to us."
|
||||
},
|
||||
{
|
||||
id: "3", title: "Do you offer emergency plumbing services?", content: "Yes, we offer emergency plumbing services for urgent situations. Call (813) 479-5578 to speak with our team about after-hours emergencies and availability."},
|
||||
id: "3", title: "Do you offer emergency plumbing services?", content: "Yes, we offer emergency plumbing services for urgent situations. Call (813) 479-5578 to speak with our team about after-hours emergencies and availability."
|
||||
},
|
||||
{
|
||||
id: "4", title: "What service areas do you cover?", content: "We serve Spring Hill, Palm Harbor, and surrounding areas in the greater Tampa Bay region. Call us to confirm service availability for your specific location."},
|
||||
id: "4", title: "What service areas do you cover?", content: "We serve Spring Hill, Palm Harbor, and surrounding areas in the greater Tampa Bay region. Call us to confirm service availability for your specific location."
|
||||
},
|
||||
{
|
||||
id: "5", title: "How long have you been in business?", content: "We've been proudly serving the community for 27 years. Our longevity is a testament to our quality workmanship and customer satisfaction. We're locally owned and operated."},
|
||||
id: "5", title: "How long have you been in business?", content: "We've been proudly serving the community for 27 years. Our longevity is a testament to our quality workmanship and customer satisfaction. We're locally owned and operated."
|
||||
},
|
||||
{
|
||||
id: "6", title: "What payment methods do you accept?", content: "We accept all major payment methods including cash, check, credit cards, and financing options for larger projects. Ask about payment plans when you call for your free estimate."},
|
||||
id: "6", title: "What payment methods do you accept?", content: "We accept all major payment methods including cash, check, credit cards, and financing options for larger projects. Ask about payment plans when you call for your free estimate."
|
||||
},
|
||||
]}
|
||||
title="Common Plumbing Questions"
|
||||
description="Find answers to frequently asked questions about our services, pricing, and process."
|
||||
@@ -226,19 +384,24 @@ export default function HomePage() {
|
||||
ctaTitle="Ready to Schedule Your Service?"
|
||||
ctaDescription="Contact us today for a free estimate or to book your plumbing service. We're here to help!"
|
||||
ctaButton={{
|
||||
text: "Call (813) 479-5578", href: "tel:+18134795578"}}
|
||||
text: "Call (813) 479-5578", href: "tel:+18134795578"
|
||||
}}
|
||||
ctaIcon={Phone}
|
||||
useInvertedBackground={false}
|
||||
animationType="slide-up"
|
||||
faqs={[
|
||||
{
|
||||
id: "1", title: "What is your response time for service calls?", content: "We prioritize urgent plumbing emergencies and work to schedule service calls quickly. Response times vary based on demand, but we always strive for prompt, reliable service."},
|
||||
id: "1", title: "What is your response time for service calls?", content: "We prioritize urgent plumbing emergencies and work to schedule service calls quickly. Response times vary based on demand, but we always strive for prompt, reliable service."
|
||||
},
|
||||
{
|
||||
id: "2", title: "Do you provide warranties on your work?", content: "Yes, we stand behind our work with warranties on labor and materials. Ask about specific warranty details when scheduling your service or requesting an estimate."},
|
||||
id: "2", title: "Do you provide warranties on your work?", content: "Yes, we stand behind our work with warranties on labor and materials. Ask about specific warranty details when scheduling your service or requesting an estimate."
|
||||
},
|
||||
{
|
||||
id: "3", title: "Can you help with water conservation upgrades?", content: "Absolutely! We can install water-efficient fixtures and advise on upgrades that reduce water usage and lower your utility bills while protecting the environment."},
|
||||
id: "3", title: "Can you help with water conservation upgrades?", content: "Absolutely! We can install water-efficient fixtures and advise on upgrades that reduce water usage and lower your utility bills while protecting the environment."
|
||||
},
|
||||
{
|
||||
id: "4", title: "Do you handle commercial plumbing work?", content: "We primarily serve residential customers in Spring Hill and Palm Harbor. Contact us directly to discuss any commercial plumbing needs or referrals."},
|
||||
id: "4", title: "Do you handle commercial plumbing work?", content: "We primarily serve residential customers in Spring Hill and Palm Harbor. Contact us directly to discuss any commercial plumbing needs or referrals."
|
||||
},
|
||||
]}
|
||||
accordionAnimationType="smooth"
|
||||
/>
|
||||
@@ -253,37 +416,49 @@ export default function HomePage() {
|
||||
{
|
||||
title: "Services", items: [
|
||||
{
|
||||
label: "Full Repipe Systems", href: "#services"},
|
||||
label: "Full Repipe Systems", href: "#services"
|
||||
},
|
||||
{
|
||||
label: "Bathroom Remodels", href: "#services"},
|
||||
label: "Bathroom Remodels", href: "#services"
|
||||
},
|
||||
{
|
||||
label: "Emergency Repairs", href: "#contact"},
|
||||
label: "Emergency Repairs", href: "#contact"
|
||||
},
|
||||
{
|
||||
label: "Free Estimates", href: "#contact"},
|
||||
label: "Free Estimates", href: "#contact"
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Company", items: [
|
||||
{
|
||||
label: "About Us", href: "#"},
|
||||
label: "About Us", href: "#"
|
||||
},
|
||||
{
|
||||
label: "Our Team", href: "#"},
|
||||
label: "Our Team", href: "#"
|
||||
},
|
||||
{
|
||||
label: "Reviews", href: "#testimonials"},
|
||||
label: "Reviews", href: "#testimonials"
|
||||
},
|
||||
{
|
||||
label: "Contact", href: "#contact"},
|
||||
label: "Contact", href: "#contact"
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Contact", items: [
|
||||
{
|
||||
label: "Phone: (813) 479-5578", href: "tel:+18134795578"},
|
||||
label: "Phone: (813) 479-5578", href: "tel:+18134795578"
|
||||
},
|
||||
{
|
||||
label: "Spring Hill, FL", href: "#"},
|
||||
label: "Spring Hill, FL", href: "#"
|
||||
},
|
||||
{
|
||||
label: "Serving Palm Harbor & Surrounding Areas", href: "#"},
|
||||
label: "Serving Palm Harbor & Surrounding Areas", href: "#"
|
||||
},
|
||||
{
|
||||
label: "Email us", href: "mailto:info@pbjplumbing.com"},
|
||||
label: "Email us", href: "mailto:info@pbjplumbing.com"
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
@@ -293,4 +468,4 @@ export default function HomePage() {
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
194
src/components/sections/storyGenerator/StoryGeneratorSection.tsx
Normal file
194
src/components/sections/storyGenerator/StoryGeneratorSection.tsx
Normal file
@@ -0,0 +1,194 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useRef } from "react";
|
||||
import { Sparkles, Volume2, RotateCcw, Wand2 } from "lucide-react";
|
||||
import Textarea from "@/components/form/Textarea";
|
||||
|
||||
interface VoiceOption {
|
||||
id: string;
|
||||
name: string;
|
||||
language: string;
|
||||
}
|
||||
|
||||
const voiceOptions: VoiceOption[] = [
|
||||
{ id: "en-US-neural2-c", name: "Alex", language: "English (US)" },
|
||||
{ id: "en-US-neural2-e", name: "Breeze", language: "English (US)" },
|
||||
{ id: "en-US-neural2-a", name: "Clara", language: "English (US)" },
|
||||
{ id: "en-GB-neural2-c", name: "Eleanor", language: "English (UK)" },
|
||||
];
|
||||
|
||||
export default function StoryGeneratorSection() {
|
||||
const [prompt, setPrompt] = useState("");
|
||||
const [story, setStory] = useState("");
|
||||
const [selectedVoice, setSelectedVoice] = useState(voiceOptions[0].id);
|
||||
const [isGenerating, setIsGenerating] = useState(false);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
||||
const audioRef = useRef<HTMLAudioElement>(null);
|
||||
|
||||
const handleGenerateStory = async () => {
|
||||
if (!prompt.trim()) return;
|
||||
|
||||
setIsGenerating(true);
|
||||
try {
|
||||
// Simulate story generation
|
||||
const generatedStory = `Once upon a time, ${prompt}. The sun rose over the horizon, casting golden light across the landscape. Every element of the world seemed to come alive with purpose and meaning. As the story unfolded, characters emerged from the mist, each with their own dreams and desires. The tale grew richer with each passing moment, weaving together threads of hope, adventure, and discovery. And so the journey began, leading to unexpected places and profound transformations.`;
|
||||
|
||||
setStory(generatedStory);
|
||||
} catch (error) {
|
||||
console.error("Error generating story:", error);
|
||||
} finally {
|
||||
setIsGenerating(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePreviewVoice = async () => {
|
||||
if (!story.trim()) return;
|
||||
|
||||
setIsPlaying(true);
|
||||
try {
|
||||
// Simulate voice preview - in production, this would use a text-to-speech API
|
||||
const utterance = new SpeechSynthesisUtterance(story);
|
||||
utterance.rate = 1;
|
||||
utterance.pitch = 1;
|
||||
|
||||
utterance.onend = () => {
|
||||
setIsPlaying(false);
|
||||
};
|
||||
|
||||
window.speechSynthesis.speak(utterance);
|
||||
} catch (error) {
|
||||
console.error("Error playing audio:", error);
|
||||
setIsPlaying(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleStopPlayback = () => {
|
||||
window.speechSynthesis.cancel();
|
||||
setIsPlaying(false);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setPrompt("");
|
||||
setStory("");
|
||||
setPreviewUrl(null);
|
||||
window.speechSynthesis.cancel();
|
||||
setIsPlaying(false);
|
||||
};
|
||||
|
||||
const selectedVoiceObj = voiceOptions.find((v) => v.id === selectedVoice);
|
||||
|
||||
return (
|
||||
<div className="w-full py-16 md:py-24">
|
||||
<div className="mx-auto max-w-4xl px-4 md:px-6">
|
||||
{/* Header */}
|
||||
<div className="mb-12 text-center">
|
||||
<div className="mb-4 flex items-center justify-center gap-2">
|
||||
<Sparkles className="h-5 w-5" />
|
||||
<span className="text-sm font-medium">Story Generation</span>
|
||||
</div>
|
||||
<h2 className="mb-3 text-3xl font-bold md:text-4xl">Create Your Story</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-400">
|
||||
Generate unique stories and listen to them with different voice options
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Main Container */}
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
{/* Input Section */}
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<label className="mb-2 block text-sm font-medium">Story Prompt</label>
|
||||
<Textarea
|
||||
value={prompt}
|
||||
onChange={setPrompt}
|
||||
placeholder="Describe your story idea... e.g., 'a wizard discovers a hidden kingdom'"
|
||||
rows={6}
|
||||
disabled={isGenerating}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Generate Button */}
|
||||
<button
|
||||
onClick={handleGenerateStory}
|
||||
disabled={!prompt.trim() || isGenerating}
|
||||
className="flex w-full items-center justify-center gap-2 rounded-lg bg-blue-600 px-6 py-3 font-medium text-white transition-all hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<Wand2 className="h-4 w-4" />
|
||||
{isGenerating ? "Generating..." : "Generate Story"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Voice Options Section */}
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<label className="mb-3 block text-sm font-medium">Select Voice</label>
|
||||
<div className="space-y-2">
|
||||
{voiceOptions.map((voice) => (
|
||||
<label
|
||||
key={voice.id}
|
||||
className="flex items-center rounded-lg border border-gray-300 p-3 cursor-pointer transition-all hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-800"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="voice"
|
||||
value={voice.id}
|
||||
checked={selectedVoice === voice.id}
|
||||
onChange={(e) => setSelectedVoice(e.target.value)}
|
||||
className="mr-3"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium">{voice.name}</p>
|
||||
<p className="text-xs text-gray-500">{voice.language}</p>
|
||||
</div>
|
||||
<Volume2 className="h-4 w-4 text-gray-400" />
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Audio Preview */}
|
||||
<div className="space-y-3">
|
||||
<label className="text-sm font-medium">Audio Preview</label>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={isPlaying ? handleStopPlayback : handlePreviewVoice}
|
||||
disabled={!story.trim()}
|
||||
className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-emerald-600 px-4 py-3 font-medium text-white transition-all hover:bg-emerald-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<Volume2 className="h-4 w-4" />
|
||||
{isPlaying ? "Stop" : "Preview Voice"}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleReset}
|
||||
className="flex items-center justify-center gap-2 rounded-lg border border-gray-300 px-4 py-3 font-medium transition-all hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-800"
|
||||
>
|
||||
<RotateCcw className="h-4 w-4" />
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Generated Story Display */}
|
||||
{story && (
|
||||
<div className="mt-8 rounded-lg border border-gray-200 bg-gray-50 p-6 dark:border-gray-700 dark:bg-gray-900">
|
||||
<h3 className="mb-4 text-lg font-semibold">Your Generated Story</h3>
|
||||
<p className="whitespace-pre-wrap text-gray-700 dark:text-gray-300 leading-relaxed">
|
||||
{story}
|
||||
</p>
|
||||
<div className="mt-4 flex items-center justify-between border-t border-gray-200 pt-4 dark:border-gray-700">
|
||||
<p className="text-sm text-gray-500">
|
||||
Voice: <span className="font-medium">{selectedVoiceObj?.name}</span>
|
||||
</p>
|
||||
<div className="text-sm text-gray-500">
|
||||
{story.split(" ").length} words
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user