feat: enhance UI components with framer-motion animations

- Added framer-motion for animations in Features, Footer, Header, Hero, and Button components.
- Implemented entrance animations for feature cards and section headers.
- Enhanced button interactions with ripple effects and gradient overlays.
- Improved mobile menu animations and transitions.
- Added animated stats and placeholders in the Hero section.
- Updated package.json to include framer-motion dependency.
This commit is contained in:
Cesar Mendivil 2025-09-16 02:20:08 -07:00
parent bfb2de8298
commit 8c2111702b
8 changed files with 868 additions and 178 deletions

View File

@ -1,4 +1,4 @@
# Inteliq UI Kit - React.js Project {# Inteliq UI Kit - React.js Project
A modern React.js project built with Vite and TypeScript, implementing a comprehensive UI kit based on Figma designs. A modern React.js project built with Vite and TypeScript, implementing a comprehensive UI kit based on Figma designs.

49
package-lock.json generated
View File

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"framer-motion": "^12.23.12",
"lucide-react": "^0.535.0", "lucide-react": "^0.535.0",
"npx": "^10.2.2", "npx": "^10.2.2",
"postcss": "^8.5.6", "postcss": "^8.5.6",
@ -2635,6 +2636,33 @@
"url": "https://github.com/sponsors/rawify" "url": "https://github.com/sponsors/rawify"
} }
}, },
"node_modules/framer-motion": {
"version": "12.23.12",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.12.tgz",
"integrity": "sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==",
"license": "MIT",
"dependencies": {
"motion-dom": "^12.23.12",
"motion-utils": "^12.23.6",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@ -3368,6 +3396,21 @@
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
} }
}, },
"node_modules/motion-dom": {
"version": "12.23.12",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.12.tgz",
"integrity": "sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.23.6"
}
},
"node_modules/motion-utils": {
"version": "12.23.6",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
"integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
"license": "MIT"
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@ -8902,6 +8945,12 @@
"dev": true, "dev": true,
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/type-check": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",

View File

@ -12,6 +12,7 @@
"dependencies": { "dependencies": {
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"framer-motion": "^12.23.12",
"lucide-react": "^0.535.0", "lucide-react": "^0.535.0",
"npx": "^10.2.2", "npx": "^10.2.2",
"postcss": "^8.5.6", "postcss": "^8.5.6",

View File

@ -1,25 +1,126 @@
import React from 'react' import React from 'react'
import { Zap, Shield, Smartphone, Code, Palette, Users } from 'lucide-react' import { Zap, Shield, Smartphone, Code, Palette, Users } from 'lucide-react'
import { motion, useInView, useAnimation } from 'framer-motion'
interface FeatureCardProps { interface FeatureCardProps {
icon: React.ReactNode icon: React.ReactNode
title: string title: string
description: string description: string
index: number
} }
const FeatureCard: React.FC<FeatureCardProps> = ({ icon, title, description }) => { const FeatureCard: React.FC<FeatureCardProps> = ({ icon, title, description, index }) => {
const controls = useAnimation()
const ref = React.useRef(null)
const isInView = useInView(ref, { once: true })
React.useEffect(() => {
if (isInView) {
controls.start("visible")
}
}, [controls, isInView])
const cardVariants = {
hidden: {
opacity: 0,
y: 50,
scale: 0.8
},
visible: {
opacity: 1,
y: 0,
scale: 1,
transition: {
duration: 0.6,
delay: index * 0.1,
type: "spring" as const,
stiffness: 100,
damping: 15
}
}
}
return ( return (
<div className="bg-white p-8 rounded-2xl shadow-sm border border-gray-100 hover:shadow-lg transition-shadow group"> <motion.div
<div className="w-12 h-12 bg-primary-100 rounded-xl flex items-center justify-center mb-6 group-hover:bg-primary-200 transition-colors"> ref={ref}
{icon} variants={cardVariants}
</div> initial="hidden"
<h3 className="text-xl font-semibold text-gray-900 mb-3">{title}</h3> animate={controls}
<p className="text-gray-600 leading-relaxed">{description}</p> whileHover={{
</div> y: -10,
scale: 1.05,
boxShadow: "0 25px 50px rgba(0, 0, 0, 0.15)",
transition: { duration: 0.3 }
}}
className="bg-white p-8 rounded-2xl shadow-sm border border-gray-100 hover:shadow-lg transition-shadow group cursor-pointer"
>
<motion.div
className="w-12 h-12 bg-primary-100 rounded-xl flex items-center justify-center mb-6 group-hover:bg-primary-200 transition-colors"
whileHover={{
rotate: 360,
scale: 1.2,
backgroundColor: "#bae6fd"
}}
transition={{ duration: 0.5 }}
>
<motion.div
animate={{
rotate: [0, 10, -10, 0],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
>
{icon}
</motion.div>
</motion.div>
<motion.h3
className="text-xl font-semibold text-gray-900 mb-3"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: index * 0.1 + 0.3 }}
>
{title}
</motion.h3>
<motion.p
className="text-gray-600 leading-relaxed"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: index * 0.1 + 0.5 }}
>
{description}
</motion.p>
{/* Hover effect overlay */}
<motion.div
className="absolute inset-0 bg-gradient-to-r from-primary-500/5 to-primary-600/5 rounded-2xl opacity-0"
whileHover={{ opacity: 1 }}
transition={{ duration: 0.3 }}
/>
</motion.div>
) )
} }
const Features: React.FC = () => { const Features: React.FC = () => {
const titleRef = React.useRef(null)
const isTitleInView = useInView(titleRef, { once: true })
const titleVariants = {
hidden: { opacity: 0, y: 50 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.8,
type: "spring" as const,
stiffness: 100
}
}
}
const features = [ const features = [
{ {
icon: <Zap className="w-6 h-6 text-primary-600" />, icon: <Zap className="w-6 h-6 text-primary-600" />,
@ -54,41 +155,129 @@ const Features: React.FC = () => {
] ]
return ( return (
<section className="py-20 lg:py-32 bg-gray-50"> <section className="py-20 lg:py-32 bg-gray-50 overflow-hidden">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Section Header */} {/* Section Header */}
<div className="text-center space-y-4 mb-16"> <motion.div
<div className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-primary-100 text-primary-800"> ref={titleRef}
className="text-center space-y-4 mb-16"
variants={titleVariants}
initial="hidden"
animate={isTitleInView ? "visible" : "hidden"}
>
<motion.div
className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-primary-100 text-primary-800"
whileHover={{ scale: 1.05 }}
animate={{
boxShadow: [
"0 0 0 0 rgba(2, 132, 199, 0)",
"0 0 0 10px rgba(2, 132, 199, 0.1)",
"0 0 0 0 rgba(2, 132, 199, 0)"
]
}}
transition={{ duration: 2, repeat: Infinity }}
>
Features Features
</div> </motion.div>
<h2 className="text-3xl lg:text-5xl font-bold text-gray-900">
<motion.h2
className="text-3xl lg:text-5xl font-bold text-gray-900"
initial={{ opacity: 0, y: 30 }}
animate={isTitleInView ? { opacity: 1, y: 0 } : {}}
transition={{ delay: 0.2, duration: 0.8 }}
>
Everything you need to Everything you need to
<span className="text-primary-600"> build amazing UIs</span> <motion.span
</h2> className="text-primary-600"
<p className="text-xl text-gray-600 max-w-3xl mx-auto leading-relaxed"> animate={{
color: ["#0284c7", "#0ea5e9", "#38bdf8", "#0284c7"]
}}
transition={{ duration: 3, repeat: Infinity }}
> build amazing UIs</motion.span>
</motion.h2>
<motion.p
className="text-xl text-gray-600 max-w-3xl mx-auto leading-relaxed"
initial={{ opacity: 0, y: 30 }}
animate={isTitleInView ? { opacity: 1, y: 0 } : {}}
transition={{ delay: 0.4, duration: 0.8 }}
>
Our comprehensive UI kit provides all the components and tools you need Our comprehensive UI kit provides all the components and tools you need
to create beautiful, accessible, and performant user interfaces. to create beautiful, accessible, and performant user interfaces.
</p> </motion.p>
</div> </motion.div>
{/* Features Grid */} {/* Features Grid */}
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8"> <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{features.map((feature, index) => ( {features.map((feature, index) => (
<FeatureCard <FeatureCard
key={index} key={feature.title}
icon={feature.icon} icon={feature.icon}
title={feature.title} title={feature.title}
description={feature.description} description={feature.description}
index={index}
/> />
))} ))}
</div> </div>
{/* Bottom CTA */} {/* Bottom CTA with sophisticated animation */}
<div className="text-center mt-16"> <motion.div
<button className="bg-primary-600 text-white px-8 py-4 rounded-xl font-semibold hover:bg-primary-700 transition-colors"> className="text-center mt-16"
Explore All Components initial={{ opacity: 0, y: 50 }}
</button> whileInView={{ opacity: 1, y: 0 }}
</div> viewport={{ once: true }}
transition={{ delay: 0.8, duration: 0.6 }}
>
<motion.button
className="bg-primary-600 text-white px-8 py-4 rounded-xl font-semibold hover:bg-primary-700 transition-colors relative overflow-hidden"
whileHover={{
scale: 1.05,
boxShadow: "0 20px 40px rgba(2, 132, 199, 0.3)"
}}
whileTap={{ scale: 0.95 }}
>
{/* Animated background gradient */}
<motion.div
className="absolute inset-0 bg-gradient-to-r from-primary-500 via-primary-600 to-primary-700"
animate={{
x: ["-100%", "100%"]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "linear" as const
}}
/>
<span className="relative z-10">Explore All Components</span>
</motion.button>
</motion.div>
{/* Background animated elements */}
<motion.div
className="absolute top-20 left-10 w-20 h-20 bg-primary-200 rounded-full opacity-20"
animate={{
scale: [1, 1.2, 1],
rotate: [0, 180, 360],
}}
transition={{
duration: 8,
repeat: Infinity,
ease: "easeInOut" as const
}}
/>
<motion.div
className="absolute bottom-20 right-10 w-16 h-16 bg-primary-300 rounded-full opacity-20"
animate={{
y: [-20, 20, -20],
x: [-10, 10, -10],
}}
transition={{
duration: 6,
repeat: Infinity,
ease: "easeInOut" as const,
delay: 2
}}
/>
</div> </div>
</section> </section>
) )

