Merge version_1 into main #1
55
package.json
55
package.json
@@ -1,41 +1,22 @@
|
||||
{
|
||||
"name": "webild-components-2",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
"build": "next build --turbopack",
|
||||
"start": "next start",
|
||||
"lint": "eslint"
|
||||
},
|
||||
"name": "webild-components-2", "version": "0.1.0", "private": true,
|
||||
"dependencies": {
|
||||
"@gsap/react": "^2.1.2",
|
||||
"@react-three/drei": "^10.7.7",
|
||||
"@react-three/fiber": "^9.4.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cobe": "^0.6.5",
|
||||
"embla-carousel-auto-scroll": "^8.6.0",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"gsap": "^3.13.0",
|
||||
"lenis": "^1.3.15",
|
||||
"lucide-react": "^0.555.0",
|
||||
"motion-number": "^1.0.0",
|
||||
"next": "16.0.7",
|
||||
"react": "19.2.1",
|
||||
"react-dom": "19.2.1",
|
||||
"react-fast-marquee": "^1.6.5",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"three": "^0.181.2"
|
||||
"@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", "@testing-library/user-event": "^13.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4", "lucide-react": "^0.263.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3",
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.0.7",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
"scripts": {
|
||||
"start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app", "react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%", "not dead", "not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version", "last 1 firefox version", "last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
0
public/favicon.ico
Normal file
0
public/favicon.ico
Normal file
1237
public/index.html
Normal file
1237
public/index.html
Normal file
File diff suppressed because it is too large
Load Diff
8
public/manifest.json
Normal file
8
public/manifest.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"short_name": "React App", "name": "Create React App Sample", "icons": [
|
||||
{
|
||||
"src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff"
|
||||
}
|
||||
33
src/App.css
Normal file
33
src/App.css
Normal file
@@ -0,0 +1,33 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
padding: 20px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
27
src/App.js
Normal file
27
src/App.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import './App.css';
|
||||
import NavbarStyleApple from './components/navbar/NavbarStyleApple/NavbarStyleApple';
|
||||
import HeroBillboard from './components/sections/hero/HeroBillboard';
|
||||
import AboutMetric from './components/sections/about/AboutMetric';
|
||||
import AboutFeatureGrid from './components/sections/about/AboutFeatureGrid';
|
||||
import AboutCardFeature from './components/sections/about/AboutCardFeature';
|
||||
import TestimonialsStorybook from './components/sections/testimonials/TestimonialsStorybook';
|
||||
import BlogGrid from './components/sections/blog/BlogGrid';
|
||||
import FooterLinksColumns from './components/footer/FooterLinksColumns/FooterLinksColumns';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<NavbarStyleApple />
|
||||
<HeroBillboard />
|
||||
<AboutMetric />
|
||||
<AboutFeatureGrid />
|
||||
<AboutCardFeature />
|
||||
<TestimonialsStorybook />
|
||||
<BlogGrid />
|
||||
<FooterLinksColumns />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,70 @@
|
||||
import React from 'react';
|
||||
import { Facebook, Twitter, Github, Linkedin } from 'lucide-react';
|
||||
|
||||
function FooterLinksColumns() {
|
||||
const footerLinks = {
|
||||
Product: ['Features', 'Pricing', 'Documentation', 'API Reference'],
|
||||
Company: ['About', 'Blog', 'Careers', 'Press'],
|
||||
Resources: ['Community', 'Support', 'Status', 'Security'],
|
||||
Legal: ['Privacy', 'Terms', 'Cookies', 'Licenses']
|
||||
};
|
||||
|
||||
const socialLinks = [
|
||||
{ icon: <Facebook size={20} />, href: '#' },
|
||||
{ icon: <Twitter size={20} />, href: '#' },
|
||||
{ icon: <Github size={20} />, href: '#' },
|
||||
{ icon: <Linkedin size={20} />, href: '#' }
|
||||
];
|
||||
|
||||
return (
|
||||
<footer className="bg-gray-900 text-white">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-6 gap-8">
|
||||
<div className="lg:col-span-2">
|
||||
<div className="flex items-center mb-4">
|
||||
<img src="/images/logo-small-gradient.0ed287ce-1768917228014.svg" alt="Logo" className="h-8 w-8" />
|
||||
<span className="ml-2 text-xl font-semibold">Brand</span>
|
||||
</div>
|
||||
<p className="text-gray-400 mb-4">
|
||||
Building the future of web development with modern tools and exceptional developer experience.
|
||||
</p>
|
||||
<div className="flex space-x-4">
|
||||
{socialLinks.map((social, index) => (
|
||||
<a key={index} href={social.href} className="text-gray-400 hover:text-white transition-colors">
|
||||
{social.icon}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{Object.entries(footerLinks).map(([category, links]) => (
|
||||
<div key={category}>
|
||||
<h3 className="text-lg font-semibold mb-4">{category}</h3>
|
||||
<ul className="space-y-2">
|
||||
{links.map((link) => (
|
||||
<li key={link}>
|
||||
<a href="#" className="text-gray-400 hover:text-white transition-colors">
|
||||
{link}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-800 mt-8 pt-8 flex flex-col md:flex-row justify-between items-center">
|
||||
<p className="text-gray-400 text-sm">
|
||||
© 2024 Brand. All rights reserved.
|
||||
</p>
|
||||
<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</a>
|
||||
<a href="#" className="text-gray-400 hover:text-white text-sm transition-colors">Terms of Service</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
||||
export default FooterLinksColumns;
|
||||
48
src/components/navbar/NavbarStyleApple/NavbarStyleApple.js
Normal file
48
src/components/navbar/NavbarStyleApple/NavbarStyleApple.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
import { Menu, X } from 'lucide-react';
|
||||
|
||||
function NavbarStyleApple() {
|
||||
const [isMenuOpen, setIsMenuOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<nav className="bg-white shadow-sm">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between h-16">
|
||||
<div className="flex items-center">
|
||||
<img src="/images/logo-small-gradient.0ed287ce-1768917228014.svg" alt="Logo" className="h-8 w-8" />
|
||||
<span className="ml-2 text-xl font-semibold">Brand</span>
|
||||
</div>
|
||||
|
||||
<div className="hidden md:flex items-center space-x-8">
|
||||
<a href="#" className="text-gray-700 hover:text-gray-900">Home</a>
|
||||
<a href="#" className="text-gray-700 hover:text-gray-900">About</a>
|
||||
<a href="#" className="text-gray-700 hover:text-gray-900">Services</a>
|
||||
<a href="#" className="text-gray-700 hover:text-gray-900">Contact</a>
|
||||
</div>
|
||||
|
||||
<div className="md:hidden flex items-center">
|
||||
<button
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
className="text-gray-700 hover:text-gray-900"
|
||||
>
|
||||
{isMenuOpen ? <X size={24} /> : <Menu size={24} />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isMenuOpen && (
|
||||
<div className="md:hidden">
|
||||
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
|
||||
<a href="#" className="block px-3 py-2 text-gray-700 hover:text-gray-900">Home</a>
|
||||
<a href="#" className="block px-3 py-2 text-gray-700 hover:text-gray-900">About</a>
|
||||
<a href="#" className="block px-3 py-2 text-gray-700 hover:text-gray-900">Services</a>
|
||||
<a href="#" className="block px-3 py-2 text-gray-700 hover:text-gray-900">Contact</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
export default NavbarStyleApple;
|
||||
49
src/components/sections/about/AboutCardFeature.js
Normal file
49
src/components/sections/about/AboutCardFeature.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import { CheckCircle } from 'lucide-react';
|
||||
|
||||
function AboutCardFeature() {
|
||||
const features = [
|
||||
'Modern React components',
|
||||
'TypeScript support',
|
||||
'Responsive design',
|
||||
'Accessibility built-in',
|
||||
'Custom theming',
|
||||
'Developer tools'
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="py-16 bg-white">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
<div>
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-6">
|
||||
Everything you need to build faster
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 mb-8">
|
||||
Our comprehensive component library includes everything you need to build modern web applications quickly and efficiently.
|
||||
</p>
|
||||
|
||||
<div className="space-y-4">
|
||||
{features.map((feature, index) => (
|
||||
<div key={index} className="flex items-center">
|
||||
<CheckCircle className="w-6 h-6 text-green-500 mr-3" />
|
||||
<span className="text-gray-700 font-medium">{feature}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<button className="mt-8 bg-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-blue-700 transition-colors">
|
||||
Learn More
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<img src="/images/devtools.7a9f095a-1768917228138.png" alt="Features" className="rounded-lg shadow-lg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutCardFeature;
|
||||
60
src/components/sections/about/AboutFeatureGrid.js
Normal file
60
src/components/sections/about/AboutFeatureGrid.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import React from 'react';
|
||||
import { Zap, Shield, Globe, Code } from 'lucide-react';
|
||||
|
||||
function AboutFeatureGrid() {
|
||||
const features = [
|
||||
{
|
||||
icon: <Zap className="w-8 h-8 text-blue-600" />,
|
||||
title: 'Lightning Fast',
|
||||
description: 'Optimized for performance with modern web standards'
|
||||
},
|
||||
{
|
||||
icon: <Shield className="w-8 h-8 text-blue-600" />,
|
||||
title: 'Secure by Default',
|
||||
description: 'Built with security best practices from the ground up'
|
||||
},
|
||||
{
|
||||
icon: <Globe className="w-8 h-8 text-blue-600" />,
|
||||
title: 'Global Scale',
|
||||
description: 'Deploy worldwide with our global infrastructure'
|
||||
},
|
||||
{
|
||||
icon: <Code className="w-8 h-8 text-blue-600" />,
|
||||
title: 'Developer First',
|
||||
description: 'Clean APIs and excellent developer experience'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="py-16 bg-gray-50">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
||||
Why choose our platform?
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
||||
Everything you need to build modern web applications
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{features.map((feature, index) => (
|
||||
<div key={index} className="bg-white p-6 rounded-lg shadow-sm hover:shadow-md transition-shadow">
|
||||
<div className="mb-4">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-gray-900 mb-2">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p className="text-gray-600">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutFeatureGrid;
|
||||
40
src/components/sections/about/AboutMetric.js
Normal file
40
src/components/sections/about/AboutMetric.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
|
||||
function AboutMetric() {
|
||||
const metrics = [
|
||||
{ value: '10K+', label: 'Happy Customers' },
|
||||
{ value: '50+', label: 'Components' },
|
||||
{ value: '99.9%', label: 'Uptime' },
|
||||
{ value: '24/7', label: 'Support' }
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="py-16 bg-white">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
||||
Trusted by developers worldwide
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
||||
Our platform is used by thousands of developers and companies to build amazing web experiences.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
|
||||
{metrics.map((metric, index) => (
|
||||
<div key={index} className="text-center">
|
||||
<div className="text-4xl md:text-5xl font-bold text-blue-600 mb-2">
|
||||
{metric.value}
|
||||
</div>
|
||||
<div className="text-gray-600 font-medium">
|
||||
{metric.label}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutMetric;
|
||||
77
src/components/sections/blog/BlogGrid.js
Normal file
77
src/components/sections/blog/BlogGrid.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import { Calendar, User } from 'lucide-react';
|
||||
|
||||
function BlogGrid() {
|
||||
const blogPosts = [
|
||||
{
|
||||
title: 'Getting Started with Modern React',
|
||||
excerpt: 'Learn the fundamentals of React 18 and build amazing user interfaces.',
|
||||
author: 'John Doe',
|
||||
date: '2024-01-15',
|
||||
image: '/images/courses.aee168f4-1768917228064.png',
|
||||
category: 'React'
|
||||
},
|
||||
{
|
||||
title: 'Building Scalable Web Applications',
|
||||
excerpt: 'Best practices for creating maintainable and scalable web applications.',
|
||||
author: 'Jane Smith',
|
||||
date: '2024-01-10',
|
||||
image: '/images/courses-box-1.e8498908-1768917228039.png',
|
||||
category: 'Architecture'
|
||||
},
|
||||
{
|
||||
title: 'The Future of Web Development',
|
||||
excerpt: 'Explore emerging trends and technologies shaping the future of web development.',
|
||||
author: 'Mike Johnson',
|
||||
date: '2024-01-05',
|
||||
image: '/images/courses-box-2.2e36a41b-1768917228024.png',
|
||||
category: 'Trends'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="py-16 bg-white">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
||||
Latest from our blog
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
||||
Stay updated with the latest trends and best practices in web development
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{blogPosts.map((post, index) => (
|
||||
<article key={index} className="bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow overflow-hidden border">
|
||||
<img src={post.image} alt={post.title} className="w-full h-48 object-cover" />
|
||||
|
||||
<div className="p-6">
|
||||
<div className="text-sm text-blue-600 font-semibold mb-2">
|
||||
{post.category}
|
||||
</div>
|
||||
|
||||
<h3 className="text-xl font-bold text-gray-900 mb-3 hover:text-blue-600 cursor-pointer">
|
||||
{post.title}
|
||||
</h3>
|
||||
|
||||
<p className="text-gray-600 mb-4">
|
||||
{post.excerpt}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center text-sm text-gray-500">
|
||||
<User className="w-4 h-4 mr-1" />
|
||||
<span className="mr-4">{post.author}</span>
|
||||
<Calendar className="w-4 h-4 mr-1" />
|
||||
<span>{post.date}</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default BlogGrid;
|
||||
32
src/components/sections/hero/HeroBillboard.js
Normal file
32
src/components/sections/hero/HeroBillboard.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import { ArrowRight } from 'lucide-react';
|
||||
|
||||
function HeroBillboard() {
|
||||
return (
|
||||
<section className="bg-gradient-to-br from-blue-50 to-indigo-100 py-20">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center">
|
||||
<h1 className="text-4xl md:text-6xl font-bold text-gray-900 mb-6">
|
||||
Build Amazing <span className="text-blue-600">Web Experiences</span>
|
||||
</h1>
|
||||
<p className="text-xl text-gray-600 mb-8 max-w-3xl mx-auto">
|
||||
Create stunning websites and applications with our comprehensive component library and design system.
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<button className="bg-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-blue-700 transition-colors flex items-center justify-center">
|
||||
Get Started <ArrowRight className="ml-2" size={20} />
|
||||
</button>
|
||||
<button className="bg-white text-gray-700 px-8 py-3 rounded-lg font-semibold border border-gray-300 hover:bg-gray-50 transition-colors">
|
||||
Learn More
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-16">
|
||||
<img src="/images/header.e5c9eff6-1768917228520.webp" alt="Hero" className="mx-auto rounded-lg shadow-2xl" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default HeroBillboard;
|
||||
@@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
import { Star } from 'lucide-react';
|
||||
|
||||
function TestimonialsStorybook() {
|
||||
const testimonials = [
|
||||
{
|
||||
name: 'John Doe',
|
||||
role: 'Frontend Developer',
|
||||
company: 'TechCorp',
|
||||
content: 'This component library has saved us countless hours of development time. The quality is exceptional.',
|
||||
rating: 5,
|
||||
avatar: '/images/256-1768917228018.png'
|
||||
},
|
||||
{
|
||||
name: 'Jane Smith',
|
||||
role: 'Product Manager',
|
||||
company: 'StartupXYZ',
|
||||
content: 'Clean, modern components that work perfectly out of the box. Highly recommended!',
|
||||
rating: 5,
|
||||
avatar: '/images/256-1768917228018.png'
|
||||
},
|
||||
{
|
||||
name: 'Mike Johnson',
|
||||
role: 'Full Stack Developer',
|
||||
company: 'WebAgency',
|
||||
content: 'The documentation is excellent and the components are very well designed.',
|
||||
rating: 5,
|
||||
avatar: '/images/256-1768917228018.png'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="py-16 bg-gray-50">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
|
||||
What developers are saying
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
||||
Join thousands of developers who trust our components
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{testimonials.map((testimonial, index) => (
|
||||
<div key={index} className="bg-white p-6 rounded-lg shadow-sm">
|
||||
<div className="flex items-center mb-4">
|
||||
{[...Array(testimonial.rating)].map((_, i) => (
|
||||
<Star key={i} className="w-5 h-5 text-yellow-400 fill-current" />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="text-gray-700 mb-4">
|
||||
"{testimonial.content}"
|
||||
</p>
|
||||
|
||||
<div className="flex items-center">
|
||||
<img src={testimonial.avatar} alt={testimonial.name} className="w-12 h-12 rounded-full mr-4" />
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900">{testimonial.name}</div>
|
||||
<div className="text-sm text-gray-600">{testimonial.role} at {testimonial.company}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default TestimonialsStorybook;
|
||||
13
src/index.css
Normal file
13
src/index.css
Normal file
@@ -0,0 +1,13 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
17
src/index.js
Normal file
17
src/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
13
src/reportWebVitals.js
Normal file
13
src/reportWebVitals.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
Reference in New Issue
Block a user