fix/landing_page #7

Merged
mihir merged 6 commits from fix/landing_page into main 2025-08-06 10:46:49 +05:30
3 changed files with 437 additions and 116 deletions
Showing only changes of commit 0a31567b38 - Show all commits

View File

@ -1,33 +1,67 @@
import { Box, Typography, Button } from "@mui/material";
import ArrowOutwardIcon from "@mui/icons-material/ArrowOutward";
import { motion } from "framer-motion";
import { motion, Variants, Transition } from "framer-motion";
const AboutUs = () => {
// Animation variants
const containerVariants = {
// Type-safe animation variants
const containerVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.2,
duration: 0.6,
staggerChildren: 0.3,
duration: 0.8,
},
},
};
const itemVariants = {
hidden: { y: 20, opacity: 0 },
const itemVariants: Variants = {
hidden: { y: 30, opacity: 0 },
visible: {
y: 0,
opacity: 1,
transition: {
duration: 0.6,
ease: "easeOut" as const,
duration: 0.8,
ease: [0.16, 1, 0.3, 1], // Cubic bezier curve for easeOut
},
},
};
const titleVariants: Variants = {
...itemVariants,
hover: {
scale: 1.02,
transition: {
repeat: Infinity,
repeatType: "reverse",
duration: 1.5,
} as Transition,
},
};
const underlineVariants: Variants = {
hidden: { width: 0 },
visible: {
width: "80px",
transition: {
delay: 0.5,
duration: 0.8,
},
},
hover: {
scale: 1.02,
transition: { duration: 0.3 },
width: "120px",
backgroundColor: "#00e1ff",
},
};
const buttonContainerVariants: Variants = {
...itemVariants,
hover: {
scale: 1.05,
transition: {
type: "spring",
stiffness: 400,
},
},
};
@ -42,46 +76,57 @@ const AboutUs = () => {
color: "#fff",
py: { xs: 8, md: 12 },
px: 3,
overflow: "hidden",
}}
>
<Box
component={motion.div}
variants={containerVariants}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-100px" }}
textAlign="center"
maxWidth={800}
mx="auto"
animate="visible"
viewport={{ once: true }}
sx={{
textAlign: "center",
maxWidth: 800,
mx: "auto",
}}
>
<Box component={motion.div} variants={itemVariants} whileHover="hover">
{/* Title Section */}
<Box
component={motion.div}
variants={titleVariants}
whileHover="hover"
sx={{ mb: 4 }}
>
<Typography
variant="h2"
gutterBottom
sx={{
fontFamily: "'Cormorant Garamond', serif",
fontWeight: 600,
fontSize: { xs: "2.5rem", md: "3rem" },
letterSpacing: "1px",
mb: 4,
position: "relative",
"&:after": {
content: '""',
display: "block",
width: "80px",
height: "3px",
background: "linear-gradient(90deg, #00FFD1, transparent)",
margin: "20px auto 0",
borderRadius: "2px",
},
textShadow: "0 0 8px rgba(0, 225, 255, 0.3)",
}}
>
About Us
<Box
component={motion.div}
variants={underlineVariants}
initial="hidden"
animate="visible"
whileHover="hover"
sx={{
height: "3px",
background: "linear-gradient(90deg, #00e1ff, transparent)",
margin: "20px auto 0",
borderRadius: "2px",
}}
/>
</Typography>
</Box>
<Box component={motion.div} variants={itemVariants}>
{/* Content Section */}
<Box component={motion.div} variants={itemVariants} sx={{ mb: 4 }}>
<Typography
paragraph
sx={{
@ -89,41 +134,67 @@ const AboutUs = () => {
fontSize: { xs: "1rem", md: "1.1rem" },
lineHeight: 1.9,
fontWeight: 300,
mb: 4,
color: "rgba(255,255,255,0.85)",
}}
>
Lorem ipsum dolor sit amet consectetur. Nisl sed sed tortor eros.
Enim hendrerit elit interdum malesuada sit dis est pharetra
suspendisse. In dolor venenatis ultricies aliquet lacinia. Faucibus
commodo eu gravida auctor eu et sit ut. Sed praesent sed odio
aliquam in fermentum. Sit vitae morbi sodales sem velit eu tempus
velit nunc. Turpis in in luctus et nulla purus nibh ut. Enim sed
fermentum purus molestie parturient morbi nunc aliquet. Aliquam sed
etiam turpis non lectus commodo cras leo gravida.
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ipsum
repellendus aperiam, nobis debitis nam nemo dolorum! Suscipit
voluptatibus eum tenetur accusantium eveniet iure, optio illum
minima, quo mollitia vitae dolorem.
</Typography>
</Box>
<Box component={motion.div} variants={itemVariants} whileHover="hover">
{/* Button Section */}
<Box
component={motion.div}
variants={buttonContainerVariants}
whileHover="hover"
>
<Button
variant="outlined"
endIcon={<ArrowOutwardIcon />}
endIcon={
<motion.div
animate={{ x: [0, 5, 0] }}
transition={{
duration: 1.5,
repeat: Infinity,
ease: "easeInOut",
}}
>
<ArrowOutwardIcon />
</motion.div>
}
sx={{
mt: 2,
borderColor: "#00FFD1",
color: "#00FFD1",
borderColor: "#00e1ff",
color: "#00e1ff",
borderRadius: "30px",
fontWeight: 500,
px: 4,
py: 1.5,
px: 3,
py: 1.1,
fontFamily: "'Montserrat', sans-serif",
letterSpacing: "1px",
fontSize: "0.9rem",
transition: "all 0.3s ease",
textTransform: "uppercase",
position: "relative",
overflow: "hidden",
"&:hover": {
backgroundColor: "#00FFD1",
color: "#000",
boxShadow: "0 5px 15px rgba(0, 255, 209, 0.4)",
backgroundColor: "rgba(0, 225, 255, 0.1)",
boxShadow: "0 0 15px rgba(0, 225, 255, 0.4)",
"&::before": {
transform: "translateX(0)",
},
},
"&::before": {
content: '""',
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
background:
"linear-gradient(90deg, transparent, rgba(0, 225, 255, 0.2), transparent)",
transform: "translateX(-100%)",
transition: "transform 0.6s ease",
},
}}
>

View File

@ -192,8 +192,8 @@ const OurWorks = () => {
variant="outlined"
sx={{
borderRadius: "20px",
border: "1px solid #00FFD1",
color: "#00FFD1",
border: "1px solid #00E0FF",
color: "#00E0FF",
px: 4,
py: 1,
fontWeight: 600,
@ -202,8 +202,8 @@ const OurWorks = () => {
letterSpacing: 0.5,
fontFamily: "'Montserrat', sans-serif",
"&:hover": {
backgroundColor: "rgba(0, 255, 209, 0.1)",
border: "1px solid #00FFD1",
backgroundColor: "rgba(0, 225, 255, 0.19)",
border: "1px solid #00e1ff",
},
transition: "all 0.3s ease",
}}

View File

@ -3,98 +3,348 @@ import {
Box,
Card,
CardContent,
Grid,
Typography,
IconButton,
} from "@mui/material";
import { motion, AnimatePresence, useAnimation, Variants } from "framer-motion";
import { useEffect, useState } from "react";
import { KeyboardArrowLeft, KeyboardArrowRight } from "@mui/icons-material";
import testimonialImg from "../testomonials/b7bef0298c881712fbc6437106d2aaef27c4fad8.jpg";
const testimonials = [
{
name: "Name",
role: "Role",
company: "Company Name & Logo",
feedback:
"Lorem ipsum dolor sit amet consectetur. Vitae dictum quam senectus posuere sit justo est turpis interdum. Ut vitae platea et adipiscing nisl.",
name: "Sarah Johnson",
role: "Marketing Director",
company: "Tech Innovations Inc.",
feedback: "Working with this team transformed our digital presence.",
rating: 5,
},
{
name: "John Dae",
role: "Sr Manager",
name: "Michael Chen",
role: "Sr. Manager",
company: "Wells Fargo",
feedback:
"Lorem ipsum dolor sit amet consectetur. Vitae dictum quam senectus posuere sit justo est turpis interdum. Ut vitae platea et adipiscing nisl.",
feedback: "Exceptional service from start to finish.",
rating: 5,
},
{
name: "Name",
role: "Role",
company: "Company Name & Logo",
feedback:
"Lorem ipsum dolor sit amet consectetur. Vitae dictum quam senectus posuere sit justo est turpis interdum. Ut vitae platea et adipiscing nisl.",
name: "Emily Rodriguez",
role: "Product Owner",
company: "Nexus Enterprises",
feedback: "The team's technical expertise was outstanding.",
rating: 4,
},
];
// Properly typed animation variants
const containerVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.2,
duration: 0.8,
},
},
};
const itemVariants: Variants = {
hidden: { y: 50, opacity: 0 },
visible: {
y: 0,
opacity: 1,
transition: {
duration: 0.6,
ease: "easeOut", // Using string literal instead of array
},
},
hover: {
y: -10,
transition: { duration: 0.3 },
},
};
const Testimonials = () => {
const [currentIndex, setCurrentIndex] = useState(0);
const [isMobile, setIsMobile] = useState(false);
const controls = useAnimation();
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 600);
};
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
useEffect(() => {
if (!isMobile) return;
const timer = setInterval(() => {
handleNext();
}, 5000);
return () => clearInterval(timer);
}, [currentIndex, isMobile]);
const handleNext = () => {
controls
.start({
x: "-100%",
opacity: 0,
transition: { duration: 0.3 },
})
.then(() => {
setCurrentIndex((prev) => (prev + 1) % testimonials.length);
controls
.start({
x: "100%",
opacity: 0,
})
.then(() => {
controls.start({
x: 0,
opacity: 1,
transition: { duration: 0.5 },
});
});
});
};
const handlePrev = () => {
controls
.start({
x: "100%",
opacity: 0,
transition: { duration: 0.3 },
})
.then(() => {
setCurrentIndex(
(prev) => (prev - 1 + testimonials.length) % testimonials.length
);
controls
.start({
x: "-100%",
opacity: 0,
})
.then(() => {
controls.start({
x: 0,
opacity: 1,
transition: { duration: 0.5 },
});
});
});
};
return (
<Box sx={{ backgroundColor: "#1d2733", color: "#fff", py: 10, px: 3 }}>
<Box textAlign="center" mb={6}>
<Typography variant="h4" fontWeight="bold" gutterBottom>
<Box
sx={{
backgroundColor: "#1d2733",
color: "#fff",
py: { xs: 6, md: 10 },
px: { xs: 2, md: 3 },
overflow: "hidden",
}}
>
{/* Header Section */}
<Box
component={motion.div}
initial="hidden"
animate="visible"
variants={containerVariants}
textAlign="center"
mb={{ xs: 4, md: 6 }}
sx={{ maxWidth: 800, mx: "auto" }}
>
<Typography variant="h3" fontWeight="bold" gutterBottom>
Testimonials
</Typography>
<Typography variant="subtitle1">
Dont just take our word for it -- hear directly from our clients
Don't just take our word for it
</Typography>
</Box>
<Grid container spacing={4} justifyContent="center">
{testimonials.map((t, idx) => (
<Grid item xs={12} sm={6} md={4} key={idx}>
<Card
{/* Mobile Carousel */}
{isMobile ? (
<Box sx={{ position: "relative", height: 450 }}>
<AnimatePresence>
<Box
component={motion.div}
key={currentIndex}
animate={controls}
initial={{ x: 0, opacity: 1 }}
exit={{ x: 0, opacity: 0 }}
sx={{
borderRadius: 3,
maxWidth: 320,
margin: "0 auto",
textAlign: "center",
py: 3,
position: "absolute",
width: "100%",
display: "flex",
justifyContent: "center",
}}
>
<Avatar
src={testimonialImg}
alt={t.name}
sx={{ width: 100, height: 100, margin: "0 auto", mb: 2 }}
/>
<CardContent>
<Typography variant="subtitle1" fontWeight="bold">
{t.name} ,{" "}
<span style={{ fontWeight: "normal" }}>{t.role}</span>
</Typography>
<Typography variant="body2" color="text.secondary" mb={1}>
{t.company}
</Typography>
<Typography variant="body2" color="text.secondary" mb={2}>
{t.feedback}
</Typography>
<Box>
{Array.from({ length: 5 }).map((_, i) => (
<span
key={i}
style={{
color: i < t.rating ? "#00FFD1" : "#ccc",
fontSize: "1.2rem",
}}
>
</span>
))}
</Box>
</CardContent>
</Card>
</Grid>
))}
</Grid>
<TestimonialCard testimonial={testimonials[currentIndex]} />
</Box>
</AnimatePresence>
<NavigationArrows handlePrev={handlePrev} handleNext={handleNext} />
</Box>
) : (
/* Desktop Grid */
<Box
component={motion.div}
initial="hidden"
animate="visible"
variants={containerVariants}
sx={{
display: "flex",
justifyContent: "center",
flexWrap: "wrap",
gap: 4,
px: { md: 4 },
}}
>
{testimonials.map((t, idx) => (
<Box
key={idx}
component={motion.div}
variants={itemVariants}
whileHover="hover"
sx={{
width: { md: 350 },
flex: { md: "1 1 300px" },
}}
>
<TestimonialCard testimonial={t} />
</Box>
))}
</Box>
)}
</Box>
);
};
// Extracted Card Component
const TestimonialCard = ({
testimonial,
}: {
testimonial: (typeof testimonials)[0];
}) => (
<Card
sx={{
borderRadius: 3,
width: "100%",
minHeight: 400,
textAlign: "center",
py: 3,
px: 2,
background: "linear-gradient(145deg, #1d2733, #232f3e)",
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)",
border: "1px solid rgba(0, 225, 255, 0.1)",
transition: "all 0.3s ease",
"&:hover": {
boxShadow: "0 12px 40px rgba(0, 225, 255, 0.15)",
borderColor: "rgba(0, 225, 255, 0.3)",
transform: "translateY(-5px)",
},
}}
>
<Avatar
src={testimonialImg}
alt={testimonial.name}
sx={{
width: 80,
height: 80,
margin: "0 auto",
mb: 2,
border: "2px solid #00e1ff",
boxShadow: "0 0 15px rgba(0, 225, 255, 0.4)",
}}
/>
<CardContent>
<Typography variant="h6" fontWeight="bold" color="#00e1ff">
{testimonial.name}
</Typography>
<Typography variant="subtitle1" color="rgba(255,255,255,0.8)" mb={0.5}>
{testimonial.role}
</Typography>
<Typography variant="body2" color="rgba(255,255,255,0.6)" mb={2}>
{testimonial.company}
</Typography>
<Typography
variant="body1"
color="rgba(255,255,255,0.8)"
mb={3}
fontStyle="italic"
>
{testimonial.feedback}
</Typography>
<Box>
{Array.from({ length: 5 }).map((_, i) => (
<Box
component="span"
key={i}
sx={{
color:
i < testimonial.rating ? "#00e1ff" : "rgba(255,255,255,0.2)",
fontSize: "1.5rem",
mx: 0.5,
textShadow:
i < testimonial.rating
? "0 0 8px rgba(0, 225, 255, 0.5)"
: "none",
}}
>
</Box>
))}
</Box>
</CardContent>
</Card>
);
// Extracted Navigation Component
const NavigationArrows = ({
handlePrev,
handleNext,
}: {
handlePrev: () => void;
handleNext: () => void;
}) => (
<>
<IconButton
onClick={handlePrev}
sx={{
position: "absolute",
left: 10,
top: "50%",
transform: "translateY(-50%)",
color: "#00e1ff",
backgroundColor: "rgba(0, 225, 255, 0.1)",
"&:hover": {
backgroundColor: "rgba(0, 225, 255, 0.2)",
},
}}
>
<KeyboardArrowLeft fontSize="large" />
</IconButton>
<IconButton
onClick={handleNext}
sx={{
position: "absolute",
right: 10,
top: "50%",
transform: "translateY(-50%)",
color: "#00e1ff",
backgroundColor: "rgba(0, 225, 255, 0.1)",
"&:hover": {
backgroundColor: "rgba(0, 225, 255, 0.2)",
},
}}
>
<KeyboardArrowRight fontSize="large" />
</IconButton>
</>
);
export default Testimonials;