View File

@ -1,95 +1,229 @@
import React from 'react' import React from 'react'
import { Github, Twitter, Linkedin, Mail } from 'lucide-react' import { Github, Twitter, Linkedin, Mail } from 'lucide-react'
import { motion, useInView } from 'framer-motion'
const Footer: React.FC = () => { const Footer: React.FC = () => {
const ref = React.useRef(null)
const isInView = useInView(ref, { once: true })
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1,
delayChildren: 0.2
}
}
}
const itemVariants = {
hidden: { y: 30, opacity: 0 },
visible: {
y: 0,
opacity: 1,
transition: {
duration: 0.6,
ease: "easeOut" as const
}
}
}
const socialIcons = [
{ Icon: Github, href: "#", color: "hover:text-gray-300" },
{ Icon: Twitter, href: "#", color: "hover:text-blue-400" },
{ Icon: Linkedin, href: "#", color: "hover:text-blue-500" },
{ Icon: Mail, href: "#", color: "hover:text-green-400" }
]
return ( return (
<footer className="bg-gray-900 text-white"> <motion.footer
className="bg-gray-900 text-white"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Main Footer Content */} {/* Main Footer Content */}
<div className="py-16"> <motion.div
ref={ref}
className="py-16"
variants={containerVariants}
initial="hidden"
animate={isInView ? "visible" : "hidden"}
>
<div className="grid lg:grid-cols-4 gap-8"> <div className="grid lg:grid-cols-4 gap-8">
{/* Brand Section */} {/* Brand Section */}
<div className="lg:col-span-1"> <motion.div
<h3 className="text-2xl font-bold mb-4">Inteliq</h3> className="lg:col-span-1"
<p className="text-gray-400 mb-6 leading-relaxed"> variants={itemVariants}
>
<motion.h3
className="text-2xl font-bold mb-4"
whileHover={{ scale: 1.05 }}
animate={{
textShadow: [
"0 0 0 rgba(2, 132, 199, 0)",
"0 0 20px rgba(2, 132, 199, 0.3)",
"0 0 0 rgba(2, 132, 199, 0)"
]
}}
transition={{ duration: 3, repeat: Infinity }}
>
Inteliq
</motion.h3>
<motion.p
className="text-gray-400 mb-6 leading-relaxed"
variants={itemVariants}
>
Modern UI components for React applications. Modern UI components for React applications.
Build beautiful interfaces faster with our comprehensive kit. Build beautiful interfaces faster with our comprehensive kit.
</p> </motion.p>
<div className="flex space-x-4"> <div className="flex space-x-4">
<a href="#" className="text-gray-400 hover:text-white transition-colors"> {socialIcons.map(({ Icon, href, color }, index) => (
<Github size={20} /> <motion.a
</a> key={index}
<a href="#" className="text-gray-400 hover:text-white transition-colors"> href={href}
<Twitter size={20} /> className={`text-gray-400 ${color} transition-colors`}
</a> whileHover={{
<a href="#" className="text-gray-400 hover:text-white transition-colors"> scale: 1.2,
<Linkedin size={20} /> y: -3,
</a> rotate: 5
<a href="#" className="text-gray-400 hover:text-white transition-colors"> }}
<Mail size={20} /> whileTap={{ scale: 0.9 }}
</a> initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5 + index * 0.1 }}
>
<Icon size={20} />
</motion.a>
))}
</div> </div>
</div> </motion.div>
{/* Product Links */} {/* Product Links */}
<div> <motion.div variants={itemVariants}>
<h4 className="font-semibold mb-4">Product</h4> <motion.h4
className="font-semibold mb-4"
whileHover={{ color: "#38bdf8" }}
>
Product
</motion.h4>
<ul className="space-y-3"> <ul className="space-y-3">
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Components</a></li> {['Components', 'Templates', 'Icons', 'Playground', 'Figma Kit'].map((item, index) => (
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Templates</a></li> <motion.li
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Icons</a></li> key={item}
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Playground</a></li> initial={{ opacity: 0, x: -20 }}
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Figma Kit</a></li> animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.3 + index * 0.1 }}
>
<motion.a
href="#"
className="text-gray-400 hover:text-white transition-colors"
whileHover={{ x: 5, color: "#ffffff" }}
>
{item}
</motion.a>
</motion.li>
))}
</ul> </ul>
</div> </motion.div>
{/* Resources Links */} {/* Resources Links */}
<div> <motion.div variants={itemVariants}>
<h4 className="font-semibold mb-4">Resources</h4> <motion.h4
className="font-semibold mb-4"
whileHover={{ color: "#38bdf8" }}
>
Resources
</motion.h4>
<ul className="space-y-3"> <ul className="space-y-3">
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Documentation</a></li> {['Documentation', 'Getting Started', 'Examples', 'Blog', 'Community'].map((item, index) => (
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Getting Started</a></li> <motion.li
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Examples</a></li> key={item}
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Blog</a></li> initial={{ opacity: 0, x: -20 }}
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Community</a></li> animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.4 + index * 0.1 }}
>
<motion.a
href="#"
className="text-gray-400 hover:text-white transition-colors"
whileHover={{ x: 5, color: "#ffffff" }}
>
{item}
</motion.a>
</motion.li>
))}
</ul> </ul>
</div> </motion.div>
{/* Company Links */} {/* Company Links */}
<div> <motion.div variants={itemVariants}>
<h4 className="font-semibold mb-4">Company</h4> <motion.h4
className="font-semibold mb-4"
whileHover={{ color: "#38bdf8" }}
>
Company
</motion.h4>
<ul className="space-y-3"> <ul className="space-y-3">
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">About</a></li> {['About', 'Careers', 'Contact', 'Privacy', 'Terms'].map((item, index) => (
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Careers</a></li> <motion.li
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Contact</a></li> key={item}
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Privacy</a></li> initial={{ opacity: 0, x: -20 }}
<li><a href="#" className="text-gray-400 hover:text-white transition-colors">Terms</a></li> animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.5 + index * 0.1 }}
>
<motion.a
href="#"
className="text-gray-400 hover:text-white transition-colors"
whileHover={{ x: 5, color: "#ffffff" }}
>
{item}
</motion.a>
</motion.li>
))}
</ul> </ul>
</div> </motion.div>
</div> </div>
</div> </motion.div>
{/* Bottom Bar */} {/* Bottom Bar */}
<div className="border-t border-gray-800 py-8"> <motion.div
className="border-t border-gray-800 py-8"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.8, duration: 0.6 }}
>
<div className="flex flex-col md:flex-row justify-between items-center"> <div className="flex flex-col md:flex-row justify-between items-center">
<p className="text-gray-400 text-sm"> <motion.p
className="text-gray-400 text-sm"
animate={{
opacity: [0.7, 1, 0.7]
}}
transition={{ duration: 3, repeat: Infinity }}
>
© 2025 Inteliq UI Kit. All rights reserved. © 2025 Inteliq UI Kit. All rights reserved.
</p> </motion.p>
<div className="flex space-x-6 mt-4 md:mt-0"> <div className="flex space-x-6 mt-4 md:mt-0">
<a href="#" className="text-gray-400 hover:text-white text-sm transition-colors"> {['Privacy Policy', 'Terms of Service', 'Cookie Policy'].map((item, index) => (
Privacy Policy <motion.a
</a> key={item}
<a href="#" className="text-gray-400 hover:text-white text-sm transition-colors"> href="#"
Terms of Service className="text-gray-400 hover:text-white text-sm transition-colors"
</a> whileHover={{ y: -2 }}
<a href="#" className="text-gray-400 hover:text-white text-sm transition-colors"> initial={{ opacity: 0 }}
Cookie Policy animate={{ opacity: 1 }}
</a> transition={{ delay: 1 + index * 0.1 }}
>
{item}
</motion.a>
))}
</div> </div>
</div> </div>
</div> </motion.div>
</div> </div>
</footer> </motion.footer>
) )
} }

