QuadraEdge/src/components/services/services.tsx

317 lines
11 KiB
TypeScript

import {
Box,
Card,
CardContent,
CardMedia,
Typography,
Container,
useMediaQuery,
useTheme,
Grid,
} from "@mui/material";
import { motion, AnimatePresence, PanInfo } from "framer-motion";
import { useState } from "react";
import serviceImage from "../services/Image Wrapper.png";
const services = [
{
title: "Design",
description:
"Lorem ipsum dolor sit amet consectetur. Non aliquam justo hendrerit vitae lacus. Cursus purus dictumst scelerisque vitae ultricies turpis aliquam turpis.",
image: `${serviceImage}`,
},
{
title: "Development",
description:
"Lorem ipsum dolor sit amet consectetur. Non aliquam justo hendrerit vitae lacus. Cursus purus dictumst scelerisque vitae ultricies turpis aliquam turpis.",
image: `${serviceImage}`,
},
{
title: "Marketing",
description:
"Lorem ipsum dolor sit amet consectetur. Non aliquam justo hendrerit vitae lacus. Cursus purus dictumst scelerisque vitae ultricies turpis aliquam turpis.",
image: `${serviceImage}`,
},
];
const Services = () => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("md"));
const [currentIndex, setCurrentIndex] = useState(0);
const [hoveredCard, setHoveredCard] = useState<number | null>(null);
const handleDragEnd = (
event: MouseEvent | TouchEvent | PointerEvent,
info: PanInfo
) => {
if (info.offset.x > 50) {
setCurrentIndex((prev) => (prev === 0 ? services.length - 1 : prev - 1));
} else if (info.offset.x < -50) {
setCurrentIndex((prev) => (prev === services.length - 1 ? 0 : prev + 1));
}
};
return (
<Box sx={{ backgroundColor: "#1d2733", color: "#fff", py: 8 }}>
<Container maxWidth="lg">
<motion.div
initial={{ opacity: 0, y: -20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
viewport={{ once: true, margin: "-100px" }}
>
<Typography
variant="h4"
align="center"
fontWeight="bold"
gutterBottom
sx={{ mb: 2 }}
>
Our Services
</Typography>
<Typography
variant="subtitle1"
align="center"
mb={6}
sx={{ maxWidth: 600, mx: "auto" }}
>
Professional solutions tailored to your needs
</Typography>
</motion.div>
{isMobile ? (
<Box sx={{ position: "relative", height: 380 }}>
<AnimatePresence initial={false}>
<motion.div
key={currentIndex}
drag="x"
onDragEnd={handleDragEnd}
dragConstraints={{ left: 0, right: 0 }}
initial={{ x: 300, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: -300, opacity: 0 }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
style={{
position: "absolute",
width: "100%",
padding: "0 16px",
}}
>
<motion.div
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<Card
sx={{
borderRadius: 2,
overflow: "hidden",
height: "100%",
bgcolor: "#fff",
display: "flex",
flexDirection: "column",
maxWidth: 300,
mx: "auto",
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
}}
>
<Box
sx={{
width: "100%",
height: 150,
display: "flex",
alignItems: "center",
justifyContent: "center",
bgcolor: "#f8f9fa",
overflow: "hidden",
}}
>
<motion.div
animate={{
scale: hoveredCard === currentIndex ? 1.05 : 1,
y: hoveredCard === currentIndex ? -5 : 0,
}}
transition={{ duration: 0.3 }}
style={{ width: "100%" }}
>
<CardMedia
component="img"
image={services[currentIndex].image}
alt={services[currentIndex].title}
sx={{
width: "100%",
height: "auto",
objectFit: "cover",
}}
/>
</motion.div>
</Box>
<CardContent sx={{ flexGrow: 1 }}>
<Typography
variant="h6"
fontWeight="bold"
gutterBottom
color="#000"
>
{services[currentIndex].title}
</Typography>
<Typography variant="body2" color="#000" sx={{ mb: 2 }}>
{services[currentIndex].description}
</Typography>
<motion.div
whileHover={{ x: 5 }}
transition={{ type: "spring", stiffness: 300 }}
>
<Typography
variant="caption"
color="primary"
fontWeight="bold"
sx={{ cursor: "pointer" }}
>
Learn more
</Typography>
</motion.div>
</CardContent>
</Card>
</motion.div>
</motion.div>
</AnimatePresence>
<Box
sx={{
display: "flex",
justifyContent: "center",
mt: 3,
gap: 1.5,
}}
>
{services.map((_, index) => (
<motion.div
key={index}
onClick={() => setCurrentIndex(index)}
whileHover={{ scale: 1.2 }}
whileTap={{ scale: 0.9 }}
>
<Box
sx={{
width: 10,
height: 10,
borderRadius: "50%",
bgcolor: index === currentIndex ? "#00E0FF" : "#ffffff80",
cursor: "pointer",
}}
/>
</motion.div>
))}
</Box>
</Box>
) : (
<Grid container spacing={3} justifyContent="center">
{services.map((service, index) => (
<Grid
item
xs={12}
sm={6}
md={4}
key={index}
sx={{ display: "flex", justifyContent: "center" }}
>
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
viewport={{ once: true, margin: "-100px" }}
onHoverStart={() => setHoveredCard(index)}
onHoverEnd={() => setHoveredCard(null)}
style={{ width: "100%", maxWidth: 280 }}
>
<motion.div
whileHover={{
y: -8,
boxShadow: "0 15px 30px -5px rgba(0, 0, 0, 0.2)",
}}
transition={{ type: "spring", stiffness: 400, damping: 10 }}
style={{ height: "100%" }}
>
<Card
sx={{
borderRadius: 2,
overflow: "hidden",
height: "100%",
bgcolor: "#fff",
display: "flex",
flexDirection: "column",
boxShadow: "0 5px 15px rgba(0, 0, 0, 0.1)",
width: "100%",
}}
>
<Box
sx={{
width: "100%",
height: 160,
display: "flex",
alignItems: "center",
justifyContent: "center",
bgcolor: "#f8f9fa",
overflow: "hidden",
}}
>
<motion.div
animate={{
scale: hoveredCard === index ? 1.1 : 1,
y: hoveredCard === index ? -5 : 0,
}}
transition={{ duration: 0.3 }}
style={{ width: "100%" }}
>
<CardMedia
component="img"
image={service.image}
alt={service.title}
sx={{
width: "100%",
height: "auto",
objectFit: "cover",
}}
/>
</motion.div>
</Box>
<CardContent sx={{ flexGrow: 1 }}>
<Typography
variant="h6"
fontWeight="bold"
gutterBottom
color="#000"
>
{service.title}
</Typography>
<Typography variant="body2" color="#000" sx={{ mb: 2 }}>
{service.description}
</Typography>
<motion.div
whileHover={{ x: 5 }}
transition={{ type: "spring", stiffness: 300 }}
>
<Typography
variant="caption"
color="primary"
fontWeight="bold"
sx={{ cursor: "pointer" }}
>
Learn more
</Typography>
</motion.div>
</CardContent>
</Card>
</motion.div>
</motion.div>
</Grid>
))}
</Grid>
)}
</Container>
</Box>
);
};
export default Services;