Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions src/app/components/Hero.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { motion, useReducedMotion } from 'motion/react';
import { Smartphone, Zap, TrendingUp, Sparkles } from 'lucide-react';
import { useState, useRef } from 'react';
import { useInView } from 'motion/react';
import { TypingText } from './TypingText';

const heroImage = "https://images.unsplash.com/photo-1551288049-bebda4e38f71?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxtb2Rlcm4lMjB3ZWJzaXRlJTIwZGFzaGJvYXJkJTIwZGVzaWdufGVufDF8fHx8MTc4MTcwMjY1OXww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral";
Expand All @@ -16,6 +17,7 @@ export function Hero() {
const reduce = useReducedMotion();
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const containerRef = useRef<HTMLDivElement>(null);
const isInView = useInView(containerRef, { margin: "200px" });

const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (reduce) return;
Expand All @@ -38,8 +40,8 @@ export function Hero() {
<section id="hero" className="relative min-h-screen flex items-center justify-center overflow-hidden bg-gradient-to-br from-indigo-50 via-white to-purple-50 dark:from-slate-900 dark:via-slate-950 dark:to-slate-900 pt-20" onMouseMove={handleMouseMove} ref={containerRef}>
{/* Gradient Mesh Background */}
<div className="absolute inset-0 overflow-hidden">
<div className="absolute -top-1/2 -left-1/4 w-[600px] h-[600px] bg-gradient-to-br from-indigo-400/30 to-purple-400/30 dark:from-indigo-600/20 dark:to-purple-600/20 rounded-full blur-3xl animate-pulse motion-reduce:animate-none" />
<div className="absolute -bottom-1/2 -right-1/4 w-[600px] h-[600px] bg-gradient-to-br from-cyan-400/30 to-blue-400/30 dark:from-cyan-600/20 dark:to-blue-600/20 rounded-full blur-3xl animate-pulse motion-reduce:animate-none" style={{ animationDelay: '1s' }} />
<div className={`absolute -top-1/2 -left-1/4 w-[600px] h-[600px] bg-gradient-to-br from-indigo-400/30 to-purple-400/30 dark:from-indigo-600/20 dark:to-purple-600/20 rounded-full blur-3xl ${isInView ? 'animate-pulse' : ''} motion-reduce:animate-none`} />
<div className={`absolute -bottom-1/2 -right-1/4 w-[600px] h-[600px] bg-gradient-to-br from-cyan-400/30 to-blue-400/30 dark:from-cyan-600/20 dark:to-blue-600/20 rounded-full blur-3xl ${isInView ? 'animate-pulse' : ''} motion-reduce:animate-none`} style={{ animationDelay: '1s' }} />
</div>

<div className="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 md:py-20">
Expand All @@ -57,7 +59,7 @@ export function Hero() {
transition={{ duration: reduce ? 0 : 0.5 }}
className="inline-flex items-center gap-2 px-4 py-2 bg-white/60 dark:bg-slate-800/60 backdrop-blur-sm rounded-full border border-indigo-100 dark:border-indigo-900 mb-6"
>
<span className="w-2 h-2 bg-green-500 rounded-full animate-pulse motion-reduce:animate-none" />
<span className={`w-2 h-2 bg-green-500 rounded-full ${isInView ? 'animate-pulse' : ''} motion-reduce:animate-none`} />
<span className="text-sm text-gray-700 dark:text-gray-200">Available for new projects</span>
</motion.div>

Expand Down Expand Up @@ -132,7 +134,7 @@ export function Hero() {
/>
<motion.div
className="absolute inset-0 bg-gradient-to-tr from-indigo-600/10 to-purple-600/10 dark:from-indigo-600/20 dark:to-purple-600/20"
animate={reduce ? undefined : {
animate={reduce || !isInView ? undefined : {
opacity: [0.6, 1, 0.6],
scale: [1, 1.04, 1],
backgroundPosition: ['0% 0%', '100% 100%', '0% 0%'],
Expand Down Expand Up @@ -199,7 +201,7 @@ export function Hero() {
transition={{ duration: reduce ? 0 : 0.6, delay: 0.3 + index * 0.15 }}
>
<motion.div
animate={reduce ? undefined : { ...cardAnimations[index] }}
animate={reduce || !isInView ? undefined : { ...cardAnimations[index] }}
transition={{
duration: 5,
repeat: Infinity,
Expand All @@ -217,18 +219,17 @@ export function Hero() {
filter: 'drop-shadow(0 10px 25px rgba(0,0,0,0.1)) drop-shadow(0 0 20px rgba(99,102,241,0.1))',
}}
>
{/* Glowing gradient border overlay */}
<motion.div
className="absolute inset-0 rounded-2xl pointer-events-none"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
animate={reduce ? undefined : {
boxShadow: [
`inset 0 0 20px rgba(99,102,241,0), inset 0 0 0px ${card.color}`,
`inset 0 0 20px rgba(99,102,241,0.2), inset 0 0 1px rgba(99,102,241,0.5)`,
`inset 0 0 20px rgba(99,102,241,0), inset 0 0 0px ${card.color}`,
],
}}
<motion.div
className="absolute inset-0 rounded-2xl pointer-events-none"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
animate={reduce || !isInView ? undefined : {
boxShadow: [
`inset 0 0 20px rgba(99,102,241,0), inset 0 0 0px ${card.color}`,
`inset 0 0 20px rgba(99,102,241,0.2), inset 0 0 1px rgba(99,102,241,0.5)`,
`inset 0 0 20px rgba(99,102,241,0), inset 0 0 0px ${card.color}`,
],
}}
transition={{
duration: 3,
repeat: Infinity,
Expand All @@ -239,10 +240,9 @@ export function Hero() {
<div
className={`w-10 h-10 bg-gradient-to-br ${card.color} rounded-lg flex items-center justify-center flex-shrink-0 transition-all duration-300 group-hover:shadow-2xl relative overflow-hidden`}
>
{/* Pulsing glow effect on icon */}
<motion.div
className={`absolute inset-0 bg-gradient-to-br ${card.color} rounded-lg blur-md`}
animate={reduce ? undefined : {
animate={reduce || !isInView ? undefined : {
opacity: [0.3, 0.6, 0.3],
scale: [1, 1.1, 1],
}}
Expand Down
11 changes: 6 additions & 5 deletions src/app/components/Services.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useRef } from 'react';
import { Link } from 'react-router-dom';
import { motion, useScroll, useTransform, useReducedMotion } from 'motion/react';
import { motion, useScroll, useTransform, useReducedMotion, useInView } from 'motion/react';
import { services } from '../data/servicesData';
import { TypingText } from './TypingText';

Expand Down Expand Up @@ -131,6 +131,7 @@ function ServiceCard({
export function Services() {
const ref = useRef<HTMLElement>(null);
const reduce = useReducedMotion();
const isInView = useInView(ref, { margin: "200px" });
const { scrollYProgress } = useScroll({ target: ref, offset: ['start end', 'end start'] });
const bgY = useTransform(scrollYProgress, [0, 1], ['-8%', '8%']);
const bgScale = useTransform(scrollYProgress, [0, 0.5, 1], [1.1, 1, 1.1]);
Expand All @@ -156,17 +157,17 @@ export function Services() {
>
<motion.div
className="absolute -top-32 -left-24 w-[640px] h-[640px] rounded-full bg-gradient-to-br from-indigo-400/40 to-purple-400/30 dark:from-indigo-500/20 dark:to-purple-500/15 blur-3xl"
animate={reduce ? undefined : { x: [0, 40, -20, 0], y: [0, -30, 20, 0], scale: [1, 1.08, 0.96, 1] }}
animate={reduce || !isInView ? undefined : { x: [0, 40, -20, 0], y: [0, -30, 20, 0], scale: [1, 1.08, 0.96, 1] }}
transition={{ duration: 18, repeat: Infinity, ease: 'easeInOut' }}
/>
<motion.div
className="absolute top-1/3 right-[-120px] w-[560px] h-[560px] rounded-full bg-gradient-to-br from-purple-400/35 to-fuchsia-300/25 dark:from-purple-500/15 dark:to-fuchsia-400/10 blur-3xl"
animate={reduce ? undefined : { x: [0, -50, 30, 0], y: [0, 25, -15, 0], scale: [1, 1.06, 0.97, 1] }}
animate={reduce || !isInView ? undefined : { x: [0, -50, 30, 0], y: [0, 25, -15, 0], scale: [1, 1.06, 0.97, 1] }}
transition={{ duration: 22, repeat: Infinity, ease: 'easeInOut' }}
/>
<motion.div
className="absolute bottom-[-160px] left-1/3 w-[600px] h-[600px] rounded-full bg-gradient-to-br from-cyan-400/35 to-teal-300/25 dark:from-cyan-500/15 dark:to-teal-400/10 blur-3xl"
animate={reduce ? undefined : { x: [0, 30, -40, 0], y: [0, -20, 30, 0], scale: [1, 1.07, 0.95, 1] }}
animate={reduce || !isInView ? undefined : { x: [0, 30, -40, 0], y: [0, -20, 30, 0], scale: [1, 1.07, 0.95, 1] }}
transition={{ duration: 26, repeat: Infinity, ease: 'easeInOut' }}
/>
</motion.div>
Expand Down Expand Up @@ -194,7 +195,7 @@ export function Services() {
'linear-gradient(110deg,#4F46E5,#7C3AED,#06B6D4,#7C3AED,#4F46E5)',
backgroundSize: '200% auto',
}}
animate={reduce ? undefined : { backgroundPositionX: ['0%', '200%'] }}
animate={reduce || !isInView ? undefined : { backgroundPositionX: ['0%', '200%'] }}
transition={{ duration: 6, repeat: Infinity, ease: 'linear' }}
>
<TypingText text="Succeed Online" delay={200} cursorColor="bg-indigo-500" />
Expand Down
8 changes: 7 additions & 1 deletion src/app/components/Testimonials.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { motion, useReducedMotion } from "motion/react";
import { motion, useReducedMotion, useInView } from "motion/react";
import { useRef } from "react";
import { Quote, Star } from "lucide-react";
import { TypingText } from "./TypingText";
import priya from "../../assets/testimonials/priya.jpg";
Expand Down Expand Up @@ -169,8 +170,12 @@ function MarqueeRow({
duration?: string;
label: string;
}) {
const ref = useRef<HTMLDivElement>(null);
const isInView = useInView(ref, { margin: "200px" });

return (
<div
ref={ref}
className="testimonial-marquee group relative overflow-hidden focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-400/60"
role="group"
tabIndex={0}
Expand All @@ -186,6 +191,7 @@ function MarqueeRow({
{
"--marquee-duration": duration,
"--marquee-direction": direction,
animationPlayState: !isInView ? 'paused' : undefined,
} as React.CSSProperties
}
>
Expand Down
Loading