mirror of
http://88.130.71.182:3000/BlitTech/contexta_fe.git
synced 2026-06-12 23:23:22 +00:00
Initial commit
This commit is contained in:
852
package-lock.json
generated
852
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -27,11 +27,14 @@
|
|||||||
"@types/react": "^19.2.7",
|
"@types/react": "^19.2.7",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^5.1.1",
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
|
"autoprefixer": "^10.4.21",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.4.24",
|
"eslint-plugin-react-refresh": "^0.4.24",
|
||||||
"globals": "^16.5.0",
|
"globals": "^16.5.0",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
|
"postcss": "^8.5.5",
|
||||||
|
"tailwindcss": "^3.4.17",
|
||||||
"typescript-eslint": "^8.48.0",
|
"typescript-eslint": "^8.48.0",
|
||||||
"vite": "^7.3.1"
|
"vite": "^7.3.1"
|
||||||
}
|
}
|
||||||
|
|||||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
|
||||||
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -11,6 +14,7 @@
|
|||||||
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -58,6 +62,72 @@
|
|||||||
.slide-in-from-bottom-2 {
|
.slide-in-from-bottom-2 {
|
||||||
animation-name: slideInFromBottom;
|
animation-name: slideInFromBottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Staggered animation delay utilities */
|
||||||
|
.delay-100 { animation-delay: 100ms; }
|
||||||
|
.delay-200 { animation-delay: 200ms; }
|
||||||
|
.delay-300 { animation-delay: 300ms; }
|
||||||
|
.delay-400 { animation-delay: 400ms; }
|
||||||
|
.delay-500 { animation-delay: 500ms; }
|
||||||
|
.delay-600 { animation-delay: 600ms; }
|
||||||
|
.delay-700 { animation-delay: 700ms; }
|
||||||
|
.delay-800 { animation-delay: 800ms; }
|
||||||
|
|
||||||
|
/* Gradient text utility */
|
||||||
|
.text-gradient {
|
||||||
|
@apply bg-clip-text text-transparent;
|
||||||
|
background-image: linear-gradient(135deg, #4f46e5, #7c3aed, #2563eb);
|
||||||
|
background-size: 200% 200%;
|
||||||
|
animation: gradientX 8s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Glass morphism */
|
||||||
|
.glass {
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-dark {
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Glow effects */
|
||||||
|
.glow-primary {
|
||||||
|
box-shadow: 0 0 20px rgba(79, 70, 229, 0.3), 0 0 60px rgba(79, 70, 229, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glow-primary-lg {
|
||||||
|
box-shadow: 0 0 40px rgba(79, 70, 229, 0.4), 0 0 100px rgba(79, 70, 229, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Noise texture overlay */
|
||||||
|
.noise-overlay::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.04'/%3E%3C/svg%3E");
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grid background pattern */
|
||||||
|
.bg-grid {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(79, 70, 229, 0.03) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(79, 70, 229, 0.03) 1px, transparent 1px);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dot grid pattern */
|
||||||
|
.bg-dots {
|
||||||
|
background-image: radial-gradient(circle, rgba(79, 70, 229, 0.08) 1px, transparent 1px);
|
||||||
|
background-size: 24px 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slideInFromBottom {
|
@keyframes slideInFromBottom {
|
||||||
|
|||||||
@@ -1,114 +1,588 @@
|
|||||||
import React from 'react'
|
import React, { useState, useEffect, useRef } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { Sparkles, Bot, Globe, Code, Database, Shield, Zap, ArrowRight, Check } from 'lucide-react'
|
import {
|
||||||
|
Sparkles, Bot, Globe, Code, Database, Shield, Zap, ArrowRight,
|
||||||
|
Check, MessageSquare, Upload, Play, ChevronRight, Star, Users,
|
||||||
|
FileText, Cpu, Lock, Download, Menu, X
|
||||||
|
} from 'lucide-react'
|
||||||
|
|
||||||
export const LandingPage: React.FC = () => (
|
// ─── Intersection Observer Hook ────────────────────────────────────────────────
|
||||||
<div className="min-h-screen bg-white">
|
function useInView(options?: IntersectionObserverInit) {
|
||||||
{/* Nav */}
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
<nav className="border-b border-gray-100 sticky top-0 bg-white/80 backdrop-blur-sm z-50">
|
const [isInView, setIsInView] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const el = ref.current
|
||||||
|
if (!el) return
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => { if (entry.isIntersecting) setIsInView(true) },
|
||||||
|
{ threshold: 0.15, ...options }
|
||||||
|
)
|
||||||
|
observer.observe(el)
|
||||||
|
return () => observer.disconnect()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return { ref, isInView }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Animated Counter ──────────────────────────────────────────────────────────
|
||||||
|
const AnimatedCounter: React.FC<{ end: number; suffix?: string; label: string; isInView: boolean }> = ({ end, suffix = '', label, isInView }) => {
|
||||||
|
const [count, setCount] = useState(0)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isInView) return
|
||||||
|
let start = 0
|
||||||
|
const duration = 2000
|
||||||
|
const increment = end / (duration / 16)
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
start += increment
|
||||||
|
if (start >= end) { setCount(end); clearInterval(timer) }
|
||||||
|
else setCount(Math.floor(start))
|
||||||
|
}, 16)
|
||||||
|
return () => clearInterval(timer)
|
||||||
|
}, [isInView, end])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="text-4xl md:text-5xl font-extrabold text-gradient">
|
||||||
|
{count.toLocaleString()}{suffix}
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-gray-500 mt-2 font-medium">{label}</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Floating Chat Preview ─────────────────────────────────────────────────────
|
||||||
|
const FloatingChatPreview: React.FC = () => {
|
||||||
|
const [messages, setMessages] = useState<{ role: string; text: string }[]>([])
|
||||||
|
const [isTyping, setIsTyping] = useState(false)
|
||||||
|
const [step, setStep] = useState(0)
|
||||||
|
|
||||||
|
const conversation = [
|
||||||
|
{ role: 'user', text: 'What are your return policies?' },
|
||||||
|
{ role: 'bot', text: 'Based on your company documents, we offer a 30-day return policy for all items in original condition. Refunds are processed within 5-7 business days.' },
|
||||||
|
{ role: 'user', text: 'Can I return sale items?' },
|
||||||
|
{ role: 'bot', text: 'According to Section 4.2 of your policy, sale items can be exchanged within 14 days but are not eligible for refunds. Would you like to know more?' },
|
||||||
|
]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (step >= conversation.length) {
|
||||||
|
const timeout = setTimeout(() => { setMessages([]); setStep(0) }, 4000)
|
||||||
|
return () => clearTimeout(timeout)
|
||||||
|
}
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
if (conversation[step].role === 'bot') {
|
||||||
|
setIsTyping(true)
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsTyping(false)
|
||||||
|
setMessages(prev => [...prev, conversation[step]])
|
||||||
|
setStep(s => s + 1)
|
||||||
|
}, 1500)
|
||||||
|
} else {
|
||||||
|
setMessages(prev => [...prev, conversation[step]])
|
||||||
|
setStep(s => s + 1)
|
||||||
|
}
|
||||||
|
}, step === 0 ? 1500 : 1000)
|
||||||
|
return () => clearTimeout(timeout)
|
||||||
|
}, [step])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full max-w-sm bg-white rounded-2xl shadow-2xl shadow-primary-500/10 border border-gray-200/60 overflow-hidden">
|
||||||
|
{/* Chat header */}
|
||||||
|
<div className="bg-gradient-to-r from-primary-600 to-primary-700 px-4 py-3 flex items-center gap-3">
|
||||||
|
<div className="w-8 h-8 bg-white/20 rounded-full flex items-center justify-center">
|
||||||
|
<Bot className="w-4 h-4 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-white text-sm font-semibold">Acme Support Bot</p>
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<span className="w-2 h-2 bg-green-400 rounded-full animate-pulse-soft" />
|
||||||
|
<span className="text-primary-200 text-xs">Online</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Messages */}
|
||||||
|
<div className="h-64 p-4 space-y-3 overflow-hidden bg-gray-50/50">
|
||||||
|
{messages.map((msg, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'} animate-fade-in-up`}
|
||||||
|
style={{ animationDelay: '0ms' }}
|
||||||
|
>
|
||||||
|
<div className={`max-w-[85%] px-3.5 py-2.5 rounded-2xl text-sm leading-relaxed ${
|
||||||
|
msg.role === 'user'
|
||||||
|
? 'bg-primary-600 text-white rounded-br-md'
|
||||||
|
: 'bg-white text-gray-700 shadow-sm border border-gray-100 rounded-bl-md'
|
||||||
|
}`}>
|
||||||
|
{msg.text}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{isTyping && (
|
||||||
|
<div className="flex justify-start animate-fade-in">
|
||||||
|
<div className="bg-white px-4 py-3 rounded-2xl rounded-bl-md shadow-sm border border-gray-100 flex gap-1.5">
|
||||||
|
<span className="w-2 h-2 bg-gray-400 rounded-full animate-typing" style={{ animationDelay: '0ms' }} />
|
||||||
|
<span className="w-2 h-2 bg-gray-400 rounded-full animate-typing" style={{ animationDelay: '200ms' }} />
|
||||||
|
<span className="w-2 h-2 bg-gray-400 rounded-full animate-typing" style={{ animationDelay: '400ms' }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Input bar */}
|
||||||
|
<div className="border-t border-gray-100 p-3 flex items-center gap-2 bg-white">
|
||||||
|
<div className="flex-1 bg-gray-100 rounded-full px-4 py-2 text-sm text-gray-400">
|
||||||
|
Type a message...
|
||||||
|
</div>
|
||||||
|
<button className="w-8 h-8 bg-primary-600 rounded-full flex items-center justify-center hover:bg-primary-700 transition-colors">
|
||||||
|
<ArrowRight className="w-4 h-4 text-white" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Feature Card (Interactive) ────────────────────────────────────────────────
|
||||||
|
const FeatureCard: React.FC<{
|
||||||
|
icon: React.ReactNode
|
||||||
|
title: string
|
||||||
|
desc: string
|
||||||
|
color: string
|
||||||
|
delay: number
|
||||||
|
isInView: boolean
|
||||||
|
}> = ({ icon, title, desc, color, delay, isInView }) => (
|
||||||
|
<div
|
||||||
|
className={`group relative bg-white rounded-2xl p-6 border border-gray-200/80 hover:border-primary-200
|
||||||
|
hover:shadow-xl hover:shadow-primary-500/5 transition-all duration-500 hover:-translate-y-1
|
||||||
|
${isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}
|
||||||
|
style={{ transitionDelay: `${delay}ms` }}
|
||||||
|
>
|
||||||
|
{/* Hover glow */}
|
||||||
|
<div className="absolute inset-0 rounded-2xl bg-gradient-to-br from-primary-50/0 to-purple-50/0
|
||||||
|
group-hover:from-primary-50/50 group-hover:to-purple-50/30 transition-all duration-500" />
|
||||||
|
<div className="relative">
|
||||||
|
<div className={`w-12 h-12 rounded-xl flex items-center justify-center mb-4 ${color}
|
||||||
|
group-hover:scale-110 transition-transform duration-300`}>
|
||||||
|
{icon}
|
||||||
|
</div>
|
||||||
|
<h3 className="font-semibold text-gray-900 mb-2 group-hover:text-primary-700 transition-colors">{title}</h3>
|
||||||
|
<p className="text-sm text-gray-500 leading-relaxed">{desc}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
// ─── How It Works Step ─────────────────────────────────────────────────────────
|
||||||
|
const Step: React.FC<{
|
||||||
|
num: number
|
||||||
|
icon: React.ReactNode
|
||||||
|
title: string
|
||||||
|
desc: string
|
||||||
|
isInView: boolean
|
||||||
|
delay: number
|
||||||
|
}> = ({ num, icon, title, desc, isInView, delay }) => (
|
||||||
|
<div
|
||||||
|
className={`relative flex flex-col items-center text-center transition-all duration-700
|
||||||
|
${isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-12'}`}
|
||||||
|
style={{ transitionDelay: `${delay}ms` }}
|
||||||
|
>
|
||||||
|
<div className="relative mb-5">
|
||||||
|
<div className="w-16 h-16 bg-gradient-to-br from-primary-500 to-primary-700 rounded-2xl flex items-center justify-center
|
||||||
|
shadow-lg shadow-primary-500/25 rotate-3 hover:rotate-0 transition-transform duration-300">
|
||||||
|
{icon}
|
||||||
|
</div>
|
||||||
|
<div className="absolute -top-2 -right-2 w-7 h-7 bg-white rounded-full border-2 border-primary-500 flex items-center justify-center">
|
||||||
|
<span className="text-xs font-bold text-primary-600">{num}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3 className="font-semibold text-gray-900 mb-2">{title}</h3>
|
||||||
|
<p className="text-sm text-gray-500 leading-relaxed max-w-xs">{desc}</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
// ─── Testimonial Card ──────────────────────────────────────────────────────────
|
||||||
|
const TestimonialCard: React.FC<{
|
||||||
|
quote: string
|
||||||
|
name: string
|
||||||
|
role: string
|
||||||
|
company: string
|
||||||
|
isInView: boolean
|
||||||
|
delay: number
|
||||||
|
}> = ({ quote, name, role, company, isInView, delay }) => (
|
||||||
|
<div
|
||||||
|
className={`bg-white rounded-2xl p-6 border border-gray-200/80 shadow-sm hover:shadow-lg
|
||||||
|
transition-all duration-700 ${isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}
|
||||||
|
style={{ transitionDelay: `${delay}ms` }}
|
||||||
|
>
|
||||||
|
<div className="flex gap-1 mb-4">
|
||||||
|
{[...Array(5)].map((_, i) => (
|
||||||
|
<Star key={i} className="w-4 h-4 text-yellow-400 fill-yellow-400" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<p className="text-gray-600 text-sm leading-relaxed mb-5 italic">"{quote}"</p>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 bg-gradient-to-br from-primary-400 to-primary-600 rounded-full flex items-center justify-center">
|
||||||
|
<span className="text-white text-sm font-bold">{name[0]}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-semibold text-gray-900">{name}</p>
|
||||||
|
<p className="text-xs text-gray-500">{role} at {company}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
// LANDING PAGE
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
export const LandingPage: React.FC = () => {
|
||||||
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||||
|
const [scrolled, setScrolled] = useState(false)
|
||||||
|
|
||||||
|
const features = useInView()
|
||||||
|
const howItWorks = useInView()
|
||||||
|
const stats = useInView()
|
||||||
|
const testimonials = useInView()
|
||||||
|
const pricing = useInView()
|
||||||
|
const cta = useInView()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => setScrolled(window.scrollY > 20)
|
||||||
|
window.addEventListener('scroll', handleScroll, { passive: true })
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-white overflow-x-hidden">
|
||||||
|
|
||||||
|
{/* ── Navigation ── */}
|
||||||
|
<nav className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
|
||||||
|
scrolled ? 'bg-white/90 backdrop-blur-xl shadow-sm border-b border-gray-100' : 'bg-transparent'
|
||||||
|
}`}>
|
||||||
<div className="max-w-6xl mx-auto px-6 py-4 flex items-center justify-between">
|
<div className="max-w-6xl mx-auto px-6 py-4 flex items-center justify-between">
|
||||||
<div className="flex items-center gap-2">
|
<Link to="/" className="flex items-center gap-2.5 group">
|
||||||
<div className="w-8 h-8 bg-primary-600 rounded-lg flex items-center justify-center">
|
<div className="w-9 h-9 bg-gradient-to-br from-primary-500 to-primary-700 rounded-xl flex items-center justify-center
|
||||||
<Sparkles className="w-4 h-4 text-white" />
|
shadow-lg shadow-primary-500/20 group-hover:shadow-primary-500/40 transition-shadow">
|
||||||
|
<Sparkles className="w-4.5 h-4.5 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<span className="font-bold text-gray-900 text-lg">Contexta</span>
|
<span className="font-bold text-gray-900 text-lg tracking-tight">Contexta</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Desktop nav */}
|
||||||
|
<div className="hidden md:flex items-center gap-8">
|
||||||
|
<Link to="/marketplace" className="text-sm text-gray-600 hover:text-gray-900 transition-colors font-medium">Marketplace</Link>
|
||||||
|
<Link to="/pricing" className="text-sm text-gray-600 hover:text-gray-900 transition-colors font-medium">Pricing</Link>
|
||||||
|
<a href="#features" className="text-sm text-gray-600 hover:text-gray-900 transition-colors font-medium">Features</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<Link to="/marketplace" className="text-sm text-gray-600 hover:text-gray-900">Marketplace</Link>
|
<div className="hidden md:flex items-center gap-3">
|
||||||
<Link to="/pricing" className="text-sm text-gray-600 hover:text-gray-900">Pricing</Link>
|
<Link to="/login" className="text-sm text-gray-600 hover:text-gray-900 transition-colors font-medium px-4 py-2">
|
||||||
<Link to="/login" className="text-sm text-gray-600 hover:text-gray-900">Sign in</Link>
|
Sign in
|
||||||
<Link to="/signup" className="bg-primary-600 text-white text-sm px-4 py-2 rounded-lg hover:bg-primary-700 font-medium transition-colors">
|
</Link>
|
||||||
|
<Link to="/signup" className="bg-primary-600 text-white text-sm px-5 py-2.5 rounded-xl hover:bg-primary-700
|
||||||
|
font-semibold transition-all shadow-md shadow-primary-500/20 hover:shadow-lg hover:shadow-primary-500/30 hover:-translate-y-0.5">
|
||||||
Get started free
|
Get started free
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile hamburger */}
|
||||||
|
<button
|
||||||
|
className="md:hidden p-2 rounded-lg hover:bg-gray-100 transition-colors"
|
||||||
|
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||||
|
>
|
||||||
|
{mobileMenuOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile menu */}
|
||||||
|
{mobileMenuOpen && (
|
||||||
|
<div className="md:hidden bg-white border-t border-gray-100 px-6 py-4 space-y-3 animate-fade-in-down shadow-lg">
|
||||||
|
<Link to="/marketplace" className="block text-sm text-gray-700 py-2 font-medium" onClick={() => setMobileMenuOpen(false)}>Marketplace</Link>
|
||||||
|
<Link to="/pricing" className="block text-sm text-gray-700 py-2 font-medium" onClick={() => setMobileMenuOpen(false)}>Pricing</Link>
|
||||||
|
<hr className="border-gray-100" />
|
||||||
|
<Link to="/login" className="block text-sm text-gray-700 py-2 font-medium" onClick={() => setMobileMenuOpen(false)}>Sign in</Link>
|
||||||
|
<Link to="/signup" className="block bg-primary-600 text-white text-sm px-4 py-2.5 rounded-xl font-semibold text-center" onClick={() => setMobileMenuOpen(false)}>
|
||||||
|
Get started free
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{/* Hero */}
|
{/* ── Hero ── */}
|
||||||
<section className="max-w-6xl mx-auto px-6 pt-20 pb-16 text-center">
|
<section className="relative pt-32 pb-20 md:pt-40 md:pb-28 overflow-hidden">
|
||||||
<div className="inline-flex items-center gap-2 bg-primary-50 text-primary-700 text-sm px-3 py-1 rounded-full mb-6 font-medium">
|
{/* Background decorations */}
|
||||||
|
<div className="absolute inset-0 bg-grid opacity-50" />
|
||||||
|
<div className="absolute top-20 -left-40 w-80 h-80 bg-primary-200/30 rounded-full blur-3xl animate-float" />
|
||||||
|
<div className="absolute top-40 -right-40 w-96 h-96 bg-purple-200/20 rounded-full blur-3xl animate-float-delayed" />
|
||||||
|
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-full h-32 bg-gradient-to-t from-white to-transparent" />
|
||||||
|
|
||||||
|
<div className="relative max-w-6xl mx-auto px-6">
|
||||||
|
<div className="flex flex-col lg:flex-row items-center gap-12 lg:gap-16">
|
||||||
|
{/* Left: Text */}
|
||||||
|
<div className="flex-1 text-center lg:text-left">
|
||||||
|
<div className="inline-flex items-center gap-2 bg-primary-50 text-primary-700 text-sm px-4 py-1.5 rounded-full
|
||||||
|
mb-6 font-medium border border-primary-100 animate-fade-in-down">
|
||||||
<Zap className="w-3.5 h-3.5" />
|
<Zap className="w-3.5 h-3.5" />
|
||||||
Build AI chatbots powered by your data
|
Build AI chatbots powered by your data
|
||||||
|
<ChevronRight className="w-3.5 h-3.5" />
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-5xl font-bold text-gray-900 mb-6 leading-tight">
|
|
||||||
Turn your documents into<br />
|
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-extrabold text-gray-900 mb-6 leading-tight animate-fade-in-up tracking-tight">
|
||||||
<span className="text-primary-600">intelligent chatbots</span>
|
Turn your documents into{' '}
|
||||||
|
<span className="text-gradient">intelligent chatbots</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xl text-gray-500 max-w-2xl mx-auto mb-10">
|
|
||||||
|
<p className="text-lg sm:text-xl text-gray-500 max-w-xl mx-auto lg:mx-0 mb-10 leading-relaxed opacity-0 animate-fade-in-up" style={{ animationDelay: '200ms' }}>
|
||||||
Upload PDFs, DOCX, and CSV files to create RAG-powered chatbots in minutes.
|
Upload PDFs, DOCX, and CSV files to create RAG-powered chatbots in minutes.
|
||||||
Publish to our marketplace or export production-ready code.
|
Publish to our marketplace or export production-ready code.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center justify-center gap-4">
|
|
||||||
<Link to="/signup" className="bg-primary-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-primary-700 transition-colors flex items-center gap-2">
|
<div className="flex flex-col sm:flex-row items-center justify-center lg:justify-start gap-4 opacity-0 animate-fade-in-up" style={{ animationDelay: '400ms' }}>
|
||||||
|
<Link to="/signup" className="bg-primary-600 text-white px-7 py-3.5 rounded-xl font-semibold
|
||||||
|
hover:bg-primary-700 transition-all flex items-center gap-2 shadow-lg shadow-primary-500/25
|
||||||
|
hover:shadow-xl hover:shadow-primary-500/30 hover:-translate-y-0.5 w-full sm:w-auto justify-center text-base">
|
||||||
Start for free <ArrowRight className="w-4 h-4" />
|
Start for free <ArrowRight className="w-4 h-4" />
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/marketplace" className="border border-gray-300 text-gray-700 px-6 py-3 rounded-xl font-semibold hover:bg-gray-50 transition-colors">
|
<Link to="/marketplace" className="border border-gray-300 text-gray-700 px-7 py-3.5 rounded-xl font-semibold
|
||||||
|
hover:bg-gray-50 hover:border-gray-400 transition-all w-full sm:w-auto text-center text-base">
|
||||||
Explore marketplace
|
Explore marketplace
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-gray-400 mt-4">No credit card required • Free forever</p>
|
|
||||||
|
<p className="text-sm text-gray-400 mt-5 opacity-0 animate-fade-in" style={{ animationDelay: '600ms' }}>
|
||||||
|
No credit card required · Free forever · 2min setup
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right: Chat Preview */}
|
||||||
|
<div className="flex-shrink-0 opacity-0 animate-fade-in-up" style={{ animationDelay: '500ms' }}>
|
||||||
|
<div className="relative">
|
||||||
|
{/* Decorative glow behind */}
|
||||||
|
<div className="absolute -inset-4 bg-gradient-to-r from-primary-500/20 to-purple-500/20 rounded-3xl blur-2xl" />
|
||||||
|
<div className="relative animate-float">
|
||||||
|
<FloatingChatPreview />
|
||||||
|
</div>
|
||||||
|
{/* Floating badges */}
|
||||||
|
<div className="absolute -left-12 top-12 bg-white rounded-xl px-3 py-2 shadow-lg border border-gray-100
|
||||||
|
flex items-center gap-2 animate-bounce-subtle hidden lg:flex">
|
||||||
|
<div className="w-6 h-6 bg-green-100 rounded-full flex items-center justify-center">
|
||||||
|
<Check className="w-3.5 h-3.5 text-green-600" />
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-semibold text-gray-700">RAG Powered</span>
|
||||||
|
</div>
|
||||||
|
<div className="absolute -right-10 bottom-20 bg-white rounded-xl px-3 py-2 shadow-lg border border-gray-100
|
||||||
|
flex items-center gap-2 animate-bounce-subtle hidden lg:flex" style={{ animationDelay: '1s' }}>
|
||||||
|
<div className="w-6 h-6 bg-purple-100 rounded-full flex items-center justify-center">
|
||||||
|
<Download className="w-3.5 h-3.5 text-purple-600" />
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-semibold text-gray-700">Export Code</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Features */}
|
{/* ── Trusted By / Stats ── */}
|
||||||
<section className="bg-gray-50 py-20">
|
<section ref={stats.ref} className="py-16 border-t border-b border-gray-100 bg-gray-50/50">
|
||||||
|
<div className="max-w-5xl mx-auto px-6">
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
|
||||||
|
<AnimatedCounter end={2500} suffix="+" label="Chatbots Created" isInView={stats.isInView} />
|
||||||
|
<AnimatedCounter end={500} suffix="+" label="Companies" isInView={stats.isInView} />
|
||||||
|
<AnimatedCounter end={10} suffix="M+" label="Messages Processed" isInView={stats.isInView} />
|
||||||
|
<AnimatedCounter end={99} suffix="%" label="Uptime" isInView={stats.isInView} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* ── Features ── */}
|
||||||
|
<section id="features" ref={features.ref} className="py-20 md:py-28">
|
||||||
<div className="max-w-6xl mx-auto px-6">
|
<div className="max-w-6xl mx-auto px-6">
|
||||||
<h2 className="text-3xl font-bold text-gray-900 text-center mb-12">Everything you need</h2>
|
<div className="text-center mb-16">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className={`inline-flex items-center gap-2 bg-primary-50 text-primary-700 text-xs px-3 py-1 rounded-full
|
||||||
|
mb-4 font-semibold uppercase tracking-wider transition-all duration-500
|
||||||
|
${features.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
|
||||||
|
Features
|
||||||
|
</div>
|
||||||
|
<h2 className={`text-3xl md:text-4xl font-extrabold text-gray-900 mb-4 tracking-tight transition-all duration-700
|
||||||
|
${features.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
|
Everything you need to build
|
||||||
|
</h2>
|
||||||
|
<p className={`text-gray-500 max-w-lg mx-auto transition-all duration-700 delay-100
|
||||||
|
${features.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
|
From document upload to deployment — we handle the heavy lifting so you can focus on your business.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
||||||
{[
|
{[
|
||||||
{
|
{ icon: <Bot className="w-6 h-6" />, title: 'RAG-Powered Chatbots', desc: 'Upload your documents and let AI answer questions based on your actual content with citations.', color: 'bg-blue-100 text-blue-600' },
|
||||||
icon: <Bot className="w-6 h-6" />,
|
{ icon: <Globe className="w-6 h-6" />, title: 'Public Marketplace', desc: 'Publish your chatbots to our marketplace so customers can discover and chat with them.', color: 'bg-green-100 text-green-600' },
|
||||||
title: 'RAG-Powered Chatbots',
|
{ icon: <Code className="w-6 h-6" />, title: 'Code Export', desc: 'Export a complete FastAPI backend + React widget. Deploy anywhere. No vendor lock-in.', color: 'bg-purple-100 text-purple-600' },
|
||||||
desc: 'Upload your documents and let AI answer questions based on your actual content with citations.',
|
{ icon: <Database className="w-6 h-6" />, title: 'Multi-Format Support', desc: 'PDF, Word, Excel, CSV, and plain text files — all processed and indexed automatically.', color: 'bg-orange-100 text-orange-600' },
|
||||||
color: 'bg-blue-100 text-blue-600',
|
{ icon: <Sparkles className="w-6 h-6" />, title: 'Premium AI Models', desc: 'Access GPT-4o, Claude 3.5 Sonnet, Gemini 1.5 Pro, and open-source models.', color: 'bg-yellow-100 text-yellow-700' },
|
||||||
},
|
{ icon: <Shield className="w-6 h-6" />, title: 'Data Isolation', desc: 'Each company gets its own isolated vector database. Your data is never mixed with others.', color: 'bg-red-100 text-red-600' },
|
||||||
{
|
].map((f, i) => (
|
||||||
icon: <Globe className="w-6 h-6" />,
|
<FeatureCard key={f.title} {...f} delay={i * 100} isInView={features.isInView} />
|
||||||
title: 'Public Marketplace',
|
|
||||||
desc: 'Publish your chatbots to our marketplace so customers can discover and chat with them.',
|
|
||||||
color: 'bg-green-100 text-green-600',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Code className="w-6 h-6" />,
|
|
||||||
title: 'Code Export',
|
|
||||||
desc: 'Export a complete FastAPI backend + React widget. Deploy anywhere. No vendor lock-in.',
|
|
||||||
color: 'bg-purple-100 text-purple-600',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Database className="w-6 h-6" />,
|
|
||||||
title: 'Multi-Format Support',
|
|
||||||
desc: 'PDF, Word, Excel, CSV, and plain text files — all processed and indexed automatically.',
|
|
||||||
color: 'bg-orange-100 text-orange-600',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Sparkles className="w-6 h-6" />,
|
|
||||||
title: 'Premium AI Models',
|
|
||||||
desc: 'Access GPT-4o, Claude 3.5 Sonnet, Gemini 1.5 Pro, and open-source models.',
|
|
||||||
color: 'bg-yellow-100 text-yellow-600',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Shield className="w-6 h-6" />,
|
|
||||||
title: 'Data Isolation',
|
|
||||||
desc: 'Each company gets its own isolated vector database. Your data is never mixed with others.',
|
|
||||||
color: 'bg-red-100 text-red-600',
|
|
||||||
},
|
|
||||||
].map(({ icon, title, desc, color }) => (
|
|
||||||
<div key={title} className="bg-white rounded-2xl p-6 border border-gray-200">
|
|
||||||
<div className={`w-12 h-12 rounded-xl flex items-center justify-center mb-4 ${color}`}>
|
|
||||||
{icon}
|
|
||||||
</div>
|
|
||||||
<h3 className="font-semibold text-gray-900 mb-2">{title}</h3>
|
|
||||||
<p className="text-sm text-gray-500 leading-relaxed">{desc}</p>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Pricing teaser */}
|
{/* ── How It Works ── */}
|
||||||
<section className="max-w-4xl mx-auto px-6 py-20 text-center">
|
<section ref={howItWorks.ref} className="py-20 md:py-28 bg-gray-50/70 relative">
|
||||||
<h2 className="text-3xl font-bold text-gray-900 mb-4">Start free, scale as you grow</h2>
|
<div className="absolute inset-0 bg-dots" />
|
||||||
<p className="text-gray-500 mb-8">Build unlimited chatbots for free. Upgrade to publish and unlock premium features.</p>
|
<div className="relative max-w-5xl mx-auto px-6">
|
||||||
<div className="flex justify-center gap-4 mb-8">
|
<div className="text-center mb-16">
|
||||||
|
<div className={`inline-flex items-center gap-2 bg-primary-50 text-primary-700 text-xs px-3 py-1 rounded-full
|
||||||
|
mb-4 font-semibold uppercase tracking-wider transition-all duration-500
|
||||||
|
${howItWorks.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
|
||||||
|
How It Works
|
||||||
|
</div>
|
||||||
|
<h2 className={`text-3xl md:text-4xl font-extrabold text-gray-900 mb-4 tracking-tight transition-all duration-700
|
||||||
|
${howItWorks.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
|
Three steps to your AI chatbot
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-10 md:gap-8">
|
||||||
|
{/* Connecting line (desktop only) */}
|
||||||
|
<div className="hidden md:block absolute top-[13.5rem] left-[22%] right-[22%] h-0.5 bg-gradient-to-r from-primary-200 via-primary-400 to-primary-200 opacity-40" />
|
||||||
|
|
||||||
|
<Step num={1} icon={<Upload className="w-7 h-7 text-white" />}
|
||||||
|
title="Upload Documents" desc="Drag and drop your PDFs, DOCX, CSV, Excel, or text files. We handle parsing and chunking automatically."
|
||||||
|
isInView={howItWorks.isInView} delay={0} />
|
||||||
|
<Step num={2} icon={<Cpu className="w-7 h-7 text-white" />}
|
||||||
|
title="Configure & Train" desc="Choose your AI model, customize the system prompt, and let our RAG engine build your knowledge base."
|
||||||
|
isInView={howItWorks.isInView} delay={200} />
|
||||||
|
<Step num={3} icon={<Play className="w-7 h-7 text-white" />}
|
||||||
|
title="Deploy Anywhere" desc="Publish to the marketplace, embed on your website, or export the full source code for self-hosting."
|
||||||
|
isInView={howItWorks.isInView} delay={400} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* ── Code Export Highlight ── */}
|
||||||
|
<section className="py-20 md:py-28 overflow-hidden">
|
||||||
|
<div className="max-w-6xl mx-auto px-6">
|
||||||
|
<div className="flex flex-col lg:flex-row items-center gap-12 lg:gap-16">
|
||||||
|
{/* Code Preview */}
|
||||||
|
<div className="flex-1 w-full max-w-lg opacity-0 animate-slide-in-left" style={{ animationDelay: '200ms' }}>
|
||||||
|
<div className="bg-gray-900 rounded-2xl overflow-hidden shadow-2xl shadow-gray-900/20">
|
||||||
|
{/* Title bar */}
|
||||||
|
<div className="flex items-center gap-2 px-4 py-3 bg-gray-800/80 border-b border-gray-700/50">
|
||||||
|
<span className="w-3 h-3 rounded-full bg-red-500/80" />
|
||||||
|
<span className="w-3 h-3 rounded-full bg-yellow-500/80" />
|
||||||
|
<span className="w-3 h-3 rounded-full bg-green-500/80" />
|
||||||
|
<span className="text-gray-500 text-xs ml-2 font-mono">exported_chatbot/backend/main.py</span>
|
||||||
|
</div>
|
||||||
|
<pre className="p-5 text-sm font-mono leading-relaxed overflow-x-auto">
|
||||||
|
<code className="text-gray-300">
|
||||||
|
{`from fastapi import FastAPI
|
||||||
|
from services.rag_engine import RAGEngine
|
||||||
|
|
||||||
|
app = FastAPI(title="My Chatbot API")
|
||||||
|
rag = RAGEngine(collection="company_abc")
|
||||||
|
|
||||||
|
@app.post("/chat")
|
||||||
|
async def chat(message: str):
|
||||||
|
response = await rag.query(message)
|
||||||
|
return {
|
||||||
|
"answer": response.text,
|
||||||
|
"sources": response.citations,
|
||||||
|
"confidence": response.score
|
||||||
|
}`}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Text */}
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="inline-flex items-center gap-2 bg-purple-50 text-purple-700 text-xs px-3 py-1 rounded-full
|
||||||
|
mb-4 font-semibold uppercase tracking-wider">
|
||||||
|
<Code className="w-3.5 h-3.5" />
|
||||||
|
Unique Feature
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl md:text-4xl font-extrabold text-gray-900 mb-5 tracking-tight">
|
||||||
|
Export production-ready code
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-500 mb-8 leading-relaxed">
|
||||||
|
Unlike any other platform, Contexta lets you download a complete FastAPI backend
|
||||||
|
and React TypeScript chat widget. Deploy on your own infrastructure with zero vendor lock-in.
|
||||||
|
</p>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{[
|
||||||
|
{ icon: <FileText className="w-4 h-4" />, text: 'Complete FastAPI backend with RAG engine' },
|
||||||
|
{ icon: <MessageSquare className="w-4 h-4" />, text: 'React TypeScript chat widget' },
|
||||||
|
{ icon: <Lock className="w-4 h-4" />, text: 'Pre-configured with your data & settings' },
|
||||||
|
{ icon: <Download className="w-4 h-4" />, text: 'One-click deployment scripts included' },
|
||||||
|
].map(({ icon, text }) => (
|
||||||
|
<div key={text} className="flex items-center gap-3 group">
|
||||||
|
<div className="w-8 h-8 bg-primary-50 rounded-lg flex items-center justify-center text-primary-600
|
||||||
|
group-hover:bg-primary-100 transition-colors flex-shrink-0">
|
||||||
|
{icon}
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-gray-700 font-medium">{text}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* ── Testimonials ── */}
|
||||||
|
<section ref={testimonials.ref} className="py-20 md:py-28 bg-gray-50/70 relative">
|
||||||
|
<div className="absolute inset-0 bg-grid opacity-30" />
|
||||||
|
<div className="relative max-w-6xl mx-auto px-6">
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<div className={`inline-flex items-center gap-2 bg-primary-50 text-primary-700 text-xs px-3 py-1 rounded-full
|
||||||
|
mb-4 font-semibold uppercase tracking-wider transition-all duration-500
|
||||||
|
${testimonials.isInView ? 'opacity-100' : 'opacity-0'}`}>
|
||||||
|
Testimonials
|
||||||
|
</div>
|
||||||
|
<h2 className={`text-3xl md:text-4xl font-extrabold text-gray-900 mb-4 tracking-tight transition-all duration-700
|
||||||
|
${testimonials.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
|
Loved by builders
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
<TestimonialCard
|
||||||
|
quote="We had our support chatbot live in under an hour. The code export feature meant we could customize everything to match our brand perfectly."
|
||||||
|
name="Sarah Chen" role="CTO" company="TechFlow"
|
||||||
|
isInView={testimonials.isInView} delay={0}
|
||||||
|
/>
|
||||||
|
<TestimonialCard
|
||||||
|
quote="The data isolation gives us confidence to use this with sensitive healthcare data. Each client's information stays completely separate."
|
||||||
|
name="Marcus Johnson" role="Head of Engineering" company="MedAssist"
|
||||||
|
isInView={testimonials.isInView} delay={150}
|
||||||
|
/>
|
||||||
|
<TestimonialCard
|
||||||
|
quote="No other platform lets you export the full source code. That was the dealbreaker for us — we needed to own the entire stack."
|
||||||
|
name="Elena Kowalski" role="VP of Product" company="DataBridge"
|
||||||
|
isInView={testimonials.isInView} delay={300}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* ── Pricing Teaser ── */}
|
||||||
|
<section ref={pricing.ref} className="py-20 md:py-28">
|
||||||
|
<div className="max-w-4xl mx-auto px-6 text-center">
|
||||||
|
<h2 className={`text-3xl md:text-4xl font-extrabold text-gray-900 mb-4 tracking-tight transition-all duration-700
|
||||||
|
${pricing.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
|
Start free, scale as you grow
|
||||||
|
</h2>
|
||||||
|
<p className={`text-gray-500 mb-10 transition-all duration-700 delay-100
|
||||||
|
${pricing.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
|
Build unlimited chatbots for free. Upgrade to publish and unlock premium features.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className={`flex flex-wrap justify-center gap-x-6 gap-y-3 mb-10 transition-all duration-700 delay-200
|
||||||
|
${pricing.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
{[
|
{[
|
||||||
{ feature: 'Free forever plan', included: true },
|
{ feature: 'Free forever plan', included: true },
|
||||||
{ feature: 'Unlimited chatbot creation', included: true },
|
{ feature: 'Unlimited chatbot creation', included: true },
|
||||||
@@ -116,33 +590,78 @@ export const LandingPage: React.FC = () => (
|
|||||||
{ feature: 'Code export', included: false, note: 'Pro+' },
|
{ feature: 'Code export', included: false, note: 'Pro+' },
|
||||||
].map(({ feature, included, note }) => (
|
].map(({ feature, included, note }) => (
|
||||||
<div key={feature} className="flex items-center gap-2 text-sm">
|
<div key={feature} className="flex items-center gap-2 text-sm">
|
||||||
<div className={`w-5 h-5 rounded-full flex items-center justify-center ${included ? 'bg-green-100 text-green-600' : 'bg-gray-100 text-gray-400'}`}>
|
<div className={`w-5 h-5 rounded-full flex items-center justify-center ${
|
||||||
|
included ? 'bg-green-100 text-green-600' : 'bg-gray-100 text-gray-400'
|
||||||
|
}`}>
|
||||||
{included ? <Check className="w-3 h-3" /> : <span className="text-xs">–</span>}
|
{included ? <Check className="w-3 h-3" /> : <span className="text-xs">–</span>}
|
||||||
</div>
|
</div>
|
||||||
<span className="text-gray-700">{feature}</span>
|
<span className="text-gray-700">{feature}</span>
|
||||||
{note && <span className="text-xs text-primary-600 bg-primary-50 px-2 py-0.5 rounded-full">{note}</span>}
|
{note && (
|
||||||
|
<span className="text-xs text-primary-600 bg-primary-50 px-2 py-0.5 rounded-full font-medium">{note}</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<Link to="/pricing" className="text-primary-600 font-medium hover:underline text-sm">
|
|
||||||
View full pricing →
|
<Link to="/pricing" className={`text-primary-600 font-semibold hover:text-primary-700 text-sm inline-flex items-center gap-1.5
|
||||||
|
transition-all duration-700 delay-300 hover:gap-2.5 ${pricing.isInView ? 'opacity-100' : 'opacity-0'}`}>
|
||||||
|
View full pricing <ArrowRight className="w-4 h-4" />
|
||||||
</Link>
|
</Link>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* CTA */}
|
{/* ── CTA ── */}
|
||||||
<section className="bg-primary-600 py-16 text-center">
|
<section ref={cta.ref} className="relative py-20 md:py-24 overflow-hidden">
|
||||||
<div className="max-w-2xl mx-auto px-6">
|
{/* Gradient background */}
|
||||||
<h2 className="text-3xl font-bold text-white mb-4">Ready to build your first chatbot?</h2>
|
<div className="absolute inset-0 bg-gradient-to-br from-primary-600 via-primary-700 to-indigo-800" />
|
||||||
<p className="text-primary-100 mb-8">Join thousands of companies using Contexta to power their AI experiences.</p>
|
<div className="absolute inset-0 bg-grid opacity-10" />
|
||||||
<Link to="/signup" className="bg-white text-primary-600 px-8 py-3 rounded-xl font-semibold hover:bg-primary-50 transition-colors inline-flex items-center gap-2">
|
{/* Floating orbs */}
|
||||||
|
<div className="absolute top-10 left-10 w-40 h-40 bg-white/5 rounded-full blur-2xl animate-float" />
|
||||||
|
<div className="absolute bottom-10 right-10 w-60 h-60 bg-white/5 rounded-full blur-2xl animate-float-delayed" />
|
||||||
|
|
||||||
|
<div className="relative max-w-2xl mx-auto px-6 text-center">
|
||||||
|
<h2 className={`text-3xl md:text-4xl font-extrabold text-white mb-5 tracking-tight transition-all duration-700
|
||||||
|
${cta.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
|
Ready to build your first chatbot?
|
||||||
|
</h2>
|
||||||
|
<p className={`text-primary-100 mb-10 text-lg transition-all duration-700 delay-100
|
||||||
|
${cta.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
|
Join hundreds of companies using Contexta to power their AI experiences.
|
||||||
|
</p>
|
||||||
|
<div className={`flex flex-col sm:flex-row items-center justify-center gap-4 transition-all duration-700 delay-200
|
||||||
|
${cta.isInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||||
|
<Link to="/signup" className="bg-white text-primary-700 px-8 py-3.5 rounded-xl font-semibold
|
||||||
|
hover:bg-primary-50 transition-all inline-flex items-center gap-2 shadow-lg shadow-black/10
|
||||||
|
hover:-translate-y-0.5 w-full sm:w-auto justify-center text-base">
|
||||||
Get started for free <ArrowRight className="w-4 h-4" />
|
Get started for free <ArrowRight className="w-4 h-4" />
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link to="/marketplace" className="border border-white/30 text-white px-8 py-3.5 rounded-xl font-semibold
|
||||||
|
hover:bg-white/10 transition-all w-full sm:w-auto text-center text-base">
|
||||||
|
Explore marketplace
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* ── Footer ── */}
|
||||||
<footer className="border-t border-gray-100 py-8 text-center text-sm text-gray-400">
|
<footer className="border-t border-gray-100 py-12 bg-white">
|
||||||
<p>© 2025 Contexta. Built with ❤️ for builders.</p>
|
<div className="max-w-6xl mx-auto px-6">
|
||||||
|
<div className="flex flex-col md:flex-row items-center justify-between gap-6">
|
||||||
|
<div className="flex items-center gap-2.5">
|
||||||
|
<div className="w-7 h-7 bg-gradient-to-br from-primary-500 to-primary-700 rounded-lg flex items-center justify-center">
|
||||||
|
<Sparkles className="w-3.5 h-3.5 text-white" />
|
||||||
|
</div>
|
||||||
|
<span className="font-bold text-gray-900 tracking-tight">Contexta</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-6 text-sm text-gray-500">
|
||||||
|
<Link to="/marketplace" className="hover:text-gray-700 transition-colors">Marketplace</Link>
|
||||||
|
<Link to="/pricing" className="hover:text-gray-700 transition-colors">Pricing</Link>
|
||||||
|
<a href="#features" className="hover:text-gray-700 transition-colors">Features</a>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-gray-400">© 2025 Contexta. Built with ❤️ for builders.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
97
tailwind.config.ts
Normal file
97
tailwind.config.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import type { Config } from 'tailwindcss'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
content: [
|
||||||
|
'./index.html',
|
||||||
|
'./src/**/*.{js,ts,jsx,tsx}',
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: {
|
||||||
|
50: '#eef2ff',
|
||||||
|
100: '#e0e7ff',
|
||||||
|
200: '#c7d2fe',
|
||||||
|
300: '#a5b4fc',
|
||||||
|
400: '#818cf8',
|
||||||
|
500: '#6366f1',
|
||||||
|
600: '#4f46e5',
|
||||||
|
700: '#4338ca',
|
||||||
|
800: '#3730a3',
|
||||||
|
900: '#312e81',
|
||||||
|
950: '#1e1b4b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter', 'system-ui', '-apple-system', 'sans-serif'],
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
'fade-in': 'fadeIn 0.6s ease-out forwards',
|
||||||
|
'fade-in-up': 'fadeInUp 0.6s ease-out forwards',
|
||||||
|
'fade-in-down': 'fadeInDown 0.5s ease-out forwards',
|
||||||
|
'slide-in-left': 'slideInLeft 0.6s ease-out forwards',
|
||||||
|
'slide-in-right': 'slideInRight 0.6s ease-out forwards',
|
||||||
|
'scale-in': 'scaleIn 0.5s ease-out forwards',
|
||||||
|
'float': 'float 6s ease-in-out infinite',
|
||||||
|
'float-delayed': 'float 6s ease-in-out 2s infinite',
|
||||||
|
'pulse-soft': 'pulseSoft 3s ease-in-out infinite',
|
||||||
|
'gradient-x': 'gradientX 8s ease infinite',
|
||||||
|
'bounce-subtle': 'bounceSubtle 2s ease-in-out infinite',
|
||||||
|
'shimmer': 'shimmer 2.5s linear infinite',
|
||||||
|
'spin-slow': 'spin 8s linear infinite',
|
||||||
|
'typing': 'typing 1.5s ease-in-out infinite',
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
fadeIn: {
|
||||||
|
from: { opacity: '0' },
|
||||||
|
to: { opacity: '1' },
|
||||||
|
},
|
||||||
|
fadeInUp: {
|
||||||
|
from: { opacity: '0', transform: 'translateY(24px)' },
|
||||||
|
to: { opacity: '1', transform: 'translateY(0)' },
|
||||||
|
},
|
||||||
|
fadeInDown: {
|
||||||
|
from: { opacity: '0', transform: 'translateY(-16px)' },
|
||||||
|
to: { opacity: '1', transform: 'translateY(0)' },
|
||||||
|
},
|
||||||
|
slideInLeft: {
|
||||||
|
from: { opacity: '0', transform: 'translateX(-32px)' },
|
||||||
|
to: { opacity: '1', transform: 'translateX(0)' },
|
||||||
|
},
|
||||||
|
slideInRight: {
|
||||||
|
from: { opacity: '0', transform: 'translateX(32px)' },
|
||||||
|
to: { opacity: '1', transform: 'translateX(0)' },
|
||||||
|
},
|
||||||
|
scaleIn: {
|
||||||
|
from: { opacity: '0', transform: 'scale(0.9)' },
|
||||||
|
to: { opacity: '1', transform: 'scale(1)' },
|
||||||
|
},
|
||||||
|
float: {
|
||||||
|
'0%, 100%': { transform: 'translateY(0)' },
|
||||||
|
'50%': { transform: 'translateY(-12px)' },
|
||||||
|
},
|
||||||
|
pulseSoft: {
|
||||||
|
'0%, 100%': { opacity: '1' },
|
||||||
|
'50%': { opacity: '0.7' },
|
||||||
|
},
|
||||||
|
gradientX: {
|
||||||
|
'0%, 100%': { backgroundPosition: '0% 50%' },
|
||||||
|
'50%': { backgroundPosition: '100% 50%' },
|
||||||
|
},
|
||||||
|
bounceSubtle: {
|
||||||
|
'0%, 100%': { transform: 'translateY(0)' },
|
||||||
|
'50%': { transform: 'translateY(-4px)' },
|
||||||
|
},
|
||||||
|
shimmer: {
|
||||||
|
'0%': { backgroundPosition: '-200% 0' },
|
||||||
|
'100%': { backgroundPosition: '200% 0' },
|
||||||
|
},
|
||||||
|
typing: {
|
||||||
|
'0%, 100%': { opacity: '0.3' },
|
||||||
|
'50%': { opacity: '1' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
} satisfies Config
|
||||||
Reference in New Issue
Block a user