Skip to content

Commit 3f02749

Browse files
committed
Fini
1 parent 1df855d commit 3f02749

File tree

5 files changed

+221
-156
lines changed

5 files changed

+221
-156
lines changed

src/components/Footer.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export function Footer() {
1313
return (
1414
<section
1515
className={clsx(
16-
'section flex w-full flex-col items-start justify-center gap-10 p-10 py-12 text-secondary md:flex-row md:justify-between',
16+
'section flex w-full flex-col items-start justify-center gap-10 p-10 py-48 text-secondary md:flex-row md:justify-between',
1717
text.className
1818
)}>
1919
<Logo />

src/components/Gallery.tsx

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import clsx from 'clsx';
2+
import { text, title } from '../fonts';
3+
import { FaGlasses, FaHeart, FaShower } from 'react-icons/fa';
4+
import { ImageGallery } from '@/components/ImageGallery';
5+
6+
export function Gallery() {
7+
return (
8+
<div
9+
className={clsx(
10+
'mt-48 flex min-h-screen w-full flex-col items-center justify-center gap-14 px-4 text-primary md:px-12',
11+
text.className
12+
)}>
13+
<h1
14+
className={clsx(
15+
'text-center text-4xl md:text-8xl',
16+
title.className
17+
)}>
18+
Your pet deserves <br /> to be pampered!
19+
</h1>
20+
<div className="flex flex-col gap-12 text-3xl md:flex-row">
21+
<div className="flex flex-row items-center justify-center gap-5">
22+
<FaShower className="text-4xl" />
23+
Bath or Shower
24+
</div>
25+
<div className="flex flex-row items-center justify-center gap-5">
26+
<FaGlasses className="text-4xl" />
27+
Hands-On Assessment
28+
</div>
29+
<div className="flex flex-row items-center justify-center gap-5">
30+
<FaHeart className="text-4xl" />
31+
Safe Drying
32+
</div>
33+
</div>
34+
<button className="flex flex-row gap-12 rounded-full bg-primary px-8 py-4 text-2xl text-white">
35+
Book an Appointment
36+
</button>
37+
<ImageGallery />
38+
</div>
39+
);
40+
}

src/components/Intro.tsx

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { NavBar } from '@/components/NavBar';
2+
import clsx from 'clsx';
3+
import { text, title } from '../fonts';
4+
import Image from 'next/image';
5+
import pets from '../dogandcat.png';
6+
import { motion, Variants } from 'framer-motion';
7+
8+
const introHeaderVariants: Variants = {
9+
hide: {
10+
opacity: 0,
11+
x: -500,
12+
},
13+
show: {
14+
opacity: 1,
15+
x: 0,
16+
transition: {
17+
duration: 2,
18+
},
19+
},
20+
};
21+
22+
const introPictureVariants: Variants = {
23+
hide: {
24+
opacity: 0,
25+
x: 500,
26+
},
27+
show: {
28+
opacity: 1,
29+
x: 0,
30+
transition: {
31+
duration: 2,
32+
},
33+
},
34+
};
35+
export function Intro() {
36+
return (
37+
<div className="flex h-[36rem] w-full flex-col items-center justify-center overflow-x-clip bg-secondary text-light md:h-[90vh]">
38+
<NavBar />
39+
<main className="relative flex w-full grow items-start justify-center py-12 px-4 md:items-center md:justify-start md:px-12">
40+
<motion.header
41+
className={clsx(
42+
'z-10 flex flex-col gap-4 md:-mt-36',
43+
title.className
44+
)}
45+
initial="hide"
46+
whileInView="show"
47+
exit="hide"
48+
variants={introHeaderVariants}>
49+
<h1 className="text-center text-5xl md:text-start md:text-8xl">
50+
The Best Pet <br /> Groomers <br /> in Town
51+
</h1>
52+
<p className={clsx('text-3xl font-light', text.className)}>
53+
For a pawfect look and feel!
54+
</p>
55+
</motion.header>
56+
<motion.div
57+
className="absolute right-0 -bottom-12 w-full sm:w-4/5 md:-bottom-36 md:w-[950px]"
58+
initial="hide"
59+
whileInView="show"
60+
exit="hide"
61+
variants={introPictureVariants}>
62+
<Image src={pets} alt="Cat and dog" />
63+
</motion.div>
64+
</main>
65+
</div>
66+
);
67+
}

src/components/Testimonials.tsx

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import Image, { ImageProps } from 'next/image';
2+
import clsx from 'clsx';
3+
import { title } from '../fonts';
4+
import pet1 from '../images/pet1.webp';
5+
import pet2 from '../images/pet2.webp';
6+
import pet3 from '../images/pet3.webp';
7+
import { WithChildrenProps } from '../types';
8+
import { useEffect, useRef, useState } from 'react';
9+
import {
10+
motion,
11+
MotionValue,
12+
useMotionValueEvent,
13+
useScroll,
14+
useTransform,
15+
} from 'framer-motion';
16+
17+
const names = [
18+
'Abi',
19+
'Brian',
20+
'Carl',
21+
'Daniella',
22+
'Edward',
23+
'Ruby',
24+
'John',
25+
'Alan',
26+
];
27+
const locations = ['Nottingham', 'Manchester', 'London', 'York', 'Brighton'];
28+
type TestimonialProps = WithChildrenProps & {
29+
className?: string;
30+
parallax: MotionValue<number>;
31+
};
32+
function Testimonial({ className, children, parallax }: TestimonialProps) {
33+
const [randomName, setRandomName] = useState('');
34+
const [randomLocation, setRandomLocation] = useState('');
35+
36+
useEffect(() => {
37+
setRandomName(names[Math.floor(Math.random() * names.length)]);
38+
setRandomLocation(
39+
locations[Math.floor(Math.random() * locations.length)]
40+
);
41+
}, []); //To make sure the random generation only runs on the client
42+
43+
return (
44+
<motion.div
45+
className={clsx(
46+
'text-md flex aspect-[3/4] h-96 flex-col items-center justify-between gap-8 rounded-md bg-white p-6 font-light text-secondary shadow',
47+
className
48+
)}
49+
style={{ y: parallax }}>
50+
{children}
51+
<div className="w-full text-start font-bold">
52+
{randomName}, {randomLocation}
53+
</div>
54+
</motion.div>
55+
);
56+
}
57+
58+
export function Testimonials() {
59+
const target = useRef(null);
60+
const { scrollYProgress } = useScroll({
61+
target,
62+
offset: ['start end', 'end start'],
63+
});
64+
const parallax = useTransform(scrollYProgress, [0, 1], [-100, 100]);
65+
const reverseParallax = useTransform(parallax, (v) => -v);
66+
useMotionValueEvent(parallax, 'change', (v) => console.log(v));
67+
return (
68+
<div
69+
className="flex min-h-[150vh] w-full flex-col items-center justify-center gap-12 bg-secondary px-4 py-24 md:p-24"
70+
ref={target}>
71+
<h2
72+
className={clsx(
73+
'text-center text-4xl text-primary md:w-1/2 md:text-7xl',
74+
title.className
75+
)}>
76+
What Our Happy Clients Say
77+
</h2>
78+
<div className="flex grow flex-wrap items-center items-center justify-center justify-center gap-24">
79+
<Testimonial className="md:mb-24" parallax={parallax}>
80+
<TestimonialImage src={pet1} alt="" />
81+
&quot;They do a great job making Milo look so lovely. The
82+
staff are knowledgeable and friendly, always willing to give
83+
help and advice. Would definitely recommend!&quot;
84+
</Testimonial>
85+
<Testimonial className="md:mt-12" parallax={reverseParallax}>
86+
<TestimonialImage src={pet2} alt="" />
87+
&quot;They do a great job making Milo look so lovely. The
88+
staff are knowledgeable and friendly, always willing to give
89+
help and advice. Would definitely recommend!&quot;
90+
</Testimonial>
91+
<Testimonial className="md:mb-12" parallax={parallax}>
92+
<TestimonialImage src={pet3} alt="" />
93+
&quot;They do a great job making Milo look so lovely. The
94+
staff are knowledgeable and friendly, always willing to give
95+
help and advice. Would definitely recommend!&quot;
96+
</Testimonial>
97+
</div>
98+
</div>
99+
);
100+
}
101+
102+
function TestimonialImage({ src, alt }: ImageProps) {
103+
return (
104+
<div className="flex h-full w-full items-center justify-center">
105+
<div className="aspect-square h-28 overflow-clip rounded-full">
106+
<Image src={src} alt={alt} className="object-cover" />
107+
</div>
108+
</div>
109+
);
110+
}

src/pages/index.tsx

+3-155
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
1-
import { NavBar } from '@/components/NavBar';
21
import Head from 'next/head';
32
import clsx from 'clsx';
43
import { text, title } from '../fonts';
5-
import pets from '../dogandcat.png';
6-
import Image, { ImageProps } from 'next/image';
7-
import { FaGlasses, FaHeart, FaShower } from 'react-icons/fa';
8-
import { ImageGallery } from '@/components/ImageGallery';
9-
import { WithChildrenProps } from '../types';
10-
11-
import pet1 from 'images/pet1.webp';
12-
import pet2 from 'images/pet2.webp';
13-
import pet3 from 'images/pet3.webp';
14-
import { useEffect, useState } from 'react';
154
import { Footer } from '@/components/Footer';
165
import { SocialsFooter } from '@/components/SocialsFooter';
6+
import { Intro } from '@/components/Intro';
7+
import { Gallery } from '@/components/Gallery';
8+
import { Testimonials } from '@/components/Testimonials';
179

1810
export default function Home() {
1911
return (
@@ -34,147 +26,3 @@ export default function Home() {
3426
</div>
3527
);
3628
}
37-
38-
function Intro() {
39-
return (
40-
<div className="text-light flex h-[36rem] w-full flex-col items-center justify-center bg-secondary md:h-[90vh]">
41-
<NavBar />
42-
<main className="relative flex w-full grow items-start justify-center py-12 px-4 md:items-center md:justify-start md:px-12">
43-
<header
44-
className={clsx(
45-
'z-10 flex flex-col gap-4 md:-mt-36',
46-
title.className
47-
)}>
48-
<h1 className="text-center text-5xl md:text-start md:text-8xl">
49-
The Best Pet <br /> Groomers <br /> in Town
50-
</h1>
51-
<p className={clsx('text-3xl font-light', text.className)}>
52-
For a pawfect look and feel!
53-
</p>
54-
</header>
55-
<div className="absolute right-0 -bottom-12 w-full sm:w-4/5 md:-bottom-36 md:w-[950px]">
56-
<Image src={pets} alt="Cat and dog" />
57-
</div>
58-
</main>
59-
</div>
60-
);
61-
}
62-
63-
function Gallery() {
64-
return (
65-
<div
66-
className={clsx(
67-
'mt-48 flex min-h-screen w-full flex-col items-center justify-center gap-14 px-4 text-primary md:px-12',
68-
text.className
69-
)}>
70-
<h1
71-
className={clsx(
72-
'text-center text-4xl md:text-8xl',
73-
title.className
74-
)}>
75-
Your pet deserves <br /> to be pampered!
76-
</h1>
77-
<div className="flex flex-col gap-12 text-3xl md:flex-row">
78-
<div className="flex flex-row items-center justify-center gap-5">
79-
<FaShower className="text-4xl" />
80-
Bath or Shower
81-
</div>
82-
<div className="flex flex-row items-center justify-center gap-5">
83-
<FaGlasses className="text-4xl" />
84-
Hands-On Assessment
85-
</div>
86-
<div className="flex flex-row items-center justify-center gap-5">
87-
<FaHeart className="text-4xl" />
88-
Safe Drying
89-
</div>
90-
</div>
91-
<button className="flex flex-row gap-12 rounded-full bg-primary px-8 py-4 text-2xl text-white">
92-
Book an Appointment
93-
</button>
94-
<ImageGallery />
95-
</div>
96-
);
97-
}
98-
const names = [
99-
'Abi',
100-
'Brian',
101-
'Carl',
102-
'Daniella',
103-
'Edward',
104-
'Ruby',
105-
'John',
106-
'Alan',
107-
];
108-
const locations = ['Nottingham', 'Manchester', 'London', 'York', 'Brighton'];
109-
110-
function Testimonial({
111-
className,
112-
children,
113-
}: WithChildrenProps & { className?: string }) {
114-
const [randomName, setRandomName] = useState('');
115-
const [randomLocation, setRandomLocation] = useState('');
116-
117-
useEffect(() => {
118-
setRandomName(names[Math.floor(Math.random() * names.length)]);
119-
setRandomLocation(
120-
locations[Math.floor(Math.random() * locations.length)]
121-
);
122-
}, []); //To make sure the random generation only runs on the client
123-
124-
return (
125-
<div
126-
className={clsx(
127-
'text-md flex aspect-[3/4] h-96 flex-col items-center justify-between gap-8 rounded-md bg-white p-6 font-light text-secondary shadow',
128-
className
129-
)}>
130-
{children}
131-
<div className="w-full text-start font-bold">
132-
{randomName}, {randomLocation}
133-
</div>
134-
</div>
135-
);
136-
}
137-
138-
function Testimonials() {
139-
return (
140-
<div className="flex min-h-[120vh] w-full flex-col items-center justify-center gap-12 bg-secondary px-4 py-24 md:p-24">
141-
<h2
142-
className={clsx(
143-
'text-center text-4xl text-primary md:w-1/2 md:text-7xl',
144-
title.className
145-
)}>
146-
What Our Happy Clients Say
147-
</h2>
148-
<div className="flex grow flex-wrap items-center items-center justify-center justify-center gap-24">
149-
<Testimonial className="md:mb-24">
150-
<TestimonialImage src={pet1} alt="" />
151-
&quot;They do a great job making Milo look so lovely. The
152-
staff are knowledgeable and friendly, always willing to give
153-
help and advice. Would definitely recommend!&quot;
154-
</Testimonial>
155-
<Testimonial className="md:mt-12">
156-
<TestimonialImage src={pet2} alt="" />
157-
&quot;They do a great job making Milo look so lovely. The
158-
staff are knowledgeable and friendly, always willing to give
159-
help and advice. Would definitely recommend!&quot;
160-
</Testimonial>
161-
<Testimonial className="md:mb-12">
162-
<TestimonialImage src={pet3} alt="" />
163-
&quot;They do a great job making Milo look so lovely. The
164-
staff are knowledgeable and friendly, always willing to give
165-
help and advice. Would definitely recommend!&quot;
166-
</Testimonial>
167-
</div>
168-
</div>
169-
);
170-
}
171-
172-
function TestimonialImage({ src, alt }: ImageProps) {
173-
return (
174-
<div className="flex h-full w-full items-center justify-center">
175-
<div className="aspect-square h-28 overflow-clip rounded-full">
176-
<Image src={src} alt={alt} className="object-cover" />
177-
</div>
178-
</div>
179-
);
180-
}

0 commit comments

Comments
 (0)