Merge version_6 into main #13

Merged
bender merged 2 commits from version_6 into main 2026-03-03 19:20:58 +00:00
2 changed files with 254 additions and 153 deletions

View File

@@ -12,7 +12,7 @@ import FaqDouble from '@/components/sections/faq/FaqDouble';
import ContactFaq from '@/components/sections/contact/ContactFaq';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import { Sparkles, Zap, Lightbulb, Rocket, Users, Star, HelpCircle, Download, Moon, Sun } from 'lucide-react';
import AnimatedChatDemo from '@/components/sections/animated-chat-demo/AnimatedChatDemo';
import AnimatedChatDemo from '@/components/sections/demo/AnimatedChatDemo';
export default function LandingPage() {
const [isDarkMode, setIsDarkMode] = useState(false);

View File

@@ -1,183 +1,284 @@
"use client";
import React, { useState, useEffect } from "react";
import { MessageCircle, CheckCircle2, Loader, Sparkles } from "lucide-react";
import React, { useState, useEffect, useRef } from "react";
import { Send } from "lucide-react";
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
interface ChatMessage {
id: string;
text: string;
isUser: boolean;
isComplete?: boolean;
}
const appIdeas = [
"Weather forecast app with beautiful UI", "Habit tracking app with reminders", "Expense manager with analytics", "Meditation guide with daily lessons", "Recipe collection app with ratings"
interface AppIdea {
id: string;
title: string;
description: string;
}
const appIdeas: AppIdea[] = [
{
id: "1", title: "Weather Dashboard", description: "A beautiful real-time weather app with hourly forecasts and weather alerts"
},
{
id: "2", title: "Todo Manager", description: "A productivity app with task organization, categories, and smart reminders"
},
{
id: "3", title: "Budget Tracker", description: "Personal finance app with spending analytics and budget goals tracking"
}
];
const processStages = [
{ label: "Design", icon: "🎨" },
{ label: "Planning", icon: "📋" },
{ label: "Coding", icon: "💻" }
];
const AnimatedChatDemo: React.FC = () => {
const [currentIdea, setCurrentIdea] = useState(0);
const [animationPhase, setAnimationPhase] = useState(0);
const [showProcessFlow, setShowProcessFlow] = useState(false);
const [showFinishedApp, setShowFinishedApp] = useState(false);
export default function AnimatedChatDemo() {
const [stage, setStage] = useState<"chat" | "process" | "finished">("chat");
const [currentIdeaIndex, setCurrentIdeaIndex] = useState(0);
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [processSteps, setProcessSteps] = useState<Array<{ name: string; active: boolean }>>([]);
const [finishedApp, setFinishedApp] = useState<AppIdea | null>(null);
const [isAutoPlaying, setIsAutoPlaying] = useState(true);
const timelineRef = useRef<gsap.core.Timeline | null>(null);
// Stage 1: Chat simulation with auto-filling and sending
useEffect(() => {
// Auto-cycle through app ideas
const ideaCycle = setInterval(() => {
setCurrentIdea((prev) => (prev + 1) % appIdeas.length);
if (stage !== "chat" || !isAutoPlaying) return;
let timeoutId: NodeJS.Timeout;
const currentIdea = appIdeas[currentIdeaIndex];
// Clear messages and start fresh
if (messages.length === 0) {
timeoutId = setTimeout(() => {
// Add user message character by character
const userMessage = currentIdea.description;
let charIndex = 0;
const typeInterval = setInterval(() => {
if (charIndex <= userMessage.length) {
setMessages((prev) => {
if (prev.length === 0 || !prev[prev.length - 1].isUser) {
return [
...prev,
{
id: `user-${Date.now()}`,
text: userMessage.substring(0, charIndex),
isUser: true,
isComplete: false
}
];
} else {
const updated = [...prev];
updated[updated.length - 1].text = userMessage.substring(0, charIndex);
return updated;
}
});
charIndex++;
} else {
clearInterval(typeInterval);
// Mark message as complete and move to next stage
setTimeout(() => {
setMessages((prev) => {
const updated = [...prev];
if (updated.length > 0) {
updated[updated.length - 1].isComplete = true;
}
return updated;
});
// Auto-send and transition to process
setTimeout(() => {
setStage("process");
}, 800);
}, 500);
}
}, 30);
}, 500);
}
return () => clearTimeout(timeoutId);
}, [stage, currentIdeaIndex, messages.length, isAutoPlaying]);
// Stage 2: Process flow animation
useEffect(() => {
if (stage !== "process" || !isAutoPlaying) return;
const steps = [
{ name: "Design", active: false },
{ name: "Planning", active: false },
{ name: "Coding", active: false }
];
setProcessSteps(steps);
let stepIndex = 0;
const stepInterval = setInterval(() => {
if (stepIndex < steps.length) {
setProcessSteps((prev) =>
prev.map((step, idx) => ({
...step,
active: idx === stepIndex
}))
);
stepIndex++;
} else {
clearInterval(stepInterval);
// Transition to finished
setTimeout(() => {
setStage("finished");
setFinishedApp(appIdeas[currentIdeaIndex]);
}, 1000);
}
}, 1200);
return () => clearInterval(stepInterval);
}, [stage, currentIdeaIndex, isAutoPlaying]);
// Stage 3: Finished app display and loop
useEffect(() => {
if (stage !== "finished" || !isAutoPlaying) return;
const loopTimeout = setTimeout(() => {
const nextIndex = (currentIdeaIndex + 1) % appIdeas.length;
setCurrentIdeaIndex(nextIndex);
setStage("chat");
setMessages([]);
setProcessSteps([]);
setFinishedApp(null);
}, 4000);
return () => clearInterval(ideaCycle);
}, []);
useEffect(() => {
// Animate through phases
const phaseTimeline = gsap.timeline({ repeat: -1, repeatDelay: 1 });
phaseTimeline
.to({}, { duration: 2 }, 0)
.to({}, { onComplete: () => setAnimationPhase(1) }, 2)
.to({}, { duration: 1 }, 2)
.to({}, { onComplete: () => setShowProcessFlow(true) }, 3)
.to({}, { duration: 2 }, 3)
.to({}, { onComplete: () => setShowFinishedApp(true) }, 5)
.to({}, { duration: 3 }, 5);
return () => phaseTimeline.kill();
}, []);
return () => clearTimeout(loopTimeout);
}, [stage, currentIdeaIndex, isAutoPlaying]);
return (
<section className="py-16 md:py-24 relative overflow-hidden">
<div className="w-full max-w-7xl mx-auto px-4 md:px-6">
<div className="text-center mb-12 md:mb-16">
<div className="inline-flex items-center gap-2 mb-4 px-3 py-1 rounded-full bg-primary-cta/10">
<Sparkles className="w-4 h-4 text-primary-cta" />
<span className="text-sm font-medium text-primary-cta">AI-Powered Magic</span>
</div>
<h2 className="text-3xl md:text-5xl font-bold mb-4">See It In Action</h2>
<p className="text-lg text-foreground/70 max-w-2xl mx-auto">
Watch how Native Line transforms your app ideas into production-ready code in real-time
<div className="w-full py-20 px-4 sm:px-6 lg:px-8 bg-gradient-to-b from-background via-background to-background-accent/10">
<div className="max-w-4xl mx-auto">
{/* Section Header */}
<div className="text-center mb-16 opacity-0 animate-in fade-in slide-in-from-bottom-4 duration-700">
<p className="text-sm font-semibold text-primary-cta mb-2">INTERACTIVE DEMO</p>
<h2 className="text-3xl sm:text-4xl md:text-5xl font-bold mb-4">See It In Action</h2>
<p className="text-base sm:text-lg text-foreground/70 max-w-2xl mx-auto">
Watch how Native Line transforms your ideas into complete apps in real-time
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 md:gap-12 items-center">
{/* Chat Box - Left Side */}
<div className="flex flex-col h-96 md:h-[500px] bg-card rounded-2xl border border-accent/20 overflow-hidden shadow-lg">
{/* Chat Header */}
<div className="bg-gradient-to-r from-primary-cta to-primary-cta/80 px-4 md:px-6 py-3 md:py-4 flex items-center gap-2">
<MessageCircle className="w-5 h-5 text-primary-cta-text" />
<span className="text-primary-cta-text font-semibold">Native Line Assistant</span>
</div>
{/* Chat Messages */}
<div className="flex-1 overflow-y-auto p-4 md:p-6 space-y-4 flex flex-col justify-end">
{/* Initial Message */}
<div className="flex justify-start">
<div className="bg-background/80 px-4 py-2 rounded-lg max-w-xs md:max-w-sm text-sm md:text-base">
<p className="text-foreground">What app would you like to build today?</p>
</div>
</div>
{/* Auto-filling User Input */}
<div className="flex justify-end gap-2 items-end">
<div className="bg-primary-cta text-primary-cta-text px-4 py-2 rounded-lg max-w-xs md:max-w-sm text-sm md:text-base">
<p className="min-h-6">
{appIdeas[currentIdea].split("").map((char, i) => (
<span
key={i}
className={`inline-block transition-opacity duration-100 ${
i < appIdeas[currentIdea].length * (animationPhase / 3)
? "opacity-100"
: "opacity-0"
{/* Main Demo Container */}
<div className="relative">
{/* Chat Stage */}
{stage === "chat" && (
<div className="animate-in fade-in duration-500">
<div className="bg-card border border-accent/20 rounded-lg p-6 sm:p-8 shadow-lg">
<div className="space-y-4 mb-6 h-40 flex flex-col justify-center">
{messages.map((msg) => (
<div
key={msg.id}
className={`flex ${msg.isUser ? "justify-end" : "justify-start"} animate-in fade-in slide-in-from-bottom-2 duration-300`}
>
<div
className={`px-4 py-2 rounded-lg max-w-xs ${
msg.isUser
? "bg-primary-cta text-white"
: "bg-background text-foreground border border-accent/30"
}`}
>
{char}
</span>
))}
</p>
</div>
{animationPhase >= 1 && (
<div className="animate-pulse">
<CheckCircle2 className="w-5 h-5 text-green-500" />
</div>
)}
</div>
{/* Response Message with Loading */}
{animationPhase >= 1 && (
<div className="flex justify-start gap-2 items-end">
{animationPhase < 2 ? (
<div className="flex gap-2">
<Loader className="w-5 h-5 text-primary-cta animate-spin" />
<span className="text-sm text-foreground/60">Generating your app...</span>
</div>
) : (
<div className="bg-background/80 px-4 py-2 rounded-lg text-sm text-foreground/80">
App generation complete! Processing stages...
</div>
)}
</div>
)}
</div>
</div>
{/* Process Flow & Finished App - Right Side */}
<div className="flex flex-col gap-6">
{/* Process Flow */}
{showProcessFlow && (
<div className="space-y-4 animate-in fade-in slide-in-from-bottom-4 duration-700">
<h3 className="text-lg font-semibold text-foreground">Processing Stages</h3>
<div className="space-y-3">
{processStages.map((stage, index) => (
<div
key={index}
className="flex items-center gap-3 p-3 bg-background/40 rounded-lg border border-accent/20 animate-in fade-in slide-in-from-left-4"
style={{
animationDelay: `${index * 0.2}s`,
animationFillMode: "both"
}}
>
<div className="text-2xl">{stage.icon}</div>
<span className="font-medium text-foreground text-sm md:text-base">{stage.label}</span>
{index <= 2 && (
<div className="ml-auto">
<CheckCircle2 className="w-5 h-5 text-green-500" />
</div>
)}
<p className="text-sm">{msg.text}</p>
{msg.isComplete && msg.isUser && (
<div className="mt-2 flex justify-end">
<Send className="w-4 h-4" />
</div>
)}
</div>
</div>
))}
</div>
</div>
)}
</div>
)}
{/* Finished App Preview */}
{showFinishedApp && (
<div className="space-y-4 animate-in fade-in slide-in-from-bottom-4 duration-700">
<h3 className="text-lg font-semibold text-foreground">Your App is Ready!</h3>
<div className="grid grid-cols-2 gap-3">
<div className="aspect-square bg-gradient-to-br from-primary-cta/20 to-accent/20 rounded-lg border border-accent/30 p-4 flex flex-col items-center justify-center text-center">
<div className="text-3xl mb-2">📱</div>
<span className="text-xs font-medium text-foreground">iOS App</span>
{/* Process Flow Stage */}
{stage === "process" && (
<div className="animate-in fade-in duration-500">
<div className="flex justify-center items-center gap-2 sm:gap-4 h-40 flex-wrap">
{processSteps.map((step, idx) => (
<div key={idx} className="flex items-center">
<div
className={`w-16 sm:w-20 h-16 sm:h-20 rounded-full flex items-center justify-center text-sm font-semibold transition-all duration-500 ${
step.active
? "bg-primary-cta text-white scale-110 shadow-lg animate-pulse"
: "bg-background border-2 border-accent/30 text-foreground"
}`}
>
{step.name}
</div>
{idx < processSteps.length - 1 && (
<div
className={`w-8 sm:w-12 h-1 mx-1 sm:mx-2 transition-all duration-500 ${
processSteps[idx + 1].active ? "bg-primary-cta" : "bg-accent/20"
}`}
/>
)}
</div>
<div className="aspect-square bg-gradient-to-br from-accent/20 to-primary-cta/20 rounded-lg border border-accent/30 p-4 flex flex-col items-center justify-center text-center">
<div className="text-3xl mb-2">🖥</div>
<span className="text-xs font-medium text-foreground">macOS App</span>
))}
</div>
</div>
)}
{/* Finished App Stage */}
{stage === "finished" && finishedApp && (
<div className="animate-in fade-in duration-700">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 items-center">
{/* App Image - Right */}
<div className="order-2 md:order-2 h-64 sm:h-80 bg-gradient-to-br from-primary-cta/10 to-accent/10 rounded-lg border border-accent/30 flex items-center justify-center animate-in fade-in slide-in-from-right-4 duration-700">
<div className="text-center">
<div className="w-20 h-20 sm:w-24 sm:h-24 bg-primary-cta/20 rounded-full mx-auto mb-4 flex items-center justify-center">
<div className="w-16 h-16 sm:w-20 sm:h-20 bg-primary-cta rounded-full" />
</div>
<p className="text-sm text-foreground/50">App Preview</p>
</div>
</div>
<div className="bg-background/60 rounded-lg border border-accent/30 p-4">
<p className="text-sm text-foreground/80">
<span className="font-semibold text-primary-cta">100% Native Swift</span> Ready to deploy Full source code included
</p>
{/* App Details - Left */}
<div className="order-1 md:order-1 animate-in fade-in slide-in-from-left-4 duration-700 space-y-4">
<div>
<h3 className="text-2xl sm:text-3xl font-bold mb-2">{finishedApp.title}</h3>
<p className="text-foreground/70 text-sm sm:text-base">{finishedApp.description}</p>
</div>
<div className="space-y-2 pt-4">
<p className="text-xs sm:text-sm font-semibold text-primary-cta"> Production-Ready Code</p>
<p className="text-xs sm:text-sm font-semibold text-primary-cta"> Ready to Deploy</p>
<p className="text-xs sm:text-sm font-semibold text-primary-cta"> Fully Yours to Modify</p>
</div>
</div>
</div>
)}
</div>
</div>
)}
</div>
{/* Loop Indicator */}
<div className="mt-12 flex justify-center gap-2">
{appIdeas.map((idea, idx) => (
<button
key={idea.id}
onClick={() => {
setCurrentIdeaIndex(idx);
setStage("chat");
setMessages([]);
setProcessSteps([]);
setFinishedApp(null);
}}
className={`w-2 h-2 rounded-full transition-all duration-300 ${
idx === currentIdeaIndex ? "bg-primary-cta w-8" : "bg-accent/30"
}`}
aria-label={`Show ${idea.title}`}
/>
))}
</div>
{/* Auto-play Toggle */}
<div className="mt-8 flex justify-center">
<button
onClick={() => setIsAutoPlaying(!isAutoPlaying)}
className="px-4 py-2 text-sm rounded-full border border-accent/30 hover:bg-card transition-colors"
>
{isAutoPlaying ? "Pause" : "Play"}
</button>
</div>
</div>
</section>
</div>
);
};
export default AnimatedChatDemo;
}