Compare commits
27 Commits
version_2_
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| de0ba31d72 | |||
|
|
3d102e0d7b | ||
| 191c81697a | |||
| 2aae4ce4e8 | |||
| 4cba1bf270 | |||
| 99318a67ea | |||
| 3dfe616831 | |||
| 414dd3b58d | |||
| 34c8036613 | |||
| 1019392c84 | |||
| d7fcb86f17 | |||
| 98b60c9c42 | |||
| d4630c1350 | |||
|
|
6e6925a223 | ||
| e1b650552d | |||
|
|
8369667f00 | ||
| a46d1f8ac9 | |||
|
|
494c91e778 | ||
| 346d253b7c | |||
|
|
0d5c2e7577 | ||
|
|
87c8264ee7 | ||
|
|
72f8053820 | ||
|
|
6d5f16afbc | ||
| 75addd1200 | |||
|
|
b52d081d32 | ||
|
|
b7fb8ae000 | ||
| 36c04637eb |
78
src/App.tsx
78
src/App.tsx
@@ -3,13 +3,15 @@ import ContactSplitEmail from '@/components/sections/contact/ContactSplitEmail';
|
||||
import FaqSplitMedia from '@/components/sections/faq/FaqSplitMedia';
|
||||
import FeaturesComparison from '@/components/sections/features/FeaturesComparison';
|
||||
import FooterSimpleMedia from '@/components/sections/footer/FooterSimpleMedia';
|
||||
import HeroBillboardCarousel from '@/components/sections/hero/HeroBillboardCarousel';
|
||||
import HeroSplitKpi from '@/components/sections/hero/HeroSplitKpi';
|
||||
import MetricsSimpleCards from '@/components/sections/metrics/MetricsSimpleCards';
|
||||
import RecentWorks from '@/components/sections/works/RecentWorks';
|
||||
import NavbarCentered from '@/components/ui/NavbarCentered';
|
||||
import TestimonialRatingCards from '@/components/sections/testimonial/TestimonialRatingCards';
|
||||
import { Droplets, Flame, Wrench } from "lucide-react";
|
||||
import { useEffect } from "react";
|
||||
import { applyRippleEffect } from "@/hooks/useButtonClick";
|
||||
import AnimatedBackground from "@/components/ui/AnimatedBackground";
|
||||
|
||||
export default function App() {
|
||||
useEffect(() => {
|
||||
@@ -20,10 +22,11 @@ export default function App() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="app-container relative z-10 isolate">
|
||||
<AnimatedBackground />
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarCentered
|
||||
logo="Apex Plumbing"
|
||||
logo="/logo.png"
|
||||
navItems={[
|
||||
{
|
||||
name: "Services",
|
||||
@@ -33,6 +36,10 @@ export default function App() {
|
||||
name: "About",
|
||||
href: "#about",
|
||||
},
|
||||
{
|
||||
name: "Works",
|
||||
href: "#works",
|
||||
},
|
||||
{
|
||||
name: "FAQ",
|
||||
href: "#faq",
|
||||
@@ -46,39 +53,32 @@ export default function App() {
|
||||
</div>
|
||||
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroBillboardCarousel
|
||||
tag="Trusted Plumbing Services"
|
||||
title="Your Local Plumbing Experts"
|
||||
description="24/7 emergency plumbing solutions, professional repairs, and expert maintenance for your home or business."
|
||||
primaryButton={{
|
||||
text: "Schedule Service",
|
||||
href: "#contact",
|
||||
}}
|
||||
secondaryButton={{
|
||||
text: "View Our Services",
|
||||
href: "#services",
|
||||
}}
|
||||
items={[
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/plumbing-professional-doing-his-job_23-2150721531.jpg",
|
||||
},
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/couple-fixing-kitchen-sink_53876-146184.jpg",
|
||||
},
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/portrait-male-car-mechanic-car-repair-shop_23-2150367540.jpg",
|
||||
},
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/water-tap-prevention-concentrated-man-leaning-water-faucet-touching-spout-pipe_259150-58276.jpg",
|
||||
},
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/two-builders-work-clothes-thoughtfully-looking-sketch-plan-with-tools-background-workshop_574295-1618.jpg",
|
||||
},
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/male-plumber-working-with-client-fix-kitchen-problems_23-2150990680.jpg",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<HeroSplitKpi
|
||||
title="Your Local Plumbing Experts"
|
||||
description="24/7 emergency plumbing solutions, professional repairs, and expert maintenance for your home or business."
|
||||
primaryButton={{
|
||||
text: "Schedule Service",
|
||||
href: "#contact",
|
||||
}}
|
||||
kpis={[
|
||||
{
|
||||
value: "15+",
|
||||
label: "Years of Excellence",
|
||||
},
|
||||
{
|
||||
value: "5,000+",
|
||||
label: "Projects Completed",
|
||||
},
|
||||
{
|
||||
value: "98%",
|
||||
label: "Client Satisfaction",
|
||||
},
|
||||
{
|
||||
value: "24/7",
|
||||
label: "Emergency Service",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="features-comp" data-section="features-comp">
|
||||
@@ -147,6 +147,10 @@ export default function App() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="works" data-section="works">
|
||||
<RecentWorks />
|
||||
</div>
|
||||
|
||||
<div id="testimonials" data-section="testimonials">
|
||||
<TestimonialRatingCards
|
||||
tag="Happy Clients"
|
||||
@@ -284,6 +288,6 @@ export default function App() {
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
43
src/app/services/page.tsx
Normal file
43
src/app/services/page.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
|
||||
const Services = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 flex flex-col items-center justify-center p-4">
|
||||
<main className="bg-white p-8 rounded-lg shadow-md max-w-2xl w-full text-center">
|
||||
<h1 className="text-4xl font-bold text-gray-900 mb-4">Our Services</h1>
|
||||
<p className="text-lg text-gray-700 mb-6">
|
||||
Discover the range of professional services we offer to help you achieve your goals.
|
||||
We are committed to delivering high-quality solutions tailored to your needs.
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 text-left">
|
||||
<div className="p-4 border border-gray-200 rounded-md">
|
||||
<h2 className="text-xl font-semibold text-gray-800 mb-2">Service A</h2>
|
||||
<p className="text-gray-600">
|
||||
A detailed description of Service A, highlighting its benefits and what it entails for our clients.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-4 border border-gray-200 rounded-md">
|
||||
<h2 className="text-xl font-semibold text-gray-800 mb-2">Service B</h2>
|
||||
<p className="text-gray-600">
|
||||
An overview of Service B, explaining how it addresses specific challenges and provides value.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-4 border border-gray-200 rounded-md">
|
||||
<h2 className="text-xl font-semibold text-gray-800 mb-2">Service C</h2>
|
||||
<p className="text-gray-600">
|
||||
Information about Service C, outlining its key features and the expertise we bring to deliver it.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-4 border border-gray-200 rounded-md">
|
||||
<h2 className="text-xl font-semibold text-gray-800 mb-2">Service D</h2>
|
||||
<p className="text-gray-600">
|
||||
A brief explanation of Service D, demonstrating our commitment to comprehensive support and solutions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Services;
|
||||
11
src/assets/logo.svg
Normal file
11
src/assets/logo.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="30" viewBox="0 0 150 30">
|
||||
<style>
|
||||
.text {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
fill: #001122;
|
||||
}
|
||||
</style>
|
||||
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" class="text">Apex Plumbing</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 409 B |
48
src/components/sections/hero/HeroSplitKpi.tsx
Normal file
48
src/components/sections/hero/HeroSplitKpi.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import Button from "@/components/ui/Button";
|
||||
import TextAnimation from "@/components/ui/TextAnimation";
|
||||
|
||||
type HeroSplitKpiProps = {
|
||||
title: string;
|
||||
description: string;
|
||||
primaryButton: { text: string; href: string };
|
||||
kpis: { value: string; label: string }[];
|
||||
};
|
||||
|
||||
const HeroSplitKpi = ({ title, description, primaryButton, kpis }: HeroSplitKpiProps) => {
|
||||
return (
|
||||
<section
|
||||
aria-label="Hero section"
|
||||
className="flex items-center w-full min-h-svh py-25"
|
||||
>
|
||||
<div className="grid md:grid-cols-2 gap-12 items-center w-content-width mx-auto">
|
||||
<div className="flex flex-col items-start gap-4 text-left">
|
||||
<TextAnimation
|
||||
text={title}
|
||||
variant="slide-up"
|
||||
tag="h1"
|
||||
className="text-6xl font-medium text-balance"
|
||||
/>
|
||||
<TextAnimation
|
||||
text={description}
|
||||
variant="slide-up"
|
||||
tag="p"
|
||||
className="text-lg leading-tight text-balance"
|
||||
/>
|
||||
<div className="mt-2">
|
||||
<Button text={primaryButton.text} href={primaryButton.href} variant="primary" animate />
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
{kpis.map((kpi) => (
|
||||
<div key={kpi.label} className="flex flex-col items-start p-6 card rounded-lg">
|
||||
<span className="text-5xl font-bold">{kpi.value}</span>
|
||||
<span className="text-lg">{kpi.label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeroSplitKpi;
|
||||
60
src/components/sections/works/RecentWorks.tsx
Normal file
60
src/components/sections/works/RecentWorks.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import TextAnimation from "@/components/ui/TextAnimation";
|
||||
|
||||
const works = [
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/plumber-at-work-in-a-bathroom-plumbing-repair-service-assemble-and-install-concept_169016-14295.jpg",
|
||||
alt: "Plumber at work in a bathroom",
|
||||
},
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/plumber-installing-new-water-tap-kitchen_169016-14300.jpg",
|
||||
alt: "Plumber installing new water tap in kitchen",
|
||||
},
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/plumber-working-on-a-kitchen-sink_169016-14298.jpg",
|
||||
alt: "Plumber working on a kitchen sink",
|
||||
},
|
||||
{
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/plumber-fixing-a-sink-in-the-bathroom_169016-14297.jpg",
|
||||
alt: "Plumber fixing a sink in the bathroom",
|
||||
},
|
||||
];
|
||||
|
||||
const RecentWorks = () => {
|
||||
return (
|
||||
<section aria-label="Recent works section" className="py-20">
|
||||
<div className="flex flex-col gap-8 mx-auto w-content-width">
|
||||
<div className="flex flex-col items-center gap-3 md:gap-2">
|
||||
<span className="px-3 py-1 text-sm card rounded">Our Portfolio</span>
|
||||
|
||||
<TextAnimation
|
||||
text="Our Recent Works"
|
||||
variant="slide-up"
|
||||
tag="h2"
|
||||
className="text-6xl font-medium text-center text-balance"
|
||||
/>
|
||||
|
||||
<TextAnimation
|
||||
text="A showcase of our quality plumbing solutions and satisfied customers."
|
||||
variant="slide-up"
|
||||
tag="p"
|
||||
className="md:max-w-6/10 text-lg leading-tight text-center"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5">
|
||||
{works.map((work, index) => (
|
||||
<div key={index} className="overflow-hidden rounded card h-80 group">
|
||||
<img
|
||||
src={work.imageSrc}
|
||||
alt={work.alt}
|
||||
className="object-cover w-full h-full transition-transform duration-300 ease-in-out group-hover:scale-105"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecentWorks;
|
||||
11
src/components/ui/AnimatedBackground.tsx
Normal file
11
src/components/ui/AnimatedBackground.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
const AnimatedBackground = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="stars"></div>
|
||||
<div className="stars2"></div>
|
||||
<div className="stars3"></div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AnimatedBackground;
|
||||
@@ -1,19 +1,19 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=${inter.variable}+${openSans.variable}:wght@400;500;600;700&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Manrope:wght@400;500;600;700&display=swap');
|
||||
@import "tailwindcss";
|
||||
@import "./styles/masks.css";
|
||||
@import "./styles/animations.css";
|
||||
|
||||
:root {
|
||||
/* @colorThemes/lightTheme/grayBlueAccent */
|
||||
--background: #f5faff;
|
||||
--card: #f1f8ff;
|
||||
--foreground: #001122;
|
||||
--primary-cta: #15479c;
|
||||
--primary-cta-text: #f5faff;
|
||||
--secondary-cta: #ffffff;
|
||||
--secondary-cta-text: #001122;
|
||||
--accent: #a8cce8;
|
||||
--background-accent: #7ba3cf;
|
||||
--background: #ffffff;
|
||||
--card: #f9f9f9;
|
||||
--foreground: #000f06e6;
|
||||
--primary-cta: #000000;
|
||||
--primary-cta-text: #ffffff;
|
||||
--secondary-cta: #f9f9f9;
|
||||
--secondary-cta-text: #000f06e6;
|
||||
--accent: #e2e2e2;
|
||||
--background-accent: #c4c4c4;
|
||||
|
||||
/* @layout/border-radius/rounded */
|
||||
--radius: 0.5rem;
|
||||
@@ -88,7 +88,7 @@
|
||||
--color-background-accent: var(--background-accent);
|
||||
|
||||
/* Fonts */
|
||||
--font-sans: '${inter.variable} ${openSans.variable}', sans-serif;
|
||||
--font-sans: 'DM Sans', sans-serif;
|
||||
--font-mono: monospace;
|
||||
|
||||
/* Border Radius */
|
||||
@@ -134,13 +134,16 @@ html {
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: '${inter.variable} ${openSans.variable}', sans-serif;
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
overscroll-behavior: none;
|
||||
overscroll-behavior-y: none;
|
||||
background: var(--background);
|
||||
}
|
||||
|
||||
.app-container {
|
||||
}
|
||||
|
||||
h1,
|
||||
@@ -149,7 +152,7 @@ h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: '${inter.variable} ${openSans.variable}', sans-serif;
|
||||
font-family: 'Manrope', sans-serif;
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
@@ -203,3 +203,68 @@
|
||||
left: 125%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes moveGradient {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animStar {
|
||||
from {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
to {
|
||||
transform: translateY(-2000px);
|
||||
}
|
||||
}
|
||||
|
||||
.stars, .stars2, .stars3 {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stars {
|
||||
background-image: radial-gradient(2px 2px at 20px 30px, #eee, rgba(0,0,0,0)),
|
||||
radial-gradient(2px 2px at 40px 70px, #fff, rgba(0,0,0,0)),
|
||||
radial-gradient(2px 2px at 50px 160px, #ddd, rgba(0,0,0,0)),
|
||||
radial-gradient(2px 2px at 90px 40px, #fff, rgba(0,0,0,0)),
|
||||
radial-gradient(2px 2px at 130px 80px, #fff, rgba(0,0,0,0)),
|
||||
radial-gradient(2px 2px at 160px 120px, #ddd, rgba(0,0,0,0));
|
||||
background-repeat: repeat;
|
||||
background-size: 200px 200px;
|
||||
animation: animStar 50s linear infinite;
|
||||
z-index: -3;
|
||||
}
|
||||
|
||||
.stars2 {
|
||||
background-image: radial-gradient(1px 1px at 10px 20px, #fff, rgba(0,0,0,0)),
|
||||
radial-gradient(1px 1px at 80px 60px, #ddd, rgba(0,0,0,0)),
|
||||
radial-gradient(1px 1px at 120px 140px, #fff, rgba(0,0,0,0));
|
||||
background-repeat: repeat;
|
||||
background-size: 300px 300px;
|
||||
animation: animStar 100s linear infinite;
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
.stars3 {
|
||||
background-image: radial-gradient(3px 3px at 50px 50px, #fff, rgba(0,0,0,0)),
|
||||
radial-gradient(3px 3px at 100px 100px, #ddd, rgba(0,0,0,0)),
|
||||
radial-gradient(3px 3px at 150px 150px, #fff, rgba(0,0,0,0));
|
||||
background-repeat: repeat;
|
||||
background-size: 400px 400px;
|
||||
animation: animStar 150s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user