Compare commits

...

8 Commits

Author SHA1 Message Date
Mihir Motiyani f62bf4d480 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>
2025-08-06 10:46:46 +05:30
hardik dd872ea234 fix : added animation and mobile view in footer section
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2025-08-02 12:09:49 +00:00
hardik 0a31567b38 fix : added animation and mobile view in testimonial section 2025-08-02 12:05:48 +00:00
hardik e863382af9 fix : changed css of about us segment
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2025-08-02 11:42:25 +00:00
hardik f20e8591cb fix : added animation and responsiveness in portfolio segment
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2025-08-02 08:19:02 +00:00
hardik ae41722019 fix : added text animation and responsiveness in hero section 2025-08-02 07:24:11 +00:00
hardik efcd9290bc fix : changed layout of header and added a logo 2025-08-02 07:19:30 +00:00
Mihir Motiyani d0dc2e8ff2 Merge pull request 'fix : frozen file issue' (#6) from feature/new_segment into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: #6
2025-07-23 22:50:17 +05:30
76 changed files with 14598 additions and 18081 deletions

View File

@ -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"
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

View File

@ -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>
); );
}; };

View File

@ -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">FAQs</Link> {["FAQs", "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>

View File

@ -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",

View File

@ -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>
); );

View File

@ -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}>
Weve 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>
); );
}; };

View File

@ -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>

View File

@ -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">
Dont 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;

26118
yarn.lock

File diff suppressed because it is too large Load Diff