View File

@ -1,76 +1,139 @@
import React from 'react' import React from 'react'
import { Menu, X } from 'lucide-react' import { Menu, X } from 'lucide-react'
import { motion, AnimatePresence } from 'framer-motion'
const Header: React.FC = () => { const Header: React.FC = () => {
const [isMenuOpen, setIsMenuOpen] = React.useState(false) const [isMenuOpen, setIsMenuOpen] = React.useState(false)
return ( return (
<header className="bg-white shadow-sm border-b border-gray-200"> <motion.header
className="bg-white shadow-sm border-b border-gray-200"
initial={{ y: -100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ type: "spring", stiffness: 100, damping: 20 }}
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16"> <div className="flex justify-between items-center h-16">
{/* Logo */} {/* Logo */}
<div className="flex-shrink-0"> <motion.div
className="flex-shrink-0"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
<h1 className="text-2xl font-bold text-gray-900">Inteliq</h1> <h1 className="text-2xl font-bold text-gray-900">Inteliq</h1>
</div> </motion.div>
{/* Desktop Navigation */} {/* Desktop Navigation */}
<nav className="hidden md:flex space-x-8"> <nav className="hidden md:flex space-x-8">
<a href="#" className="text-gray-700 hover:text-primary-600 px-3 py-2 text-sm font-medium"> {['Home', 'Features', 'About', 'Contact'].map((item, index) => (
Home <motion.a
</a> key={item}
<a href="#" className="text-gray-700 hover:text-primary-600 px-3 py-2 text-sm font-medium"> href="#"
Features className="text-gray-700 hover:text-primary-600 px-3 py-2 text-sm font-medium relative"
</a> whileHover={{ y: -2 }}
<a href="#" className="text-gray-700 hover:text-primary-600 px-3 py-2 text-sm font-medium"> initial={{ opacity: 0, y: 20 }}
About animate={{ opacity: 1, y: 0 }}
</a> transition={{ delay: index * 0.1 }}
<a href="#" className="text-gray-700 hover:text-primary-600 px-3 py-2 text-sm font-medium"> >
Contact {item}
</a> <motion.div
className="absolute bottom-0 left-0 w-full h-0.5 bg-primary-600"
initial={{ scaleX: 0 }}
whileHover={{ scaleX: 1 }}
transition={{ duration: 0.2 }}
/>
</motion.a>
))}
</nav> </nav>
{/* CTA Button */} {/* CTA Button */}
<div className="hidden md:flex items-center space-x-4"> <div className="hidden md:flex items-center space-x-4">
<button className="bg-primary-600 text-white px-6 py-2 rounded-lg font-medium hover:bg-primary-700 transition-colors"> <motion.button
className="bg-primary-600 text-white px-6 py-2 rounded-lg font-medium hover:bg-primary-700 transition-colors"
whileHover={{ scale: 1.05, boxShadow: "0 10px 25px rgba(2, 132, 199, 0.3)" }}
whileTap={{ scale: 0.95 }}
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.5 }}
>
Get Started Get Started
</button> </motion.button>
</div> </div>
{/* Mobile menu button */} {/* Mobile menu button */}
<div className="md:hidden"> <div className="md:hidden">
<button <motion.button
onClick={() => setIsMenuOpen(!isMenuOpen)} onClick={() => setIsMenuOpen(!isMenuOpen)}
className="text-gray-700 hover:text-gray-900" className="text-gray-700 hover:text-gray-900"
whileTap={{ scale: 0.9 }}
> >
{isMenuOpen ? <X size={24} /> : <Menu size={24} />} <AnimatePresence mode="wait">
</button> {isMenuOpen ? (
<motion.div
key="close"
initial={{ rotate: 0 }}
animate={{ rotate: 180 }}
exit={{ rotate: 0 }}
transition={{ duration: 0.2 }}
>
<X size={24} />
</motion.div>
) : (
<motion.div
key="menu"
initial={{ rotate: 180 }}
animate={{ rotate: 0 }}
exit={{ rotate: 180 }}
transition={{ duration: 0.2 }}
>
<Menu size={24} />
</motion.div>
)}
</AnimatePresence>
</motion.button>
</div> </div>
</div> </div>
{/* Mobile Navigation */} {/* Mobile Navigation */}
{isMenuOpen && ( <AnimatePresence>
<div className="md:hidden"> {isMenuOpen && (
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3 bg-white border-t border-gray-200"> <motion.div
<a href="#" className="block px-3 py-2 text-base font-medium text-gray-700 hover:text-primary-600"> className="md:hidden"
Home initial={{ height: 0, opacity: 0 }}
</a> animate={{ height: "auto", opacity: 1 }}
<a href="#" className="block px-3 py-2 text-base font-medium text-gray-700 hover:text-primary-600"> exit={{ height: 0, opacity: 0 }}
Features transition={{ duration: 0.3, ease: "easeInOut" }}
</a> >
<a href="#" className="block px-3 py-2 text-base font-medium text-gray-700 hover:text-primary-600"> <div className="px-2 pt-2 pb-3 space-y-1 sm:px-3 bg-white border-t border-gray-200 overflow-hidden">
About {['Home', 'Features', 'About', 'Contact'].map((item, index) => (
</a> <motion.a
<a href="#" className="block px-3 py-2 text-base font-medium text-gray-700 hover:text-primary-600"> key={item}
Contact href="#"
</a> className="block px-3 py-2 text-base font-medium text-gray-700 hover:text-primary-600"
<button className="w-full mt-4 bg-primary-600 text-white px-6 py-2 rounded-lg font-medium hover:bg-primary-700 transition-colors"> initial={{ x: -20, opacity: 0 }}
Get Started animate={{ x: 0, opacity: 1 }}
</button> transition={{ delay: index * 0.1 }}
</div> whileHover={{ x: 10 }}
</div> >
)} {item}
</motion.a>
))}
<motion.button
className="w-full mt-4 bg-primary-600 text-white px-6 py-2 rounded-lg font-medium hover:bg-primary-700 transition-colors"
initial={{ y: 20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 0.4 }}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
Get Started
</motion.button>
</div>
</motion.div>
)}
</AnimatePresence>
</div> </div>
</header> </motion.header>
) )
} }

