23 Commits

Author SHA1 Message Date
632d5f5b0e Update src/app/page.tsx 2026-03-03 19:44:01 +00:00
02a2e47483 Update src/app/page.tsx 2026-03-03 19:32:28 +00:00
01d82f500e Update src/app/styles/variables.css 2026-03-03 19:27:50 +00:00
499470486b Update src/app/styles/base.css 2026-03-03 19:27:50 +00:00
fa87385a30 Update src/app/page.tsx 2026-03-03 19:27:50 +00:00
4fca796f17 Update src/app/layout.tsx 2026-03-03 19:27:49 +00:00
86fd66cd4f Merge version_6 into main
Merge version_6 into main
2026-03-03 19:20:57 +00:00
d87ad0467b Update src/components/sections/demo/AnimatedChatDemo.tsx 2026-03-03 19:20:53 +00:00
60e5eaee78 Update src/app/page.tsx 2026-03-03 19:20:52 +00:00
0b1452ab23 Merge version_6 into main
Merge version_6 into main
2026-03-03 19:18:35 +00:00
f7a8a7d76a Add src/components/sections/animated-chat-demo/AnimatedChatDemo.tsx 2026-03-03 19:18:31 +00:00
f40adddf1b Update src/app/styles/base.css 2026-03-03 19:18:31 +00:00
2a8ba69422 Update src/app/page.tsx 2026-03-03 19:18:30 +00:00
4f2137d411 Update src/app/layout.tsx 2026-03-03 19:18:29 +00:00
f145cfbe21 Update src/app/globals.css 2026-03-03 19:18:28 +00:00
1b10b9c9a3 Merge version_6 into main
Merge version_6 into main
2026-03-03 18:59:40 +00:00
d2f6a92f5d Update src/app/layout.tsx 2026-03-03 18:59:36 +00:00
f6c54fbecd Merge version_6 into main
Merge version_6 into main
2026-03-03 18:57:15 +00:00
88bc009d32 Add src/components/sections/demo/AnimatedChatDemo.tsx 2026-03-03 18:57:07 +00:00
699db63ab6 Update src/app/page.tsx 2026-03-03 18:57:05 +00:00
b7bc3df039 Update src/app/layout.tsx 2026-03-03 18:57:03 +00:00
6310a94da7 Merge version_5 into main
Merge version_5 into main
2026-03-03 18:48:46 +00:00
0095283904 Merge version_5 into main
Merge version_5 into main
2026-03-03 18:42:00 +00:00
7 changed files with 754 additions and 93 deletions

View File

