Initial: landing-page template via tAI

This commit is contained in:
Joe Wee
2026-05-21 12:33:21 +01:00
commit ff8b808fb4
10 changed files with 569 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
export default function Footer() {
return (
<footer className="border-t py-8">
<div className="container text-center text-sm text-muted-foreground">
&copy; 2026 Luminary. All rights reserved.
</div>
</footer>
);
}
+12
View File
@@ -0,0 +1,12 @@
import { Button } from "@/components/ui/button";
export default function Header() {
return (
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container flex h-16 items-center justify-between">
<span className="text-xl font-bold">Luminary</span>
<Button>Get Started</Button>
</div>
</header>
);
}
+3
View File
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
+10
View File
@@ -0,0 +1,10 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
+471
View File
@@ -0,0 +1,471 @@
import { useState, useEffect } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Input } from "@/components/ui/input";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
Menu, ArrowRight, Check, X, Quote, ChevronLeft, ChevronRight,
Github, Twitter, Linkedin, Instagram,
Sparkles, TrendingUp, Users, Award, Clock, Shield, Zap, Heart, Lock
} from "lucide-react";
import { Switch } from "@/components/ui/switch";
import { ThemeToggle } from "@/components/ThemeToggle";
export default function LandingPage() {
const [mobileOpen, setMobileOpen] = useState(false);
const [scrolled, setScrolled] = useState(false);
const [activeTestimonial, setActiveTestimonial] = useState(0);
const [email, setEmail] = useState("");
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 20);
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
const testimonials = [
{ quote: "Luminary replaced four tools for us. Our product team finally has a single source of truth — from customer feedback to shipped features.", name: "Elena Rodriguez", title: "VP Product", company: "Notion" },
{ quote: "The insights engine alone justified the switch. We discovered three critical pain points that our NPS surveys completely missed.", name: "David Chen", title: "CPO", company: "Loom" },
{ quote: "Our roadmap used to live in five different spreadsheets. Now the entire company can see what we are building and why it matters.", name: "Priya Patel", title: "Head of Product", company: "Figma" },
];
const navLinks = [
{ label: "Features", href: "#features" },
{ label: "Results", href: "#stats" },
{ label: "Pricing", href: "#pricing" },
{ label: "Stories", href: "#testimonials" },
];
return (
<div className="min-h-screen bg-background text-foreground antialiased">
{/* ── HEADER ── */}
<header
className={\`fixed top-0 inset-x-0 z-50 transition-all duration-300 \${
scrolled
? "bg-background/95 backdrop-blur-lg border-b shadow-sm"
: "bg-transparent"
}\`}
>
<div className="mx-auto max-w-7xl flex items-center justify-between px-6 py-4">
<a href="/" className="text-xl font-bold tracking-tight">
Luminary
</a>
<nav className="hidden md:flex items-center gap-8">
{navLinks.map((l) => (
<a
key={l.href}
href={l.href}
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
>
{l.label}
</a>
))}
</nav>
<div className="hidden md:flex items-center gap-3">
<ThemeToggle />
<Button size="sm" className="rounded-full px-6">Get Early Access <ArrowRight className="ml-1.5 h-4 w-4" /></Button>
</div>
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
<SheetTrigger asChild className="md:hidden">
<Button variant="ghost" size="icon"><Menu className="h-5 w-5" /></Button>
</SheetTrigger>
<SheetContent side="right" className="w-72">
<nav className="mt-8 flex flex-col gap-4">
{navLinks.map((l) => (
<a key={l.href} href={l.href} className="text-lg font-medium" onClick={() => setMobileOpen(false)}>
{l.label}
</a>
))}
<Button className="mt-4 w-full rounded-full">Get Early Access</Button>
<ThemeToggle />
</nav>
</SheetContent>
</Sheet>
</div>
</header>
{/* ── HERO ── */}
<section className="relative min-h-screen flex items-center justify-center overflow-hidden bg-gradient-to-br from-violet-950 via-purple-900 to-indigo-950">
{/* Grid dots pattern */}
<div
className="absolute inset-0 opacity-[0.15]"
style={{
backgroundImage: "radial-gradient(circle, rgba(255,255,255,0.5) 1px, transparent 1px)",
backgroundSize: "32px 32px",
}}
/>
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-1/3 left-1/4 w-[500px] h-[500px] rounded-full bg-violet-500 opacity-20 blur-[150px]" />
<div className="absolute bottom-1/4 right-1/4 w-[400px] h-[400px] rounded-full bg-indigo-400 opacity-15 blur-[120px]" />
<div className="absolute right-10 top-1/3 w-64 h-64 rounded-full bg-violet-500/10 blur-[80px] animate-pulse" />
</div>
<div className="relative z-10 mx-auto max-w-4xl px-6 text-center">
<Badge variant="secondary" className="mb-6 px-4 py-1.5 text-sm backdrop-blur bg-white/10 text-white border-white/20 hover:bg-white/15">
<Sparkles className="mr-1.5 h-3.5 w-3.5" /> Launching Summer 2026
</Badge>
<h1 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-extrabold tracking-tight text-white leading-[1.1]">
Transform how your team builds products that customers love
</h1>
<p className="mx-auto mt-6 max-w-2xl text-lg sm:text-xl text-violet-200 leading-relaxed">
The all-in-one platform that brings together product strategy, customer insights, and execution — so you can focus on what matters most.
</p>
<div className="mt-10 flex flex-col sm:flex-row items-center justify-center gap-4">
<Button size="lg" className="rounded-full px-8 text-base bg-white text-violet-950 hover:bg-white/90 shadow-lg shadow-white/20">
Start Building Free <ArrowRight className="ml-2 h-4 w-4" />
</Button>
<Button variant="outline" size="lg" className="rounded-full px-8 text-base border-white/30 text-white hover:bg-white/10">
See It in Action
</Button>
</div>
<div className="mt-4 flex items-center justify-center gap-1.5 text-sm text-violet-300">
<Lock className="h-3.5 w-3.5" /> No credit card required
</div>
{/* Social proof row */}
<div className="mt-14 flex items-center justify-center gap-4">
<div className="flex -space-x-3">
{["A", "B", "C", "D"].map((letter, i) => (
<Avatar key={i} className="h-9 w-9 border-2 border-violet-900 ring-2 ring-violet-900">
<AvatarFallback className={\`text-xs font-medium text-white \${
["bg-pink-500", "bg-indigo-500", "bg-emerald-500", "bg-amber-500"][i]
}\`}>{letter}</AvatarFallback>
</Avatar>
))}
</div>
<p className="text-sm text-violet-200">Joined by 2,400+ product teams this month</p>
</div>
</div>
</section>
{/* ── SOCIAL PROOF BAR ── */}
<section className="py-12 border-y bg-muted/30 animate-fade-in">
<div className="mx-auto max-w-5xl px-6">
<div className="flex flex-col sm:flex-row items-center justify-center divide-y sm:divide-y-0 sm:divide-x divide-border">
{[
{ value: "12K+", label: "Active Teams" },
{ value: "4.9/5", label: "Average Rating" },
{ value: "98%", label: "Retention Rate" },
{ value: "150+", label: "Countries" },
].map((s, i) => (
<div key={i} className="flex flex-col items-center py-4 sm:py-0 sm:px-10">
<span className="text-3xl sm:text-4xl font-extrabold tabular-nums">{s.value}</span>
<span className="text-sm text-muted-foreground mt-1">{s.label}</span>
</div>
))}
</div>
</div>
</section>
{/* ── FEATURES ── */}
<section id="features" className="py-24">
<div className="mx-auto max-w-7xl px-6">
<div className="text-center max-w-2xl mx-auto mb-20 animate-fade-up">
<Badge variant="outline" className="mb-4">Why Luminary</Badge>
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight">Built for teams that refuse to settle</h2>
<p className="mt-4 text-lg text-muted-foreground">Three core capabilities that change the way you work, from ideation to impact.</p>
</div>
{[
{
icon: <Zap className="h-5 w-5" />, title: "Instant insights from every customer touchpoint", desc: "Automatically capture, organize, and surface customer feedback from support tickets, interviews, and surveys in real time.",
bullets: ["AI-powered sentiment analysis across all channels", "Automated tagging and theme detection", "Real-time alerting for emerging trends"], gradient: "from-indigo-500 to-violet-600"
},
{
icon: <Shield className="h-5 w-5" />, title: "Roadmaps that align your entire organization", desc: "Create living roadmaps that connect strategy to execution. Keep stakeholders informed and teams focused on the highest-impact work.",
bullets: ["Visual timeline and kanban views", "Automatic dependency mapping", "Stakeholder sharing with custom permissions"], gradient: "from-emerald-500 to-teal-600"
},
{
icon: <TrendingUp className="h-5 w-5" />, title: "Measure impact, not just output", desc: "Track how every feature affects your core metrics. Know exactly which bets paid off and where to double down.",
bullets: ["Built-in OKR and KPI tracking", "Feature-level impact attribution", "Executive dashboards with one-click export"], gradient: "from-amber-500 to-orange-600"
},
].map((feature, i) => (
<div
key={i}
className={\`flex flex-col lg:flex-row gap-12 lg:gap-16 items-center mb-24 last:mb-0 \${
i % 2 === 1 ? "lg:flex-row-reverse" : ""
}\`}
>
{/* Image placeholder */}
<div className="flex-1 w-full animate-scale-in">
<div className={\`aspect-video w-full rounded-2xl bg-gradient-to-br \${feature.gradient} opacity-90 shadow-2xl relative overflow-hidden\`}>
<div className="absolute inset-0" style={{ backgroundImage: "radial-gradient(circle at 25% 25%, rgba(255,255,255,0.15) 1px, transparent 1px)", backgroundSize: "20px 20px" }} />
<div className="absolute inset-0 flex items-center justify-center">
<div className="w-24 h-24 rounded-2xl bg-white/10 backdrop-blur-sm flex items-center justify-center text-white/60 text-4xl font-bold shadow-lg">{i + 1}</div>
</div>
<div className="absolute bottom-4 right-4 bg-white/10 backdrop-blur-md rounded-xl p-3 shadow-lg"><div className="text-white text-sm font-medium">Live demo →</div></div>
<div className="absolute top-4 left-4 w-12 h-12 rounded-full bg-white/5 blur-lg" />
</div>
</div>
{/* Content */}
<div className="flex-1 w-full">
<Badge variant="secondary" className="mb-4">
{feature.icon}
<span className="ml-2">Feature {i + 1}</span>
</Badge>
<h3 className="text-2xl sm:text-3xl font-bold tracking-tight mb-4">{feature.title}</h3>
<p className="text-muted-foreground leading-relaxed mb-6">{feature.desc}</p>
<ul className="space-y-3">
{feature.bullets.map((b, j) => (
<li key={j} className="flex items-start gap-3 text-sm">
<Check className="h-5 w-5 text-emerald-500 shrink-0 mt-0.5" />
<span>{b}</span>
</li>
))}
</ul>
</div>
</div>
))}
</div>
</section>
{/* ── STATS ── */}
<section id="stats" className="py-24 bg-foreground text-background">
<div className="h-px bg-gradient-to-r from-transparent via-background/20 to-transparent" />
<div className="mx-auto max-w-6xl px-6">
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight text-center mb-16 animate-fade-up">The numbers speak for themselves</h2>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-8 stagger">
{[
{ icon: <Users className="h-6 w-6" />, value: "2.4M+", label: "Insights Captured" },
{ icon: <TrendingUp className="h-6 w-6" />, value: "37%", label: "Faster Time-to-Market" },
{ icon: <Award className="h-6 w-6" />, value: "#1", label: "on G2 for Product Mgmt" },
{ icon: <Clock className="h-6 w-6" />, value: "< 2 min", label: "Average Setup Time" },
].map((s, i) => (
<div key={i} className="text-center group animate-fade-up">
<div className="inline-flex items-center justify-center w-12 h-12 rounded-xl bg-background/10 mb-4 group-hover:bg-background/20 group-hover:scale-110 transition-all duration-300">
{s.icon}
</div>
<div className="text-4xl sm:text-5xl font-extrabold tabular-nums mb-2">{s.value}</div>
<div className="text-sm opacity-70">{s.label}</div>
</div>
))}
</div>
</div>
</section>
{/* ── TESTIMONIALS ── */}
<section id="testimonials" className="py-24">
<div className="mx-auto max-w-4xl px-6">
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight text-center mb-16 animate-fade-up">What product leaders are saying</h2>
<div className="relative bg-gradient-to-b from-primary/5 to-transparent rounded-2xl p-8">
<Quote className="absolute -top-4 left-0 h-16 w-16 text-primary/10" />
<div className="text-center px-4 sm:px-12">
<p className="text-xl sm:text-2xl italic leading-relaxed text-foreground/90 mb-8">
"{testimonials[activeTestimonial].quote}"
</p>
<div className="flex items-center justify-center gap-3 mb-8">
<Avatar className="h-12 w-12">
<AvatarFallback className="bg-primary/10 text-primary font-medium">
{testimonials[activeTestimonial].name.split(" ").map((n: string) => n[0]).join("")}
</AvatarFallback>
</Avatar>
<div className="text-left">
<div className="font-semibold">{testimonials[activeTestimonial].name}</div>
<div className="text-sm text-muted-foreground">{testimonials[activeTestimonial].title}</div>
<div className="text-xs text-muted-foreground/70">{testimonials[activeTestimonial].company}</div>
</div>
</div>
{/* Navigation dots */}
<div className="flex items-center justify-center gap-2">
<Button
variant="ghost"
size="icon"
className="h-8 w-8"
onClick={() => setActiveTestimonial((prev) => (prev === 0 ? testimonials.length - 1 : prev - 1))}
>
<ChevronLeft className="h-4 w-4" />
</Button>
{testimonials.map((_, i) => (
<button
key={i}
onClick={() => setActiveTestimonial(i)}
className={\`h-2.5 rounded-full transition-all duration-300 \${
i === activeTestimonial ? "w-8 bg-primary" : "w-2.5 bg-muted-foreground/30 hover:bg-muted-foreground/50"
}\`}
/>
))}
<Button
variant="ghost"
size="icon"
className="h-8 w-8"
onClick={() => setActiveTestimonial((prev) => (prev === testimonials.length - 1 ? 0 : prev + 1))}
>
<ChevronRight className="h-4 w-4" />
</Button>
</div>
</div>
</div>
</div>
</section>
{/* ── PRICING ── */}
<section id="pricing" className="py-24 bg-muted/30">
<div className="mx-auto max-w-6xl px-6">
<div className="text-center max-w-2xl mx-auto mb-16 animate-fade-up">
<Badge variant="outline" className="mb-4">Pricing</Badge>
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight">Simple, transparent pricing</h2>
<p className="mt-4 text-muted-foreground">Start free, scale as you grow. No hidden fees, cancel anytime.</p>
</div>
<div className="flex items-center justify-center gap-3 mb-8">
<span className="text-sm font-medium">Monthly</span>
<Switch />
<span className="text-sm font-medium">Annual</span>
<Badge className="bg-emerald-100 text-emerald-700">Save 20%</Badge>
</div>
<div className="grid md:grid-cols-3 gap-8 items-start stagger">
{[
{
name: "Free", price: "$0", period: "/month", desc: "For individuals and small teams getting started.",
features: ["Up to 10 team members", "1,000 insights/month", "Basic roadmaps", "Community support"],
missing: ["Advanced analytics", "Custom integrations"],
cta: "Get Started Free", popular: false,
},
{
name: "Pro", price: "$29", period: "/user/month", desc: "For growing teams that need advanced features.",
features: ["Unlimited team members", "Unlimited insights", "Advanced roadmaps & OKRs", "Priority support", "All integrations"],
missing: [],
cta: "Start Free Trial", popular: true,
},
{
name: "Enterprise", price: "Custom", period: "", desc: "For organizations with advanced security and compliance needs.",
features: ["Everything in Pro", "SSO & SAML", "Dedicated account manager", "Custom SLA", "Audit logs & compliance", "On-premise deployment"],
missing: [],
cta: "Contact Sales", popular: false,
},
].map((plan, i) => (
<Card key={i} className={\`relative border animate-fade-up hover:scale-[1.02] transition-all duration-300 \${plan.popular ? "border-primary shadow-2xl shadow-primary/20 scale-105" : "border-border hover:border-primary/30 hover:shadow-lg hover:-translate-y-1"}\`}>
{plan.popular && (
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
<Badge className="bg-primary text-primary-foreground shadow-md">Most Popular</Badge>
</div>
)}
<CardHeader className="text-center pb-2">
<CardTitle className="text-lg">{plan.name}</CardTitle>
<div className="mt-4">
<span className="text-4xl font-extrabold">{plan.price}</span>
<span className="text-muted-foreground ml-1">{plan.period}</span>
</div>
<p className="text-sm text-muted-foreground mt-2">{plan.desc}</p>
</CardHeader>
<CardContent className="pt-4">
<ul className="space-y-3 mb-6">
{plan.features.map((f, j) => (
<li key={j} className="flex items-center gap-2.5 text-sm">
<Check className="h-4 w-4 text-emerald-500 shrink-0" /><span>{f}</span>
</li>
))}
{plan.missing.map((m, j) => (
<li key={j} className="flex items-center gap-2.5 text-sm text-muted-foreground">
<X className="h-4 w-4 text-muted-foreground/50 shrink-0" /><span>{m}</span>
</li>
))}
</ul>
<Button className={\`w-full rounded-full \${plan.popular ? "" : "variant-outline"}\`} variant={plan.popular ? "default" : "outline"}>
{plan.cta} <ArrowRight className="ml-2 h-4 w-4" />
</Button>
</CardContent>
</Card>
))}
</div>
</div>
</section>
{/* ── FAQ ── */}
<section className="py-24">
<div className="mx-auto max-w-3xl px-6">
<div className="text-center mb-16 animate-fade-up">
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight">Frequently asked questions</h2>
<p className="mt-4 text-muted-foreground">Everything you need to know about the platform.</p>
</div>
<Card className="bg-card/80 backdrop-blur-sm">
<CardContent className="p-6">
<Accordion type="single" collapsible className="w-full">
{[
{ q: "How does the free plan work?", a: "The free plan includes up to 10 team members and 1,000 insights per month. No credit card required to get started." },
{ q: "Can I change plans later?", a: "Absolutely. You can upgrade, downgrade, or cancel your plan at any time. Changes take effect at the start of your next billing cycle." },
{ q: "What integrations do you support?", a: "We integrate with Slack, Jira, Linear, Notion, Intercom, Zendesk, and 50+ more tools. Custom integrations are available on Enterprise plans." },
{ q: "Is my data secure?", a: "Yes. We are SOC 2 Type II certified, GDPR compliant, and all data is encrypted at rest and in transit. Enterprise plans include additional security features." },
{ q: "Do you offer a trial period?", a: "Yes, all paid plans come with a 14-day free trial. You can explore all features before committing." },
{ q: "How do I get support?", a: "Free plans get community support. Pro plans include priority email support with 4-hour response times. Enterprise gets dedicated account management and phone support." },
].map((faq, i) => (
<AccordionItem key={i} value={\`faq-\${i}\`}>
<AccordionTrigger className="text-left">{faq.q}</AccordionTrigger>
<AccordionContent className="text-muted-foreground">{faq.a}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</CardContent>
</Card>
<div className="text-center mt-8">
<p className="text-muted-foreground mb-4">Still have questions?</p>
<Button variant="outline">Contact Support</Button>
</div>
</div>
</section>
{/* ── CTA ── */}
<section id="contact" className="py-24 bg-gradient-to-r from-primary to-primary/80">
<div className="mx-auto max-w-2xl px-6 text-center">
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight text-primary-foreground">Ready to build products your customers love?</h2>
<p className="mt-4 text-lg text-primary-foreground/80">Join thousands of product teams who ship better, faster, and with more confidence.</p>
<form onSubmit={(e) => { e.preventDefault(); if (email.includes("@")) { toast.success("You're in! Check your inbox."); setEmail(""); } }} className="mt-8 flex flex-col sm:flex-row items-center gap-3 max-w-md mx-auto">
<Input
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your work email"
className="h-12 rounded-full bg-white/95 text-foreground border-0 px-6 flex-1"
/>
<Button type="submit" variant="secondary" size="lg" className="rounded-full px-8 whitespace-nowrap shadow-lg active:scale-[0.97] transition-transform">
Get Started <ArrowRight className="ml-2 h-4 w-4" />
</Button>
</form>
<p className="mt-3 text-sm text-primary-foreground/60">Free for teams up to 10. No credit card required.</p>
</div>
</section>
{/* ── FOOTER ── */}
<footer className="border-t py-12 bg-background">
<div className="mx-auto max-w-7xl px-6">
<div className="grid gap-8 sm:grid-cols-2 lg:grid-cols-4">
<div>
<div className="text-lg font-bold mb-3">Luminary</div>
<p className="text-sm text-muted-foreground leading-relaxed">The product management platform built for modern teams.</p>
<div className="flex gap-3 mt-4">
<a href="#" className="text-muted-foreground hover:text-foreground transition-colors"><Twitter className="h-5 w-5" /></a>
<a href="#" className="text-muted-foreground hover:text-foreground transition-colors"><Github className="h-5 w-5" /></a>
<a href="#" className="text-muted-foreground hover:text-foreground transition-colors"><Linkedin className="h-5 w-5" /></a>
<a href="#" className="text-muted-foreground hover:text-foreground transition-colors"><Instagram className="h-5 w-5" /></a>
</div>
</div>
{[
{ title: "Product", links: ["Features", "Integrations", "Pricing", "Changelog"] },
{ title: "Resources", links: ["Documentation", "Blog", "Community", "Support"] },
{ title: "Company", links: ["About", "Careers", "Privacy"] },
].map((col, i) => (
<div key={i}>
<div className="text-sm font-semibold mb-3">{col.title}</div>
<ul className="space-y-2">
{col.links.map((link, j) => (
<li key={j}>
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">{link}</a>
</li>
))}
</ul>
</div>
))}
</div>
<div className="mt-12 pt-8 border-t flex flex-col sm:flex-row items-center justify-between gap-4">
<p className="text-sm text-muted-foreground">© 2026 Luminary, Inc. All rights reserved.</p>
<div className="flex items-center gap-1 text-sm text-muted-foreground">
Made with <Heart className="h-3.5 w-3.5 text-red-500 mx-1 fill-red-500" /> by the team
</div>
</div>
</div>
</footer>
</div>
);
}