View File

@ -1,80 +1,272 @@
import React from 'react' import React from 'react'
import { ArrowRight, Play } from 'lucide-react' import { ArrowRight, Play } from 'lucide-react'
import { motion, useInView } from 'framer-motion'
const Hero: React.FC = () => { const Hero: React.FC = () => {
const ref = React.useRef(null)
const isInView = useInView(ref, { once: true })
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.2,
delayChildren: 0.3
}
}
}
const itemVariants = {
hidden: { y: 50, opacity: 0 },
visible: {
y: 0,
opacity: 1,
transition: {
type: "spring" as const,
stiffness: 100,
damping: 20
}
}
}
return ( return (
<section className="bg-gradient-to-br from-primary-50 to-white"> <section className="bg-gradient-to-br from-primary-50 to-white overflow-hidden">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 lg:py-32"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 lg:py-32">
<div className="grid lg:grid-cols-2 gap-12 items-center"> <motion.div
ref={ref}
className="grid lg:grid-cols-2 gap-12 items-center"
variants={containerVariants}
initial="hidden"
animate={isInView ? "visible" : "hidden"}
>
{/* Left Content */} {/* Left Content */}
<div className="space-y-8"> <div className="space-y-8">
<div className="space-y-4"> <div className="space-y-4">
<div className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-primary-100 text-primary-800"> <motion.div
className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-primary-100 text-primary-800"
variants={itemVariants}
whileHover={{ scale: 1.05 }}
>
🚀 New Update Available 🚀 New Update Available
</div> </motion.div>
<h1 className="text-4xl lg:text-6xl font-bold text-gray-900 leading-tight">
<motion.h1
className="text-4xl lg:text-6xl font-bold text-gray-900 leading-tight"
variants={itemVariants}
>
Build Amazing Build Amazing
<span className="text-primary-600"> UI Components</span> <motion.span
</h1> className="text-primary-600"
<p className="text-xl text-gray-600 leading-relaxed"> initial={{ backgroundPosition: "0% 50%" }}
animate={{ backgroundPosition: "100% 50%" }}
transition={{ duration: 3, repeat: Infinity, repeatType: "reverse" }}
style={{
background: "linear-gradient(90deg, #0284c7, #0ea5e9, #38bdf8, #0284c7)",
backgroundSize: "200% 100%",
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
backgroundClip: "text"
}}
> UI Components</motion.span>
</motion.h1>
<motion.p
className="text-xl text-gray-600 leading-relaxed"
variants={itemVariants}
>
Create stunning user interfaces with our comprehensive UI kit. Create stunning user interfaces with our comprehensive UI kit.
Designed for modern web applications with React and TypeScript. Designed for modern web applications with React and TypeScript.
</p> </motion.p>
</div> </div>
{/* CTA Buttons */} {/* CTA Buttons */}
<div className="flex flex-col sm:flex-row gap-4"> <motion.div
<button className="bg-primary-600 text-white px-8 py-4 rounded-xl font-semibold hover:bg-primary-700 transition-colors flex items-center justify-center group"> className="flex flex-col sm:flex-row gap-4"
variants={itemVariants}
>
<motion.button
className="bg-primary-600 text-white px-8 py-4 rounded-xl font-semibold hover:bg-primary-700 transition-colors flex items-center justify-center group"
whileHover={{
scale: 1.05,
boxShadow: "0 20px 40px rgba(2, 132, 199, 0.3)",
y: -5
}}
whileTap={{ scale: 0.95 }}
>
Get Started Get Started
<ArrowRight size={20} className="ml-2 group-hover:translate-x-1 transition-transform" /> <motion.div
</button> className="ml-2"
<button className="border border-gray-300 text-gray-700 px-8 py-4 rounded-xl font-semibold hover:bg-gray-50 transition-colors flex items-center justify-center"> animate={{ x: [0, 5, 0] }}
<Play size={20} className="mr-2" /> transition={{ duration: 1.5, repeat: Infinity }}
>
<ArrowRight size={20} />
</motion.div>
</motion.button>
<motion.button
className="border border-gray-300 text-gray-700 px-8 py-4 rounded-xl font-semibold hover:bg-gray-50 transition-colors flex items-center justify-center group"
whileHover={{
scale: 1.05,
borderColor: "#0284c7",
boxShadow: "0 10px 25px rgba(0, 0, 0, 0.1)"
}}
whileTap={{ scale: 0.95 }}
>
<motion.div
className="mr-2"
whileHover={{ scale: 1.2, rotate: 360 }}
transition={{ duration: 0.3 }}
>
<Play size={20} />
</motion.div>
Watch Demo Watch Demo
</button> </motion.button>
</div> </motion.div>
{/* Stats */} {/* Stats */}
<div className="flex flex-wrap gap-8 pt-8"> <motion.div
<div> className="flex flex-wrap gap-8 pt-8"
<div className="text-3xl font-bold text-gray-900">50+</div> variants={itemVariants}
<div className="text-gray-600">Components</div> >
</div> {[
<div> { number: "50+", label: "Components" },
<div className="text-3xl font-bold text-gray-900">10k+</div> { number: "10k+", label: "Downloads" },
<div className="text-gray-600">Downloads</div> { number: "99%", label: "Satisfaction" }
</div> ].map((stat, index) => (
<div> <motion.div
<div className="text-3xl font-bold text-gray-900">99%</div> key={stat.label}
<div className="text-gray-600">Satisfaction</div> initial={{ scale: 0, opacity: 0 }}
</div> animate={{ scale: 1, opacity: 1 }}
</div> transition={{ delay: 1 + index * 0.2, type: "spring", stiffness: 200 }}
whileHover={{ scale: 1.1, y: -5 }}
>
<motion.div
className="text-3xl font-bold text-gray-900"
animate={{ color: ["#111827", "#0284c7", "#111827"] }}
transition={{ duration: 2, repeat: Infinity, delay: index * 0.5 }}
>
{stat.number}
</motion.div>
<div className="text-gray-600">{stat.label}</div>
</motion.div>
))}
</motion.div>
</div> </div>
{/* Right Content - Placeholder for design */} {/* Right Content - Animated design placeholder */}
<div className="relative"> <motion.div
<div className="bg-white rounded-2xl shadow-2xl p-8 space-y-6"> className="relative"
<div className="h-4 bg-gray-200 rounded animate-pulse"></div> variants={itemVariants}
>
<motion.div
className="bg-white rounded-2xl shadow-2xl p-8 space-y-6"
whileHover={{
y: -10,
boxShadow: "0 25px 50px rgba(0, 0, 0, 0.15)"
}}
animate={{
y: [-10, 10, -10]
}}
transition={{
duration: 3,
repeat: Infinity,
ease: "easeInOut" as const
}}
>
<motion.div
className="h-4 bg-gray-200 rounded"
animate={{ opacity: [0.3, 1, 0.3] }}
transition={{ duration: 2, repeat: Infinity }}
/>
<div className="space-y-3"> <div className="space-y-3">
<div className="h-3 bg-gray-200 rounded animate-pulse"></div> {[1, 0.8, 0.6].map((width, index) => (
<div className="h-3 bg-gray-200 rounded w-5/6 animate-pulse"></div> <motion.div
<div className="h-3 bg-gray-200 rounded w-4/6 animate-pulse"></div> key={index}
className="h-3 bg-gray-200 rounded"
style={{ width: `${width * 100}%` }}
animate={{ opacity: [0.5, 1, 0.5] }}
transition={{
duration: 1.5,
repeat: Infinity,
delay: index * 0.3
}}
/>
))}
</div> </div>
<div className="flex space-x-4"> <div className="flex space-x-4">
<div className="w-20 h-10 bg-primary-200 rounded animate-pulse"></div> <motion.div
<div className="w-20 h-10 bg-gray-200 rounded animate-pulse"></div> className="w-20 h-10 bg-primary-200 rounded"
whileHover={{ scale: 1.1, backgroundColor: "#bae6fd" }}
animate={{ opacity: [0.7, 1, 0.7] }}
transition={{ duration: 2, repeat: Infinity }}
/>
<motion.div
className="w-20 h-10 bg-gray-200 rounded"
whileHover={{ scale: 1.1 }}
animate={{ opacity: [0.5, 0.8, 0.5] }}
transition={{ duration: 2.5, repeat: Infinity }}
/>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<div className="h-2 bg-gray-200 rounded animate-pulse"></div> {[1, 0.75].map((width, index) => (
<div className="h-2 bg-gray-200 rounded w-3/4 animate-pulse"></div> <motion.div
key={index}
className="h-2 bg-gray-200 rounded"
style={{ width: `${width * 100}%` }}
animate={{ scaleX: [0.8, 1, 0.8] }}
transition={{
duration: 2,
repeat: Infinity,
delay: index * 0.5
}}
/>
))}
</div> </div>
</div> </motion.div>
{/* Floating elements */} {/* Floating elements with sophisticated animations */}
<div className="absolute -top-4 -right-4 w-8 h-8 bg-primary-500 rounded-full opacity-20"></div> <motion.div
<div className="absolute -bottom-4 -left-4 w-6 h-6 bg-primary-300 rounded-full opacity-30"></div> className="absolute -top-4 -right-4 w-8 h-8 bg-primary-500 rounded-full"
</div> animate={{
</div> scale: [1, 1.2, 1],
rotate: [0, 180, 360],
opacity: [0.2, 0.8, 0.2]
}}
transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut" as const
}}
/>
<motion.div
className="absolute -bottom-4 -left-4 w-6 h-6 bg-primary-300 rounded-full"
animate={{
scale: [1, 0.8, 1],
x: [-10, 10, -10],
opacity: [0.3, 0.9, 0.3]
}}
transition={{
duration: 3,
repeat: Infinity,
ease: "easeInOut" as const,
delay: 1
}}
/>
<motion.div
className="absolute top-1/2 -left-8 w-4 h-4 bg-primary-400 rounded-full"
animate={{
y: [-20, 20, -20],
opacity: [0.4, 1, 0.4]
}}
transition={{
duration: 2.5,
repeat: Infinity,
ease: "easeInOut" as const,
delay: 0.5
}}
/>
</motion.div>
</motion.div>
</div> </div>
</section> </section>
) )