@@ -1,5 +1,145 @@
@import "tailwindcss";
@import "./styles/variables.css";
@import "./styles/theme.css";
@import "./styles/utilities.css";
@import "./styles/base.css";
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');
@layer base {
* {
@apply m-0 p-0 box-border;
}
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
@apply bg-background text-foreground overflow-x-hidden;
font-family: var(--font-inter), sans-serif;
font-weight: 400;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: inherit;
}
}
@layer utilities {
.rounded-theme {
@apply rounded-md;
}
.rounded-theme-capped {
@apply rounded-2xl;
}
.rounded-theme-sharp {
@apply rounded-none;
}
.rounded-theme-pill {
@apply rounded-full;
}
.p-content {
@apply px-6 sm:px-8 lg:px-10 py-8 sm:py-12 lg:py-16;
}
.w-content-width {
width: var(--width-content-width);
}
.max-w-content-width {
max-width: var(--width-content-width);
}
.animate-in {
animation: fadeInUp 0.6s ease-out forwards;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fadeIn 0.5s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.slide-in-from-bottom-2 {
animation: slideInFromBottom2 0.4s ease-out;
}
@keyframes slideInFromBottom2 {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.slide-in-from-bottom-4 {
animation: slideInFromBottom4 0.5s ease-out;
}
@keyframes slideInFromBottom4 {
from {
opacity: 0;
transform: translateY(16px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.slide-in-from-left-4 {
animation: slideInFromLeft4 0.6s ease-out;
}
@keyframes slideInFromLeft4 {
from {
opacity: 0;
transform: translateX(-16px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.slide-in-from-right-4 {
animation: slideInFromRight4 0.6s ease-out;
}
@keyframes slideInFromRight4 {
from {
opacity: 0;
transform: translateX(16px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
}

View File

@@ -1,13 +1,7 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { Poppins } from "next/font/google";
import "./styles/variables.css";
import "./globals.css";
import { ServiceWrapper } from "@/components/ServiceWrapper";
import Tag from "@/tag/Tag";
const inter = Inter({
variable: "--font-inter", subsets: ["latin"],
});
const poppins = Poppins({
variable: "--font-poppins", subsets: ["latin"],
@@ -15,40 +9,18 @@ const poppins = Poppins({
});
export const metadata: Metadata = {
title: "Native Line - Build Native Apps Just Talk", description: "Create production-ready iOS, iPad, and Mac apps with conversational AI. No code, no compromise. Native Line turns your ideas into native Swift apps instantly.", keywords: "native app builder, iOS development, app generator, no-code, Swift, indie developers, app creation, AI, macOS", metadataBase: new URL("https://nativeline.app"),
alternates: {
canonical: "https://nativeline.app"
},
openGraph: {
title: "Native Line - Build Native Apps Just Talk", description: "Create production-ready iOS, iPad, and Mac apps with conversational AI. Native Line turns your ideas into native Swift apps instantly.", url: "https://nativeline.app", siteName: "Native Line", type: "website", images: [
{
url: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AQRMtx5ZUGLrwvjDcVIYHeaKiH/a-sleek-macos-application-window-showing-1772522998510-05a82eb5.png", alt: "Native Line App Builder Interface"
}
]
},
twitter: {
card: "summary_large_image", title: "Native Line - Build Native Apps Just Talk", description: "Create production-ready iOS, iPad, and Mac apps with conversational AI. No code, no compromise.", images: ["https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AQRMtx5ZUGLrwvjDcVIYHeaKiH/a-sleek-macos-application-window-showing-1772522998510-05a82eb5.png"]
},
robots: {
index: true,
follow: true
}
};
title: "Native Line - Build Native Apps Just Talk", description: "Turn your ideas into production-ready iOS, iPad, and Mac apps instantly. Pure native Swift, beautifully designed, completely yours."};
export default function RootLayout({
children,
}: Readonly<{
}: {
children: React.ReactNode;
}>) {
}) {
return (
<html lang="en" suppressHydrationWarning>
<ServiceWrapper>
<body
className={`${inter.variable} ${poppins.variable} antialiased`}
>
<Tag />
{children}
<html lang="en">
<body className={poppins.variable}>
{children}
<script
dangerouslySetInnerHTML={{
__html: `
@@ -1416,7 +1388,6 @@ export default function RootLayout({
}}
/>
</body>
</ServiceWrapper>
</html>
);
}

View File

@@ -11,23 +11,24 @@ import TestimonialCardFive from '@/components/sections/testimonial/TestimonialCa
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 { Sparkles, Zap, Lightbulb, Rocket, Users, Star, HelpCircle, Download } from 'lucide-react';
import AnimatedChatDemo from '@/components/sections/demo/AnimatedChatDemo';
export default function LandingPage() {
const [isDarkMode, setIsDarkMode] = useState(false);
return (
<ThemeProvider
defaultButtonVariant="hover-magnetic"
defaultTextAnimation="reveal-blur"
borderRadius="soft"
contentWidth="small"
defaultButtonVariant="expand-hover"
defaultTextAnimation="entrance-slide"
borderRadius="rounded"
contentWidth="medium"
sizing="mediumLargeSizeLargeTitles"
background="noise"
cardStyle="soft-shadow"
primaryButtonStyle="flat"
secondaryButtonStyle="layered"
headingFontWeight="extrabold"
background="none"
cardStyle="glass-elevated"
primaryButtonStyle="shadow"
secondaryButtonStyle="glass"
headingFontWeight="semibold"
>
<div id="nav" data-section="nav">
<NavbarStyleCentered
@@ -90,6 +91,10 @@ export default function LandingPage() {
/>
</div>
<div id="chatDemo" data-section="chatDemo">
<AnimatedChatDemo />
</div>
<div id="features" data-section="features">
<FeatureCardNineteen
title="Why Choose Native Line"

View File

@@ -1,28 +1,7 @@
* {
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 1) rgba(255, 255, 255, 0);
}
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');
html {
overscroll-behavior: none;
overscroll-behavior-y: none;
}
body {
background-color: var(--background);
color: var(--foreground);
font-family: var(--font-inter), sans-serif;
position: relative;
min-height: 100vh;
overscroll-behavior: none;
overscroll-behavior-y: none;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: var(--font-inter), sans-serif;
@layer base {
body {
font-family: var(--font-poppins), sans-serif;
}
}

View File

@@ -2,23 +2,23 @@
/* Base units */
/* --vw is set by ThemeProvider */
/* --background: #f5f3f0;;;
--card: #fdfcfb;;;
--foreground: #2a2520e6;;;
--primary-cta: #c69c7b;;;
--secondary-cta: #fdfcfb;;;
--accent: #e8dfd5;;;
--background-accent: #d4c4b0;;; */
/* --background: #ffffff;;;
--card: #f9f9f9;;;
--foreground: #000612e6;;;
--primary-cta: #106EFB;;;
--secondary-cta: #f9f9f9;;;
--accent: #e2e2e2;;;
--background-accent: #106EFB;;; */
--background: #f5f3f0;;;
--card: #fdfcfb;;;
--foreground: #2a2520e6;;;
--primary-cta: #c69c7b;;;
--background: #ffffff;;;
--card: #f9f9f9;;;
--foreground: #000612e6;;;
--primary-cta: #106EFB;;;
--primary-cta-text: #ffffff;;;
--secondary-cta: #fdfcfb;;;
--secondary-cta-text: #120a00e6;;;
--accent: #e8dfd5;;;
--background-accent: #d4c4b0;;;
--secondary-cta: #f9f9f9;;;
--secondary-cta-text: #000612e6;;;
--accent: #e2e2e2;;;
--background-accent: #106EFB;;;
/* text sizing - set by ThemeProvider */
/* --text-2xs: clamp(0.465rem, 0.62vw, 0.62rem);

View File

@@ -0,0 +1,282 @@
"use client";
import React, { useState, useEffect } from "react";
import { Send } from "lucide-react";
interface ChatMessage {
id: string;
text: string;
isUser: boolean;
isComplete?: boolean;
}
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"
}
];
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);
// Stage 1: Chat simulation with auto-filling and sending
useEffect(() => {
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 () => clearTimeout(loopTimeout);
}, [stage, currentIdeaIndex, isAutoPlaying]);
return (
<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>
{/* 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"
}`}
>
<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>
)}
{/* 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>
</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>
{/* 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>
{/* 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>
</div>
);
}

View File

@@ -0,0 +1,284 @@
"use client";
import React, { useState, useEffect, useRef } from "react";
import { Send } from "lucide-react";
import gsap from "gsap";
interface ChatMessage {
id: string;
text: string;
isUser: boolean;
isComplete?: boolean;
}
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"
}
];
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(() => {
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 () => clearTimeout(loopTimeout);
}, [stage, currentIdeaIndex, isAutoPlaying]);
return (
<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>
{/* 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"
}`}
>
<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>
)}
{/* 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>
</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>
{/* 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>
{/* 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>
</div>
);
}