| import React, { useState, useEffect } from 'react';
|
| import { motion, AnimatePresence } from 'framer-motion';
|
| import { Brain, FileText, Upload, Sparkles, MessageSquare, Plus, ChevronRight } from 'lucide-react';
|
|
|
| const HeroAnimation = () => {
|
|
|
| const [step, setStep] = useState('upload');
|
|
|
|
|
| useEffect(() => {
|
| const sequence = async () => {
|
| while (true) {
|
| setStep('upload');
|
| await new Promise(r => setTimeout(r, 2000));
|
| setStep('processing');
|
| await new Promise(r => setTimeout(r, 1500));
|
| setStep('chat');
|
| await new Promise(r => setTimeout(r, 2000));
|
| setStep('mindmap');
|
| await new Promise(r => setTimeout(r, 4000));
|
|
|
| setStep('reset');
|
| await new Promise(r => setTimeout(r, 500));
|
| }
|
| };
|
| sequence();
|
| }, []);
|
|
|
| return (
|
| <div className="relative rounded-xl border border-slate-200 bg-white/50 backdrop-blur-sm shadow-2xl shadow-blue-900/10 overflow-hidden w-full max-w-4xl mx-auto aspect-[16/9]">
|
| {/* Window Controls */}
|
| <div className="bg-white border-b border-slate-100 p-3 flex items-center gap-2">
|
| <div className="flex gap-1.5">
|
| <div className="w-3 h-3 rounded-full bg-red-400/80"></div>
|
| <div className="w-3 h-3 rounded-full bg-amber-400/80"></div>
|
| <div className="w-3 h-3 rounded-full bg-green-400/80"></div>
|
| </div>
|
| <div className="flex-1 text-center">
|
| <div className="bg-slate-100 text-slate-400 text-[10px] py-1 px-3 rounded-md inline-block font-mono">
|
| vertical.ai / notebook
|
| </div>
|
| </div>
|
| </div>
|
|
|
| <div className="flex h-full pb-10">
|
| {/* 1. Sidebar (Static) */}
|
| <div className="w-1/4 border-r border-slate-100 bg-slate-50/50 p-4 hidden sm:flex flex-col gap-3">
|
| <div className="w-full h-8 bg-blue-600/10 rounded-lg border border-blue-600/20 flex items-center px-3 gap-2">
|
| <Plus size={14} className="text-blue-600" />
|
| <span className="text-xs font-medium text-blue-700">New Note</span>
|
| </div>
|
| <div className="space-y-2 mt-2">
|
| {[1, 2, 3].map((i) => (
|
| <div key={i} className="flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-slate-200/50">
|
| <FileText size={12} className="text-slate-400" />
|
| <div className="h-2 w-16 bg-slate-200 rounded-full"></div>
|
| </div>
|
| ))}
|
| </div>
|
|
|
| {/* Active Paper Upload */}
|
| <AnimatePresence>
|
| {step !== 'reset' && (
|
| <motion.div
|
| initial={{ opacity: 0, y: 20 }}
|
| animate={{ opacity: 1, y: 0 }}
|
| className="mt-auto bg-white border border-slate-200 p-3 rounded-lg shadow-sm"
|
| >
|
| <div className="flex items-center gap-2 mb-2">
|
| <div className="p-1.5 bg-red-100 text-red-600 rounded">
|
| <FileText size={14} />
|
| </div>
|
| <div className="text-[10px] font-medium text-slate-700 truncate">
|
| Attention_Is_All_You_Need.pdf
|
| </div>
|
| </div>
|
| <div className="h-1 w-full bg-slate-100 rounded-full overflow-hidden">
|
| <motion.div
|
| className="h-full bg-green-500"
|
| initial={{ width: "0%" }}
|
| animate={{ width: step === 'upload' ? "60%" : "100%" }}
|
| transition={{ duration: 1 }}
|
| />
|
| </div>
|
| </motion.div>
|
| )}
|
| </AnimatePresence>
|
| </div>
|
|
|
| {/* 2. Main Area */}
|
| <div className="flex-1 flex flex-col relative overflow-hidden">
|
| {/* Chat Area */}
|
| <div className="flex-1 p-6 space-y-6">
|
| {/* User Message */}
|
| <AnimatePresence>
|
| {(step === 'processing' || step === 'chat' || step === 'mindmap') && (
|
| <motion.div
|
| initial={{ opacity: 0, x: 20 }}
|
| animate={{ opacity: 1, x: 0 }}
|
| className="flex justify-end"
|
| >
|
| <div className="bg-slate-100 text-slate-700 px-4 py-2.5 rounded-2xl rounded-tr-sm text-sm font-medium shadow-sm max-w-[80%]">
|
| Explain the Transformer architecture logic.
|
| </div>
|
| </motion.div>
|
| )}
|
| </AnimatePresence>
|
|
|
| {/* AI Response */}
|
| <AnimatePresence>
|
| {(step === 'chat' || step === 'mindmap') && (
|
| <motion.div
|
| initial={{ opacity: 0, x: -20 }}
|
| animate={{ opacity: 1, x: 0 }}
|
| transition={{ delay: 0.2 }}
|
| className="flex gap-3"
|
| >
|
| <div className="w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 flex items-center justify-center text-white shadow-md shrink-0">
|
| <Sparkles size={14} />
|
| </div>
|
| <div className="space-y-2 max-w-[90%]">
|
| <div className="text-xs font-bold text-slate-800 flex items-center gap-2">
|
| Vertical AI
|
| <span className="text-[10px] px-1.5 py-0.5 bg-green-100 text-green-700 rounded-full font-medium">Verified Sources</span>
|
| </div>
|
| <div className="text-sm text-slate-600 leading-relaxed bg-white p-4 rounded-xl border border-slate-100 shadow-sm">
|
| <p className="mb-2">The Transformer architecture replaces RNNs with self-attention mechanisms.</p>
|
| <div className="flex gap-2 mt-3">
|
| <div className="h-2 w-24 bg-slate-100 rounded animate-pulse"></div>
|
| <div className="h-2 w-16 bg-slate-100 rounded animate-pulse"></div>
|
| </div>
|
| </div>
|
| </div>
|
| </motion.div>
|
| )}
|
| </AnimatePresence>
|
| </div>
|
|
|
| {/* Processing Overlay */}
|
| <AnimatePresence>
|
| {step === 'processing' && (
|
| <motion.div
|
| initial={{ opacity: 0 }}
|
| animate={{ opacity: 1 }}
|
| exit={{ opacity: 0 }}
|
| className="absolute inset-0 bg-white/60 backdrop-blur-sm flex items-center justify-center z-10"
|
| >
|
| <div className="flex flex-col items-center gap-3">
|
| <motion.div
|
| animate={{ rotate: 360 }}
|
| transition={{ repeat: Infinity, duration: 2, ease: "linear" }}
|
| >
|
| <Brain size={32} className="text-blue-500" />
|
| </motion.div>
|
| <div className="text-sm font-bold text-blue-900">Analyzing Knowledge Graph...</div>
|
| </div>
|
| </motion.div>
|
| )}
|
| </AnimatePresence>
|
|
|
| {/* Mind Map Overlay (Pops up at end) */}
|
| <AnimatePresence>
|
| {step === 'mindmap' && (
|
| <motion.div
|
| initial={{ scale: 0.8, opacity: 0, y: 50 }}
|
| animate={{ scale: 1, opacity: 1, y: 0 }}
|
| transition={{ type: "spring", bounce: 0.4 }}
|
| className="absolute bottom-6 right-6 bg-white border border-slate-200 shadow-2xl rounded-xl p-4 w-64 z-20"
|
| >
|
| <div className="flex items-center justify-between mb-3">
|
| <div className="flex items-center gap-2">
|
| <Brain size={16} className="text-purple-600" />
|
| <span className="text-xs font-bold text-slate-700">Concept Map</span>
|
| </div>
|
| <ChevronRight size={14} className="text-slate-400" />
|
| </div>
|
| {/* Mock Graph Nodes */}
|
| <div className="h-32 relative bg-slate-50 rounded-lg border border-slate-100 overflow-hidden">
|
| <motion.div
|
| initial={{ scale: 0 }} animate={{ scale: 1 }} transition={{ delay: 0.2 }}
|
| className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-12 h-8 bg-blue-100 border border-blue-300 rounded flex items-center justify-center text-[8px] font-bold text-blue-700 z-10"
|
| >
|
| Attention
|
| </motion.div>
|
|
|
| {/* Satellite Nodes */}
|
| {[0, 1, 2].map((i) => (
|
| <motion.div
|
| key={i}
|
| initial={{ scale: 0, x: "-50%", y: "-50%" }}
|
| animate={{
|
| scale: 1,
|
| left: i === 0 ? '20%' : i === 1 ? '80%' : '50%',
|
| top: i === 0 ? '30%' : i === 1 ? '40%' : '80%'
|
| }}
|
| transition={{ delay: 0.4 + (i * 0.1) }}
|
| className="absolute w-8 h-8 rounded-full bg-white border border-slate-200 shadow-sm flex items-center justify-center text-[10px]"
|
| >
|
| <div className="w-1.5 h-1.5 rounded-full bg-purple-400"></div>
|
| </motion.div>
|
| ))}
|
|
|
| {/* Connecting Lines */}
|
| <svg className="absolute inset-0 w-full h-full pointer-events-none">
|
| <motion.line
|
| initial={{ pathLength: 0 }} animate={{ pathLength: 1 }}
|
| x1="50%" y1="50%" x2="20%" y2="30%" stroke="#cbd5e1" strokeWidth="1"
|
| />
|
| <motion.line
|
| initial={{ pathLength: 0 }} animate={{ pathLength: 1 }}
|
| x1="50%" y1="50%" x2="80%" y2="40%" stroke="#cbd5e1" strokeWidth="1"
|
| />
|
| <motion.line
|
| initial={{ pathLength: 0 }} animate={{ pathLength: 1 }}
|
| x1="50%" y1="50%" x2="50%" y2="80%" stroke="#cbd5e1" strokeWidth="1"
|
| />
|
| </svg>
|
| </div>
|
| </motion.div>
|
| )}
|
| </AnimatePresence>
|
| </div>
|
| </div>
|
| </div>
|
| );
|
| };
|
|
|
| export default HeroAnimation;
|
|
|