View File

@ -1,10 +1,12 @@
import React from 'react' import React from 'react'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { motion } from 'framer-motion'
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' variant?: 'primary' | 'secondary' | 'outline' | 'ghost'
size?: 'sm' | 'md' | 'lg' size?: 'sm' | 'md' | 'lg'
children: React.ReactNode children: React.ReactNode
animated?: boolean
} }
const Button: React.FC<ButtonProps> = ({ const Button: React.FC<ButtonProps> = ({
@ -12,9 +14,10 @@ const Button: React.FC<ButtonProps> = ({
size = 'md', size = 'md',
className, className,
children, children,
animated = true,
...props ...props
}) => { }) => {
const baseClasses = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2' const baseClasses = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 relative overflow-hidden'
const variants = { const variants = {
primary: 'bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500', primary: 'bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500',
@ -35,11 +38,70 @@ const Button: React.FC<ButtonProps> = ({
sizes[size], sizes[size],
className className
) )
const buttonVariants = {
hover: {
scale: 1.05,
boxShadow: variant === 'primary'
? "0 10px 25px rgba(2, 132, 199, 0.3)"
: "0 10px 25px rgba(0, 0, 0, 0.1)",
transition: { duration: 0.2 }
},
tap: { scale: 0.95 }
}
const rippleVariants = {
initial: { scale: 0, opacity: 0.8 },
animate: {
scale: 4,
opacity: 0,
transition: { duration: 0.6, ease: "easeOut" as const }
}
}
if (!animated) {
return (
<button className={classes} {...props}>
{children}
</button>
)
}
return ( return (
<button className={classes} {...props}> <motion.button
{children} className={classes}
</button> variants={buttonVariants}
whileHover="hover"
whileTap="tap"
{...(props as any)}
>
{/* Ripple effect */}
<motion.span
className="absolute inset-0 bg-white rounded-lg"
initial="initial"
whileTap="animate"
variants={rippleVariants}
style={{ mixBlendMode: variant === 'primary' ? 'overlay' : 'multiply' }}
/>
{/* Gradient overlay for primary variant */}
{variant === 'primary' && (
<motion.div
className="absolute inset-0 bg-gradient-to-r from-primary-500 via-primary-600 to-primary-700 rounded-lg"
animate={{
x: ["-100%", "100%"]
}}
transition={{
duration: 3,
repeat: Infinity,
ease: "linear" as const,
repeatDelay: 2
}}
/>
)}
<span className="relative z-10">{children}</span>
</motion.button>
) )
} }