Merge pull request 'fix/landing_page' (#7) from fix/landing_page into main
continuous-integration/drone/push Build is passing
Details
Reviewed-on: #7 Reviewed-by: Mihir Motiyani <mihir@midastix.com>
|
|
@ -58,5 +58,6 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react-icons": "^2.2.7",
|
"@types/react-icons": "^2.2.7",
|
||||||
"@types/react-slick": "^0.23.13"
|
"@types/react-slick": "^0.23.13"
|
||||||
}
|
},
|
||||||
|
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 311 B |
|
After Width: | Height: | Size: 195 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 9.0 MiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 422 KiB |
|
After Width: | Height: | Size: 619 B |
|
After Width: | Height: | Size: 626 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1017 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 549 B |
|
After Width: | Height: | Size: 580 B |
|
After Width: | Height: | Size: 238 B |
|
After Width: | Height: | Size: 671 B |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 336 B |
|
After Width: | Height: | Size: 536 B |
|
After Width: | Height: | Size: 265 B |
|
After Width: | Height: | Size: 265 B |
|
After Width: | Height: | Size: 440 B |
|
After Width: | Height: | Size: 287 B |
|
After Width: | Height: | Size: 287 B |
|
After Width: | Height: | Size: 716 B |
|
|
@ -1,36 +1,200 @@
|
||||||
import { Box, Typography, Button } from "@mui/material";
|
import { Box, Typography, Button } from "@mui/material";
|
||||||
import ArrowOutwardIcon from "@mui/icons-material/ArrowOutward";
|
import ArrowOutwardIcon from "@mui/icons-material/ArrowOutward";
|
||||||
|
import { motion, Variants, Transition } from "framer-motion";
|
||||||
|
|
||||||
const AboutUs = () => {
|
const AboutUs = () => {
|
||||||
|
// Type-safe animation variants
|
||||||
|
const containerVariants: Variants = {
|
||||||
|
hidden: { opacity: 0 },
|
||||||
|
visible: {
|
||||||
|
opacity: 1,
|
||||||
|
transition: {
|
||||||
|
staggerChildren: 0.3,
|
||||||
|
duration: 0.8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemVariants: Variants = {
|
||||||
|
hidden: { y: 30, opacity: 0 },
|
||||||
|
visible: {
|
||||||
|
y: 0,
|
||||||
|
opacity: 1,
|
||||||
|
transition: {
|
||||||
|
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: {
|
||||||
|
width: "120px",
|
||||||
|
backgroundColor: "#00e1ff",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttonContainerVariants: Variants = {
|
||||||
|
...itemVariants,
|
||||||
|
hover: {
|
||||||
|
scale: 1.05,
|
||||||
|
transition: {
|
||||||
|
type: "spring",
|
||||||
|
stiffness: 400,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ backgroundColor: "#1d2733", color: "#fff", py: 10, px: 3 }}>
|
<Box
|
||||||
<Box textAlign="center" maxWidth={800} mx="auto">
|
component={motion.div}
|
||||||
<Typography variant="h4" fontWeight="bold" gutterBottom>
|
initial={{ opacity: 0 }}
|
||||||
|
whileInView={{ opacity: 1 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#1d2733",
|
||||||
|
color: "#fff",
|
||||||
|
py: { xs: 8, md: 12 },
|
||||||
|
px: 3,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
component={motion.div}
|
||||||
|
variants={containerVariants}
|
||||||
|
initial="hidden"
|
||||||
|
animate="visible"
|
||||||
|
viewport={{ once: true }}
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
maxWidth: 800,
|
||||||
|
mx: "auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Title Section */}
|
||||||
|
<Box
|
||||||
|
component={motion.div}
|
||||||
|
variants={titleVariants}
|
||||||
|
whileHover="hover"
|
||||||
|
sx={{ mb: 4 }}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h2"
|
||||||
|
sx={{
|
||||||
|
fontFamily: "'Cormorant Garamond', serif",
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: { xs: "2.5rem", md: "3rem" },
|
||||||
|
letterSpacing: "1px",
|
||||||
|
position: "relative",
|
||||||
|
textShadow: "0 0 8px rgba(0, 225, 255, 0.3)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
About Us
|
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>
|
</Typography>
|
||||||
<Typography variant="body1" paragraph>
|
</Box>
|
||||||
Lorem ipsum dolor sit amet consectetur. Nisl sed sed tortor eros. Enim
|
|
||||||
hendrerit elit interdum malesuada sit dis est pharetra suspendisse. In
|
{/* Content Section */}
|
||||||
dolor venenatis ultricies aliquet lacinia. Faucibus commodo eu gravida
|
<Box component={motion.div} variants={itemVariants} sx={{ mb: 4 }}>
|
||||||
auctor eu et sit ut. Sed praesent sed odio aliquam in fermentum. Sit
|
<Typography
|
||||||
vitae morbi sodales sem velit eu tempus velit nunc. Turpis in in
|
paragraph
|
||||||
luctus et nulla purus nibh ut. Enim sed fermentum purus molestie
|
sx={{
|
||||||
parturient morbi nunc aliquet. Aliquam sed etiam turpis non lectus
|
fontFamily: "'Montserrat', sans-serif",
|
||||||
commodo cras leo gravida.
|
fontSize: { xs: "1rem", md: "1.1rem" },
|
||||||
|
lineHeight: 1.9,
|
||||||
|
fontWeight: 300,
|
||||||
|
color: "rgba(255,255,255,0.85)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
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>
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Button Section */}
|
||||||
|
<Box
|
||||||
|
component={motion.div}
|
||||||
|
variants={buttonContainerVariants}
|
||||||
|
whileHover="hover"
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
endIcon={<ArrowOutwardIcon />}
|
endIcon={
|
||||||
|
<motion.div
|
||||||
|
animate={{ x: [0, 5, 0] }}
|
||||||
|
transition={{
|
||||||
|
duration: 1.5,
|
||||||
|
repeat: Infinity,
|
||||||
|
ease: "easeInOut",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ArrowOutwardIcon />
|
||||||
|
</motion.div>
|
||||||
|
}
|
||||||
sx={{
|
sx={{
|
||||||
mt: 2,
|
borderColor: "#00e1ff",
|
||||||
borderColor: "#00FFD1",
|
color: "#00e1ff",
|
||||||
color: "#00FFD1",
|
|
||||||
borderRadius: "30px",
|
borderRadius: "30px",
|
||||||
fontWeight: "bold",
|
fontWeight: 500,
|
||||||
px: 4,
|
px: 3,
|
||||||
|
py: 1.1,
|
||||||
|
fontFamily: "'Montserrat', sans-serif",
|
||||||
|
letterSpacing: "1px",
|
||||||
|
fontSize: "0.9rem",
|
||||||
|
textTransform: "uppercase",
|
||||||
|
position: "relative",
|
||||||
|
overflow: "hidden",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: "#00FFD1",
|
backgroundColor: "rgba(0, 225, 255, 0.1)",
|
||||||
color: "#000",
|
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",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -38,6 +202,7 @@ const AboutUs = () => {
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,92 +1,294 @@
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
Box, Container, Grid, Typography, Link, Divider, Stack, useMediaQuery, useTheme
|
Box,
|
||||||
} from '@mui/material';
|
Container,
|
||||||
import {
|
Grid,
|
||||||
Instagram, YouTube, Facebook, LinkedIn
|
Typography,
|
||||||
} from '@mui/icons-material';
|
Link,
|
||||||
import { motion } from 'framer-motion';
|
Divider,
|
||||||
|
Stack,
|
||||||
|
useMediaQuery,
|
||||||
|
useTheme,
|
||||||
|
} from "@mui/material";
|
||||||
|
import { Instagram, YouTube, Facebook, LinkedIn } from "@mui/icons-material";
|
||||||
|
import { motion, Variants } from "framer-motion";
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.between("sm", "md"));
|
||||||
|
|
||||||
|
// Animation variants
|
||||||
|
const containerVariants: Variants = {
|
||||||
|
hidden: { opacity: 0 },
|
||||||
|
visible: {
|
||||||
|
opacity: 1,
|
||||||
|
transition: {
|
||||||
|
staggerChildren: 0.1,
|
||||||
|
when: "beforeChildren",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemVariants: Variants = {
|
||||||
|
hidden: { y: 20, opacity: 0 },
|
||||||
|
visible: {
|
||||||
|
y: 0,
|
||||||
|
opacity: 1,
|
||||||
|
transition: {
|
||||||
|
duration: 0.5,
|
||||||
|
ease: "easeOut",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
scale: 1.05,
|
||||||
|
color: "#00E0FF",
|
||||||
|
transition: { duration: 0.2 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const socialIconVariants: Variants = {
|
||||||
|
hidden: { scale: 0 },
|
||||||
|
visible: {
|
||||||
|
scale: 1,
|
||||||
|
transition: {
|
||||||
|
type: "spring",
|
||||||
|
stiffness: 500,
|
||||||
|
damping: 15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
scale: 1.2,
|
||||||
|
transition: { duration: 0.2 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ backgroundColor: '#0F111A', color: '#fff', pt: 6, pb: 2 }}>
|
<Box
|
||||||
|
component="footer"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#0F111A",
|
||||||
|
color: "#fff",
|
||||||
|
pt: 8,
|
||||||
|
pb: 4,
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Container maxWidth="lg">
|
<Container maxWidth="lg">
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 10 }}
|
initial="hidden"
|
||||||
animate={{ opacity: 1, y: 0 }}
|
whileInView="visible"
|
||||||
transition={{ duration: 0.8 }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
|
variants={containerVariants}
|
||||||
>
|
>
|
||||||
<Grid container spacing={4}>
|
<Grid container spacing={isMobile ? 3 : 4}>
|
||||||
{/* Column 1: Explore Links */}
|
{/* Column 1: Explore Links */}
|
||||||
<Grid item xs={12} sm={6} md={3}>
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<Typography
|
||||||
|
component={motion.div}
|
||||||
|
variants={itemVariants}
|
||||||
|
variant="h6"
|
||||||
|
fontWeight={600}
|
||||||
|
gutterBottom
|
||||||
|
sx={{ color: "#00E0FF" }}
|
||||||
|
>
|
||||||
|
Explore
|
||||||
|
</Typography>
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
<Link href="#" color="inherit" underline="hover">About Us</Link>
|
{["About Us", "Portfolio", "Blogs", "Services"].map((item) => (
|
||||||
<Link href="#" color="inherit" underline="hover">Portfolio</Link>
|
<Link
|
||||||
<Link href="#" color="inherit" underline="hover">Blogs</Link>
|
key={item}
|
||||||
<Link href="#" color="inherit" underline="hover">Services</Link>
|
component={motion.a}
|
||||||
|
variants={itemVariants}
|
||||||
|
whileHover="hover"
|
||||||
|
href="#"
|
||||||
|
color="inherit"
|
||||||
|
underline="hover"
|
||||||
|
sx={{
|
||||||
|
display: "inline-block",
|
||||||
|
transition: "color 0.2s ease",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* Column 2: Support Links */}
|
{/* Column 2: Support Links */}
|
||||||
<Grid item xs={12} sm={6} md={3}>
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<Typography
|
||||||
|
component={motion.div}
|
||||||
|
variants={itemVariants}
|
||||||
|
variant="h6"
|
||||||
|
fontWeight={600}
|
||||||
|
gutterBottom
|
||||||
|
sx={{ color: "#00E0FF" }}
|
||||||
|
>
|
||||||
|
Support
|
||||||
|
</Typography>
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
<Link href="#" color="inherit" underline="hover">FAQ’s</Link>
|
{["FAQ’s", "Terms & Conditions", "Privacy Policy"].map(
|
||||||
<Link href="#" color="inherit" underline="hover">Terms & Conditions</Link>
|
(item) => (
|
||||||
<Link href="#" color="inherit" underline="hover">Privacy Policy</Link>
|
<Link
|
||||||
|
key={item}
|
||||||
|
component={motion.a}
|
||||||
|
variants={itemVariants}
|
||||||
|
whileHover="hover"
|
||||||
|
href="#"
|
||||||
|
color="inherit"
|
||||||
|
underline="hover"
|
||||||
|
sx={{
|
||||||
|
display: "inline-block",
|
||||||
|
transition: "color 0.2s ease",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* Column 3: Logo (only visible on md+) */}
|
{/* Column 3: Logo */}
|
||||||
{!isMobile && (
|
|
||||||
<Grid item xs={12} sm={6} md={3}>
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
<Box sx={{ display: 'flex', justifyContent: { sm: 'center', md: 'flex-end' }, mb: 2 }}>
|
<Box
|
||||||
<img
|
component={motion.div}
|
||||||
src="/logo.png" // Replace with actual logo
|
variants={itemVariants}
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: isMobile
|
||||||
|
? "flex-start"
|
||||||
|
: isTablet
|
||||||
|
? "center"
|
||||||
|
: "flex-end",
|
||||||
|
mb: 2,
|
||||||
|
height: "100%",
|
||||||
|
alignItems: isMobile ? "flex-start" : "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<motion.img
|
||||||
|
initial={{ scale: 0 }}
|
||||||
|
animate={{ scale: 1 }}
|
||||||
|
transition={{
|
||||||
|
type: "spring",
|
||||||
|
stiffness: 300,
|
||||||
|
damping: 15,
|
||||||
|
delay: 0.2,
|
||||||
|
}}
|
||||||
|
src="/logo.png"
|
||||||
alt="Quadra Edge"
|
alt="Quadra Edge"
|
||||||
style={{ maxWidth: '180px', height: 'auto' }}
|
style={{
|
||||||
|
maxWidth: isMobile ? "140px" : "180px",
|
||||||
|
height: "auto",
|
||||||
|
filter: "drop-shadow(0 0 8px rgba(0, 224, 255, 0.4))",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Column 4: Contact Info + Socials */}
|
{/* Column 4: Contact Info + Socials */}
|
||||||
<Grid item xs={12} sm={6} md={3}>
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
{/* Mobile: show logo here instead */}
|
<Typography
|
||||||
{isMobile && (
|
component={motion.div}
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end', mb: 2 }}>
|
variants={itemVariants}
|
||||||
<img
|
variant="h6"
|
||||||
src="/logo.png" // Replace with actual logo
|
fontWeight={600}
|
||||||
alt="Quadra Edge"
|
gutterBottom
|
||||||
style={{ maxWidth: '180px', height: 'auto' }}
|
sx={{ color: "#00E0FF" }}
|
||||||
/>
|
>
|
||||||
</Box>
|
Contact Us
|
||||||
)}
|
</Typography>
|
||||||
|
|
||||||
<Typography fontWeight={600} gutterBottom>Contact Us</Typography>
|
<Typography
|
||||||
<Typography variant="body2" mb={1}>Number</Typography>
|
component={motion.div}
|
||||||
<Typography variant="body2">Address</Typography>
|
variants={itemVariants}
|
||||||
|
variant="body2"
|
||||||
|
mb={1}
|
||||||
|
>
|
||||||
|
+1 (123) 456-7890
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
component={motion.div}
|
||||||
|
variants={itemVariants}
|
||||||
|
variant="body2"
|
||||||
|
>
|
||||||
|
123 Business Ave, Suite 100
|
||||||
|
<br />
|
||||||
|
New York, NY 10001
|
||||||
|
</Typography>
|
||||||
|
|
||||||
<Stack
|
<Stack
|
||||||
direction="row"
|
direction="row"
|
||||||
spacing={2}
|
spacing={2}
|
||||||
sx={{ mt: 2 }}
|
sx={{ mt: 3 }}
|
||||||
|
component={motion.div}
|
||||||
|
variants={containerVariants}
|
||||||
>
|
>
|
||||||
<Link href="#"><Instagram sx={{ color: '#00E0FF' }} /></Link>
|
{[
|
||||||
<Link href="#"><YouTube sx={{ color: '#00E0FF' }} /></Link>
|
{ icon: <Instagram />, name: "Instagram" },
|
||||||
<Link href="#"><Facebook sx={{ color: '#00E0FF' }} /></Link>
|
{ icon: <YouTube />, name: "YouTube" },
|
||||||
<Link href="#"><LinkedIn sx={{ color: '#00E0FF' }} /></Link>
|
{ icon: <Facebook />, name: "Facebook" },
|
||||||
|
{ icon: <LinkedIn />, name: "LinkedIn" },
|
||||||
|
].map((social, index) => (
|
||||||
|
<Link
|
||||||
|
key={social.name}
|
||||||
|
component={motion.a}
|
||||||
|
variants={socialIconVariants}
|
||||||
|
whileHover="hover"
|
||||||
|
href="#"
|
||||||
|
sx={{
|
||||||
|
color: "#00E0FF",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
aria-label={social.name}
|
||||||
|
>
|
||||||
|
{React.cloneElement(social.icon, {
|
||||||
|
sx: {
|
||||||
|
fontSize: isMobile ? "1.8rem" : "2rem",
|
||||||
|
transition: "transform 0.2s ease",
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Divider sx={{ my: 4, borderColor: '#00E0FF' }} />
|
<Divider
|
||||||
|
component={motion.hr}
|
||||||
|
initial={{ scaleX: 0 }}
|
||||||
|
whileInView={{ scaleX: 1 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.8, delay: 0.2 }}
|
||||||
|
sx={{
|
||||||
|
my: 4,
|
||||||
|
borderColor: "#00E0FF",
|
||||||
|
borderBottomWidth: 2,
|
||||||
|
opacity: 0.6,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<Box textAlign="center">
|
<Box
|
||||||
<Typography variant="body2" sx={{ color: '#00E0FF' }}>
|
component={motion.div}
|
||||||
Copyright © 2025 QuadraEdge
|
initial={{ opacity: 0 }}
|
||||||
|
whileInView={{ opacity: 1 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.4 }}
|
||||||
|
textAlign="center"
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
color: "#00E0FF",
|
||||||
|
fontSize: isMobile ? "0.8rem" : "0.9rem",
|
||||||
|
letterSpacing: "0.5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Copyright © {new Date().getFullYear()} QuadraEdge. All rights
|
||||||
|
reserved.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,9 @@ import React, { useState } from "react";
|
||||||
import {
|
import {
|
||||||
AppBar,
|
AppBar,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
Typography,
|
|
||||||
IconButton,
|
IconButton,
|
||||||
Drawer,
|
Drawer,
|
||||||
List,
|
List,
|
||||||
ListItem,
|
|
||||||
ListItemText,
|
ListItemText,
|
||||||
Button,
|
Button,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
|
|
@ -14,39 +12,68 @@ import {
|
||||||
Box,
|
Box,
|
||||||
Container,
|
Container,
|
||||||
ListItemButton,
|
ListItemButton,
|
||||||
|
Divider,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import MenuIcon from "@mui/icons-material/Menu";
|
import MenuIcon from "@mui/icons-material/Menu";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
|
import HomeIcon from "@mui/icons-material/Home";
|
||||||
|
import BuildIcon from "@mui/icons-material/Build";
|
||||||
|
import WorkIcon from "@mui/icons-material/Work";
|
||||||
|
import InfoIcon from "@mui/icons-material/Info";
|
||||||
|
import ArticleIcon from "@mui/icons-material/Article";
|
||||||
|
import logo from "../QE Website design/Logo.png";
|
||||||
|
|
||||||
const navItems = ["Home", "Services", "Portfolio", "About Us", "Blog"];
|
const navItems = [
|
||||||
|
{ label: "Home", icon: <HomeIcon />, href: "#" },
|
||||||
|
{ label: "Services", icon: <BuildIcon />, href: "#" },
|
||||||
|
{ label: "Portfolio", icon: <WorkIcon />, href: "#" },
|
||||||
|
{ label: "About Us", icon: <InfoIcon />, href: "#" },
|
||||||
|
{ label: "Blog", icon: <ArticleIcon />, href: "#" },
|
||||||
|
];
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
const [mobileOpen, setMobileOpen] = useState(false);
|
const [mobileOpen, setMobileOpen] = useState(false);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down("md"));
|
const isMobile = useMediaQuery(theme.breakpoints.down("md"));
|
||||||
|
|
||||||
const toggleDrawer = () => {
|
const toggleDrawer = () => setMobileOpen(!mobileOpen);
|
||||||
setMobileOpen(!mobileOpen);
|
|
||||||
};
|
|
||||||
|
|
||||||
const drawer = (
|
const drawer = (
|
||||||
<Box sx={{ width: 250, backgroundColor: "#000" }} onClick={toggleDrawer}>
|
<Box
|
||||||
<List>
|
sx={{ width: 260, height: "100%", backgroundColor: "#000" }}
|
||||||
|
onClick={toggleDrawer}
|
||||||
|
>
|
||||||
|
<ListItemButton
|
||||||
|
component="a"
|
||||||
|
href="#"
|
||||||
|
sx={{ justifyContent: "center", my: 2 }}
|
||||||
|
>
|
||||||
|
<Box component="img" src={logo} alt="Logo" sx={{ height: 40 }} />
|
||||||
|
</ListItemButton>
|
||||||
|
<Divider sx={{ backgroundColor: "#444" }} />
|
||||||
|
<Box>
|
||||||
{navItems.map((item) => (
|
{navItems.map((item) => (
|
||||||
<ListItemButton component="a" href="#" key={item}>
|
<ListItemButton component="a" href={item.href} key={item.label}>
|
||||||
<ListItemText primary={item} sx={{ color: "#fff" }} />
|
<Box
|
||||||
|
sx={{ display: "flex", alignItems: "center", color: "#00E0FF" }}
|
||||||
|
>
|
||||||
|
<Box sx={{ mr: 2 }}>{item.icon}</Box>
|
||||||
|
<ListItemText primary={item.label} sx={{ color: "#fff" }} />
|
||||||
|
</Box>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
))}
|
))}
|
||||||
<ListItem disablePadding>
|
</Box>
|
||||||
|
<Divider sx={{ backgroundColor: "#444", my: 2 }} />
|
||||||
|
<Box px={2}>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{
|
sx={{
|
||||||
borderColor: "#00E0FF",
|
borderColor: "#00E0FF",
|
||||||
color: "#00E0FF",
|
color: "#00E0FF",
|
||||||
backgroundColor: "transparent",
|
borderRadius: "24px",
|
||||||
borderRadius: "8px",
|
fontWeight: 600,
|
||||||
m: 2,
|
textTransform: "none",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: "#00E0FF",
|
backgroundColor: "#00E0FF",
|
||||||
color: "#000",
|
color: "#000",
|
||||||
|
|
@ -55,8 +82,7 @@ const Header = () => {
|
||||||
>
|
>
|
||||||
Contact Us
|
Contact Us
|
||||||
</Button>
|
</Button>
|
||||||
</ListItem>
|
</Box>
|
||||||
</List>
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -66,20 +92,10 @@ const Header = () => {
|
||||||
sx={{ backgroundColor: "#000", boxShadow: "none" }}
|
sx={{ backgroundColor: "#000", boxShadow: "none" }}
|
||||||
>
|
>
|
||||||
<Container maxWidth="lg">
|
<Container maxWidth="lg">
|
||||||
<Toolbar sx={{ justifyContent: "space-between", padding: "16px 0" }}>
|
<Toolbar sx={{ justifyContent: "space-between", py: 1.5 }}>
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0, y: -10 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 0.6 }}
|
|
||||||
>
|
|
||||||
<Typography variant="h6" sx={{ fontWeight: 700, color: "#fff" }}>
|
|
||||||
QUADRA EDGE
|
|
||||||
</Typography>
|
|
||||||
</motion.div>
|
|
||||||
|
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<>
|
<>
|
||||||
<IconButton color="inherit" edge="end" onClick={toggleDrawer}>
|
<IconButton edge="end" onClick={toggleDrawer}>
|
||||||
<MenuIcon sx={{ color: "#fff" }} />
|
<MenuIcon sx={{ color: "#fff" }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Drawer
|
<Drawer
|
||||||
|
|
@ -92,44 +108,78 @@ const Header = () => {
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Left - Logo */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -10 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
component="a"
|
||||||
|
href="#"
|
||||||
|
sx={{ display: "flex", alignItems: "center" }}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={logo}
|
||||||
|
alt="Logo"
|
||||||
|
sx={{ height: 40, width: "auto", objectFit: "contain" }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Center - Navigation */}
|
||||||
<Box sx={{ display: "flex", gap: 4, alignItems: "center" }}>
|
<Box sx={{ display: "flex", gap: 4, alignItems: "center" }}>
|
||||||
{navItems.map((item, index) => (
|
{navItems.map((item, index) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={item}
|
key={item.label}
|
||||||
initial={{ opacity: 0, y: -5 }}
|
initial={{ opacity: 0, y: -5 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ delay: 0.1 * index }}
|
transition={{ delay: 0.1 * index }}
|
||||||
>
|
>
|
||||||
<Typography
|
<Box
|
||||||
variant="body1"
|
|
||||||
component="a"
|
component="a"
|
||||||
href="#"
|
href={item.href}
|
||||||
sx={{
|
sx={{
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: "1rem",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
color: "#00E0FF",
|
color: "#00E0FF",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item}
|
{item.label}
|
||||||
</Typography>
|
</Box>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Right - Contact Us */}
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: -5 }}
|
initial={{ opacity: 0, x: 10 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
transition={{ delay: 0.5 }}
|
transition={{ duration: 0.6 }}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
borderColor: "#00E0FF",
|
borderColor: "#00E0FF",
|
||||||
color: "#00E0FF",
|
color: "#00E0FF",
|
||||||
backgroundColor: "transparent",
|
borderRadius: "24px",
|
||||||
borderRadius: "8px",
|
|
||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
padding: "8px 24px",
|
fontWeight: 600,
|
||||||
|
px: 3,
|
||||||
|
py: 1,
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: "#00E0FF",
|
backgroundColor: "#00E0FF",
|
||||||
color: "#000",
|
color: "#000",
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,63 @@
|
||||||
import { Box, Button, Container, Grid, Typography } from "@mui/material";
|
import { Box, Button, Container, Grid, Typography } from "@mui/material";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import backgroundImg from "../hero/Frame 22.png";
|
import backgroundImg from "../hero/Frame 22.png";
|
||||||
|
|
||||||
export default function Hero() {
|
export default function Hero() {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ backgroundColor: "#0F111A", color: "#fff", py: 10 }}>
|
<Box sx={{ backgroundColor: "#0F111A", color: "#fff", py: 10 }}>
|
||||||
<Container maxWidth="lg">
|
<Container maxWidth="lg">
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: -20 }}
|
initial={{ opacity: 0, y: -30 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.8 }}
|
transition={{ duration: 1 }}
|
||||||
|
>
|
||||||
|
<Grid container spacing={4} alignItems="center">
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<Box>
|
||||||
|
<Typography
|
||||||
|
variant="h2"
|
||||||
|
fontWeight="bold"
|
||||||
|
gutterBottom
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: "2rem", sm: "2.8rem", md: "3.4rem" },
|
||||||
|
lineHeight: 1.2,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Grid container>
|
|
||||||
<Grid item md={6}>
|
|
||||||
<Typography variant="h3" fontWeight="bold" gutterBottom>
|
|
||||||
We Create <br />
|
We Create <br />
|
||||||
Brands That Stick
|
Brands That Stick
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
|
{/* Sliding second line after 7s */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: 50 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: 7, duration: 1 }}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h5"
|
||||||
|
sx={{
|
||||||
|
mt: 2,
|
||||||
|
fontWeight: 300,
|
||||||
|
color: "#00E0FF",
|
||||||
|
fontStyle: "italic",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
"Let your brand speak before you do."
|
||||||
|
</Typography>
|
||||||
|
</motion.div>
|
||||||
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={6}>
|
|
||||||
<Typography variant="body1" maxWidth="sm">
|
<Grid item xs={12} md={6}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 1, duration: 1 }}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
sx={{ maxWidth: "500px", fontSize: "1.1rem", color: "#ccc" }}
|
||||||
|
>
|
||||||
We help founders grow through bold design, sharp strategy, and
|
We help founders grow through bold design, sharp strategy, and
|
||||||
smart marketing that drives recognition, engagement and
|
smart marketing that drives recognition, engagement and
|
||||||
long-term brand loyalty.
|
long-term brand loyalty.
|
||||||
|
|
@ -29,6 +68,11 @@ export default function Hero() {
|
||||||
mt: 4,
|
mt: 4,
|
||||||
borderColor: "#00E0FF",
|
borderColor: "#00E0FF",
|
||||||
color: "#00E0FF",
|
color: "#00E0FF",
|
||||||
|
borderRadius: "24px",
|
||||||
|
px: 4,
|
||||||
|
py: 1.5,
|
||||||
|
textTransform: "none",
|
||||||
|
fontWeight: 600,
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: "#00E0FF",
|
backgroundColor: "#00E0FF",
|
||||||
color: "#000",
|
color: "#000",
|
||||||
|
|
@ -37,12 +81,21 @@ export default function Hero() {
|
||||||
>
|
>
|
||||||
Get in Touch
|
Get in Touch
|
||||||
</Button>
|
</Button>
|
||||||
|
</motion.div>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</Container>
|
</Container>
|
||||||
<Box width="100%">
|
|
||||||
<img src={backgroundImg} alt="" width={"100%"} />
|
<Box width="100%" mt={8}>
|
||||||
|
<motion.img
|
||||||
|
src={backgroundImg}
|
||||||
|
alt="Hero Background"
|
||||||
|
width="100%"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ delay: 1.5, duration: 1 }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -6,109 +6,213 @@ import {
|
||||||
Grid,
|
Grid,
|
||||||
Typography,
|
Typography,
|
||||||
Button,
|
Button,
|
||||||
|
Container,
|
||||||
|
useMediaQuery,
|
||||||
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
import portfolioImg from "../ourwork/Rectangle 6.png";
|
import portfolioImg from "../ourwork/Rectangle 6.png";
|
||||||
|
|
||||||
const works = [
|
const works = [
|
||||||
{
|
{
|
||||||
title: "Project Name",
|
title: "Project Aurora",
|
||||||
image: portfolioImg,
|
image: portfolioImg,
|
||||||
|
description: "Modern web design with seamless user experience",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Project Name",
|
title: "Project Nexus",
|
||||||
image: portfolioImg,
|
image: portfolioImg,
|
||||||
|
description: "Mobile application development for enterprise",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Project Name",
|
title: "Project Horizon",
|
||||||
image: portfolioImg,
|
image: portfolioImg,
|
||||||
|
description: "Brand identity and marketing campaign",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const OurWorks = () => {
|
const OurWorks = () => {
|
||||||
return (
|
const theme = useTheme();
|
||||||
<Box sx={{ backgroundColor: "#1d2733", color: "#fff", py: 8, px: 2 }}>
|
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||||
<Typography variant="h4" align="center" fontWeight="bold" gutterBottom>
|
|
||||||
Our Works
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="subtitle1" align="center" mb={6}>
|
|
||||||
We’ve helped brands grow through bold strategy and creative execution.
|
|
||||||
Explore our recent success stories.
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Grid container spacing={4} justifyContent="center">
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#1d2733",
|
||||||
|
color: "#fff",
|
||||||
|
py: 8,
|
||||||
|
px: { xs: 2, sm: 4 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Container maxWidth="md">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: -20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
align="center"
|
||||||
|
fontWeight={700}
|
||||||
|
gutterBottom
|
||||||
|
sx={{
|
||||||
|
mb: 2,
|
||||||
|
fontFamily: "'Montserrat', sans-serif",
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Our Portfolio
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="subtitle1"
|
||||||
|
align="center"
|
||||||
|
mb={6}
|
||||||
|
sx={{
|
||||||
|
maxWidth: 600,
|
||||||
|
mx: "auto",
|
||||||
|
color: "rgba(255,255,255,0.8)",
|
||||||
|
fontFamily: "'Open Sans', sans-serif",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
We craft digital experiences that drive results
|
||||||
|
</Typography>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<Grid container spacing={isMobile ? 3 : 4} justifyContent="center">
|
||||||
{works.map((work, index) => (
|
{works.map((work, index) => (
|
||||||
<Grid item xs={12} sm={6} md={4} key={index}>
|
<Grid item xs={12} sm={6} md={4} key={index}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
whileHover={{ y: -5 }}
|
||||||
|
>
|
||||||
<Card
|
<Card
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: 3,
|
borderRadius: 2,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
bgcolor: "#fff",
|
bgcolor: "#fff",
|
||||||
maxWidth: 320,
|
maxWidth: 320,
|
||||||
margin: "0 auto",
|
height: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
|
||||||
|
transition: "all 0.3s ease",
|
||||||
|
"&:hover": {
|
||||||
|
boxShadow: "0 8px 24px rgba(0,0,0,0.12)",
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
elevation={3}
|
|
||||||
>
|
>
|
||||||
<CardContent>
|
<Box
|
||||||
<Typography
|
sx={{
|
||||||
variant="subtitle1"
|
height: 180,
|
||||||
fontWeight="bold"
|
display: "flex",
|
||||||
color="Black"
|
alignItems: "center",
|
||||||
gutterBottom
|
justifyContent: "center",
|
||||||
|
bgcolor: "#f8f9fa",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{work.title}
|
|
||||||
</Typography>
|
|
||||||
</CardContent>
|
|
||||||
<CardMedia
|
<CardMedia
|
||||||
component="img"
|
component="img"
|
||||||
image={work.image}
|
image={work.image}
|
||||||
alt={work.title}
|
alt={work.title}
|
||||||
sx={{
|
sx={{
|
||||||
|
width: "90%",
|
||||||
|
height: "90%",
|
||||||
objectFit: "contain",
|
objectFit: "contain",
|
||||||
height: 250,
|
transition: "transform 0.3s ease",
|
||||||
px: 2,
|
"&:hover": {
|
||||||
|
transform: "scale(1.05)",
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<CardContent>
|
</Box>
|
||||||
<Button
|
<CardContent sx={{ flexGrow: 1, px: 3, py: 2 }}>
|
||||||
variant="contained"
|
<Typography
|
||||||
fullWidth
|
variant="h6"
|
||||||
|
fontWeight={600}
|
||||||
|
color="#000"
|
||||||
|
gutterBottom
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#000",
|
fontFamily: "'Montserrat', sans-serif",
|
||||||
color: "#00FFD1",
|
fontSize: "1.1rem",
|
||||||
fontWeight: "bold",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: "#333",
|
|
||||||
},
|
|
||||||
borderRadius: "30px",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
VIEW DEMO
|
{work.title}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="#000"
|
||||||
|
sx={{
|
||||||
|
mb: 2,
|
||||||
|
fontFamily: "'Open Sans', sans-serif",
|
||||||
|
fontSize: "0.875rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{work.description}
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
<CardContent sx={{ px: 3, py: 0, pb: 3 }}>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
borderRadius: "20px",
|
||||||
|
border: "1px solid #000",
|
||||||
|
color: "#000",
|
||||||
|
fontWeight: 600,
|
||||||
|
py: 1,
|
||||||
|
fontSize: "0.8rem",
|
||||||
|
textTransform: "none",
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
fontFamily: "'Montserrat', sans-serif",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "#000",
|
||||||
|
color: "#fff",
|
||||||
|
border: "1px solid #000",
|
||||||
|
},
|
||||||
|
transition: "all 0.3s ease",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
View Case Study
|
||||||
</Button>
|
</Button>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
</motion.div>
|
||||||
</Grid>
|
</Grid>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Box mt={6} display="flex" justifyContent="center">
|
<Box mt={6} display="flex" justifyContent="center">
|
||||||
|
<motion.div whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.98 }}>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: "30px",
|
borderRadius: "20px",
|
||||||
borderColor: "#00FFD1",
|
border: "1px solid #00E0FF",
|
||||||
color: "#00FFD1",
|
color: "#00E0FF",
|
||||||
px: 4,
|
px: 4,
|
||||||
py: 1.5,
|
py: 1,
|
||||||
fontWeight: "bold",
|
fontWeight: 600,
|
||||||
|
fontSize: "0.9rem",
|
||||||
|
textTransform: "none",
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
fontFamily: "'Montserrat', sans-serif",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: "#00FFD1",
|
backgroundColor: "rgba(0, 225, 255, 0.19)",
|
||||||
color: "#000",
|
border: "1px solid #00e1ff",
|
||||||
},
|
},
|
||||||
|
transition: "all 0.3s ease",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
VIEW FULL PORTFOLIO →
|
Explore Full Portfolio
|
||||||
</Button>
|
</Button>
|
||||||
|
</motion.div>
|
||||||
</Box>
|
</Box>
|
||||||
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
Container,
|
Container,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
|
Grid,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { motion, AnimatePresence, PanInfo } from "framer-motion";
|
import { motion, AnimatePresence, PanInfo } from "framer-motion";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
@ -35,18 +36,17 @@ const services = [
|
||||||
|
|
||||||
const Services = () => {
|
const Services = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
const isMobile = useMediaQuery(theme.breakpoints.down("md"));
|
||||||
const [currentIndex, setCurrentIndex] = useState(0);
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
|
const [hoveredCard, setHoveredCard] = useState<number | null>(null);
|
||||||
|
|
||||||
const handleDragEnd = (
|
const handleDragEnd = (
|
||||||
event: MouseEvent | TouchEvent | PointerEvent,
|
event: MouseEvent | TouchEvent | PointerEvent,
|
||||||
info: PanInfo
|
info: PanInfo
|
||||||
) => {
|
) => {
|
||||||
if (info.offset.x > 50) {
|
if (info.offset.x > 50) {
|
||||||
// Swiped right
|
|
||||||
setCurrentIndex((prev) => (prev === 0 ? services.length - 1 : prev - 1));
|
setCurrentIndex((prev) => (prev === 0 ? services.length - 1 : prev - 1));
|
||||||
} else if (info.offset.x < -50) {
|
} else if (info.offset.x < -50) {
|
||||||
// Swiped left
|
|
||||||
setCurrentIndex((prev) => (prev === services.length - 1 ? 0 : prev + 1));
|
setCurrentIndex((prev) => (prev === services.length - 1 ? 0 : prev + 1));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -58,23 +58,29 @@ const Services = () => {
|
||||||
initial={{ opacity: 0, y: -20 }}
|
initial={{ opacity: 0, y: -20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6 }}
|
transition={{ duration: 0.6 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h4"
|
variant="h4"
|
||||||
align="center"
|
align="center"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
|
sx={{ mb: 2 }}
|
||||||
>
|
>
|
||||||
Services
|
Our Services
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="subtitle1" align="center" mb={6}>
|
<Typography
|
||||||
We offer design, development & marketing services
|
variant="subtitle1"
|
||||||
|
align="center"
|
||||||
|
mb={6}
|
||||||
|
sx={{ maxWidth: 600, mx: "auto" }}
|
||||||
|
>
|
||||||
|
Professional solutions tailored to your needs
|
||||||
</Typography>
|
</Typography>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<Box sx={{ position: "relative", height: 400, overflow: "hidden" }}>
|
<Box sx={{ position: "relative", height: 380 }}>
|
||||||
<AnimatePresence initial={false}>
|
<AnimatePresence initial={false}>
|
||||||
<motion.div
|
<motion.div
|
||||||
key={currentIndex}
|
key={currentIndex}
|
||||||
|
|
@ -90,70 +96,102 @@ const Services = () => {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
padding: "0 16px",
|
padding: "0 16px",
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
<motion.div
|
||||||
|
whileHover={{ scale: 1.02 }}
|
||||||
|
whileTap={{ scale: 0.98 }}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: 5,
|
borderRadius: 2,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
bgcolor: "#fff",
|
bgcolor: "#fff",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
maxWidth: 345,
|
maxWidth: 300,
|
||||||
mx: "auto",
|
mx: "auto",
|
||||||
|
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
|
||||||
}}
|
}}
|
||||||
elevation={3}
|
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
height: 200,
|
width: "100%",
|
||||||
|
height: 150,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
|
bgcolor: "#f8f9fa",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
<motion.div
|
||||||
|
animate={{
|
||||||
|
scale: hoveredCard === currentIndex ? 1.05 : 1,
|
||||||
|
y: hoveredCard === currentIndex ? -5 : 0,
|
||||||
|
}}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
style={{ width: "100%" }}
|
||||||
>
|
>
|
||||||
<CardMedia
|
<CardMedia
|
||||||
component="img"
|
component="img"
|
||||||
image={services[currentIndex].image}
|
image={services[currentIndex].image}
|
||||||
alt={services[currentIndex].title}
|
alt={services[currentIndex].title}
|
||||||
sx={{
|
sx={{
|
||||||
objectFit: "contain",
|
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "auto",
|
||||||
|
objectFit: "cover",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</motion.div>
|
||||||
</Box>
|
</Box>
|
||||||
<CardContent sx={{ flexGrow: 1 }}>
|
<CardContent sx={{ flexGrow: 1 }}>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h6"
|
variant="h6"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
color="black"
|
color="#000"
|
||||||
>
|
>
|
||||||
{services[currentIndex].title}
|
{services[currentIndex].title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="black">
|
<Typography variant="body2" color="#000" sx={{ mb: 2 }}>
|
||||||
{services[currentIndex].description}
|
{services[currentIndex].description}
|
||||||
</Typography>
|
</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>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
{/* Dots indicator */}
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
mt: 2,
|
mt: 3,
|
||||||
gap: 1,
|
gap: 1.5,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{services.map((_, index) => (
|
{services.map((_, index) => (
|
||||||
<Box
|
<motion.div
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => setCurrentIndex(index)}
|
onClick={() => setCurrentIndex(index)}
|
||||||
|
whileHover={{ scale: 1.2 }}
|
||||||
|
whileTap={{ scale: 0.9 }}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: 10,
|
width: 10,
|
||||||
height: 10,
|
height: 10,
|
||||||
|
|
@ -162,52 +200,77 @@ const Services = () => {
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Box
|
<Grid container spacing={3} justifyContent="center">
|
||||||
sx={{
|
|
||||||
display: "grid",
|
|
||||||
gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
|
|
||||||
gap: 4,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{services.map((service, index) => (
|
{services.map((service, index) => (
|
||||||
<motion.div
|
<Grid
|
||||||
|
item
|
||||||
|
xs={12}
|
||||||
|
sm={6}
|
||||||
|
md={4}
|
||||||
key={index}
|
key={index}
|
||||||
whileHover={{ y: -5 }}
|
sx={{ display: "flex", justifyContent: "center" }}
|
||||||
transition={{ duration: 0.3 }}
|
>
|
||||||
|
<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
|
<Card
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: 5,
|
borderRadius: 2,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
bgcolor: "#fff",
|
bgcolor: "#fff",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
|
boxShadow: "0 5px 15px rgba(0, 0, 0, 0.1)",
|
||||||
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
elevation={3}
|
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
height: 200,
|
width: "100%",
|
||||||
|
height: 160,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
|
bgcolor: "#f8f9fa",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<motion.div whileHover={{ scale: 1.05 }}>
|
<motion.div
|
||||||
|
animate={{
|
||||||
|
scale: hoveredCard === index ? 1.1 : 1,
|
||||||
|
y: hoveredCard === index ? -5 : 0,
|
||||||
|
}}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
>
|
||||||
<CardMedia
|
<CardMedia
|
||||||
component="img"
|
component="img"
|
||||||
image={service.image}
|
image={service.image}
|
||||||
alt={service.title}
|
alt={service.title}
|
||||||
sx={{
|
sx={{
|
||||||
objectFit: "contain",
|
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "auto",
|
||||||
|
objectFit: "cover",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
@ -217,18 +280,33 @@ const Services = () => {
|
||||||
variant="h6"
|
variant="h6"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
color="black"
|
color="#000"
|
||||||
>
|
>
|
||||||
{service.title}
|
{service.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="black">
|
<Typography variant="body2" color="#000" sx={{ mb: 2 }}>
|
||||||
{service.description}
|
{service.description}
|
||||||
</Typography>
|
</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>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
</Grid>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -3,98 +3,348 @@ import {
|
||||||
Box,
|
Box,
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
Grid,
|
|
||||||
Typography,
|
Typography,
|
||||||
|
IconButton,
|
||||||
} from "@mui/material";
|
} 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";
|
import testimonialImg from "../testomonials/b7bef0298c881712fbc6437106d2aaef27c4fad8.jpg";
|
||||||
|
|
||||||
const testimonials = [
|
const testimonials = [
|
||||||
{
|
{
|
||||||
name: "Name",
|
name: "Sarah Johnson",
|
||||||
role: "Role",
|
role: "Marketing Director",
|
||||||
company: "Company Name & Logo",
|
company: "Tech Innovations Inc.",
|
||||||
feedback:
|
feedback: "Working with this team transformed our digital presence.",
|
||||||
"Lorem ipsum dolor sit amet consectetur. Vitae dictum quam senectus posuere sit justo est turpis interdum. Ut vitae platea et adipiscing nisl.",
|
|
||||||
rating: 5,
|
rating: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "John Dae",
|
name: "Michael Chen",
|
||||||
role: "Sr Manager",
|
role: "Sr. Manager",
|
||||||
company: "Wells Fargo",
|
company: "Wells Fargo",
|
||||||
feedback:
|
feedback: "Exceptional service from start to finish.",
|
||||||
"Lorem ipsum dolor sit amet consectetur. Vitae dictum quam senectus posuere sit justo est turpis interdum. Ut vitae platea et adipiscing nisl.",
|
|
||||||
rating: 5,
|
rating: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Name",
|
name: "Emily Rodriguez",
|
||||||
role: "Role",
|
role: "Product Owner",
|
||||||
company: "Company Name & Logo",
|
company: "Nexus Enterprises",
|
||||||
feedback:
|
feedback: "The team's technical expertise was outstanding.",
|
||||||
"Lorem ipsum dolor sit amet consectetur. Vitae dictum quam senectus posuere sit justo est turpis interdum. Ut vitae platea et adipiscing nisl.",
|
|
||||||
rating: 4,
|
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 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 (
|
return (
|
||||||
<Box sx={{ backgroundColor: "#1d2733", color: "#fff", py: 10, px: 3 }}>
|
<Box
|
||||||
<Box textAlign="center" mb={6}>
|
sx={{
|
||||||
<Typography variant="h4" fontWeight="bold" gutterBottom>
|
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
|
Testimonials
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="subtitle1">
|
<Typography variant="subtitle1">
|
||||||
Don’t just take our word for it -- hear directly from our clients
|
Don't just take our word for it
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Grid container spacing={4} justifyContent="center">
|
{/* Mobile Carousel */}
|
||||||
{testimonials.map((t, idx) => (
|
{isMobile ? (
|
||||||
<Grid item xs={12} sm={6} md={4} key={idx}>
|
<Box sx={{ position: "relative", height: 450 }}>
|
||||||
<Card
|
<AnimatePresence>
|
||||||
|
<Box
|
||||||
|
component={motion.div}
|
||||||
|
key={currentIndex}
|
||||||
|
animate={controls}
|
||||||
|
initial={{ x: 0, opacity: 1 }}
|
||||||
|
exit={{ x: 0, opacity: 0 }}
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: 3,
|
position: "absolute",
|
||||||
maxWidth: 320,
|
width: "100%",
|
||||||
margin: "0 auto",
|
display: "flex",
|
||||||
textAlign: "center",
|
justifyContent: "center",
|
||||||
py: 3,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Avatar
|
<TestimonialCard testimonial={testimonials[currentIndex]} />
|
||||||
src={testimonialImg}
|
</Box>
|
||||||
alt={t.name}
|
</AnimatePresence>
|
||||||
sx={{ width: 100, height: 100, margin: "0 auto", mb: 2 }}
|
|
||||||
/>
|
<NavigationArrows handlePrev={handlePrev} handleNext={handleNext} />
|
||||||
<CardContent>
|
</Box>
|
||||||
<Typography variant="subtitle1" fontWeight="bold">
|
) : (
|
||||||
{t.name} ,{" "}
|
/* Desktop Grid */
|
||||||
<span style={{ fontWeight: "normal" }}>{t.role}</span>
|
<Box
|
||||||
</Typography>
|
component={motion.div}
|
||||||
<Typography variant="body2" color="text.secondary" mb={1}>
|
initial="hidden"
|
||||||
{t.company}
|
animate="visible"
|
||||||
</Typography>
|
variants={containerVariants}
|
||||||
<Typography variant="body2" color="text.secondary" mb={2}>
|
sx={{
|
||||||
{t.feedback}
|
display: "flex",
|
||||||
</Typography>
|
justifyContent: "center",
|
||||||
<Box>
|
flexWrap: "wrap",
|
||||||
{Array.from({ length: 5 }).map((_, i) => (
|
gap: 4,
|
||||||
<span
|
px: { md: 4 },
|
||||||
key={i}
|
|
||||||
style={{
|
|
||||||
color: i < t.rating ? "#00FFD1" : "#ccc",
|
|
||||||
fontSize: "1.2rem",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
★
|
{testimonials.map((t, idx) => (
|
||||||
</span>
|
<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>
|
||||||
</CardContent>
|
)}
|
||||||
</Card>
|
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</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;
|
export default Testimonials;
|
||||||
|
|
|
||||||