AppForge: migrate off Supabase to external Postgres + Better Auth + local storage

- New Express + TypeScript backend (server/) with pg, Better Auth, local file storage
- De-Supabased Postgres schema (server/db) and TS reimplementations of DB functions
- Frontend data layer rewired to REST (rest-client + backend-client compat shim)
- Removed all Supabase references (code, config, deps, docs)
- New brand assets: gradient favicon/app icons + dark/white wordmark logos

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Leon Serfaty
2026-06-28 04:50:29 -04:00
co-authored by Claude Opus 4.8
commit 1a8b8ee5a0
271 changed files with 63734 additions and 0 deletions
+250
View File
@@ -0,0 +1,250 @@
import { Button } from "@/components/ui/button";
import { ArrowRight, Play, Sparkles, Globe, Zap } from "lucide-react";
import { Link } from "react-router-dom";
import { motion, useScroll, useTransform, useMotionValue, useSpring } from "framer-motion";
import { useRef, useEffect } from "react";
const HeroSection = () => {
const sectionRef = useRef<HTMLElement>(null);
// Mouse position tracking
const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);
// Smooth spring physics for mouse follow
const springConfig = { damping: 25, stiffness: 150 };
const smoothMouseX = useSpring(mouseX, springConfig);
const smoothMouseY = useSpring(mouseY, springConfig);
// Different movement intensities for each orb (parallax depth)
const orb1X = useTransform(smoothMouseX, [-0.5, 0.5], [-40, 40]);
const orb1Y = useTransform(smoothMouseY, [-0.5, 0.5], [-40, 40]);
const orb2X = useTransform(smoothMouseX, [-0.5, 0.5], [30, -30]);
const orb2Y = useTransform(smoothMouseY, [-0.5, 0.5], [30, -30]);
const orb3X = useTransform(smoothMouseX, [-0.5, 0.5], [-20, 20]);
const orb3Y = useTransform(smoothMouseY, [-0.5, 0.5], [-25, 25]);
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
const { clientX, clientY } = e;
const { innerWidth, innerHeight } = window;
// Normalize to -0.5 to 0.5 range
mouseX.set((clientX / innerWidth) - 0.5);
mouseY.set((clientY / innerHeight) - 0.5);
};
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
}, [mouseX, mouseY]);
const { scrollYProgress } = useScroll({
target: sectionRef,
offset: ["start start", "end start"]
});
const backgroundY = useTransform(scrollYProgress, [0, 1], ["0%", "50%"]);
const gradientScale = useTransform(scrollYProgress, [0, 1], [1, 1.5]);
const contentY = useTransform(scrollYProgress, [0, 1], ["0%", "25%"]);
const floatingY = useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
return (
<section ref={sectionRef} className="relative min-h-screen flex items-center justify-center overflow-hidden pt-20">
{/* Radial Gradient Background with Parallax */}
<motion.div
className="absolute inset-0 pointer-events-none"
style={{ y: backgroundY }}
>
{/* Primary radial gradient with mouse follow */}
<motion.div
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[800px] md:w-[1200px] md:h-[1200px]"
style={{ scale: gradientScale, x: orb1X, y: orb1Y }}
>
<div className="absolute inset-0 bg-[radial-gradient(circle,_hsl(var(--primary)_/_0.15)_0%,_transparent_70%)]" />
</motion.div>
{/* Secondary radial gradient with mouse follow */}
<motion.div
className="absolute top-1/4 right-1/4 w-[600px] h-[600px] md:w-[900px] md:h-[900px]"
style={{ scale: gradientScale, x: orb2X, y: orb2Y }}
>
<div className="absolute inset-0 bg-[radial-gradient(circle,_hsl(var(--primary)_/_0.08)_0%,_transparent_60%)]" />
</motion.div>
{/* Accent gradient glow with mouse follow */}
<motion.div
className="absolute bottom-1/4 left-1/3 w-[400px] h-[400px] md:w-[600px] md:h-[600px]"
style={{ scale: gradientScale, x: orb3X, y: orb3Y }}
>
<div className="absolute inset-0 bg-[radial-gradient(circle,_hsl(var(--muted-foreground)_/_0.05)_0%,_transparent_50%)]" />
</motion.div>
</motion.div>
{/* Background Base */}
<div className="absolute inset-0 bg-muted/20" />
{/* Grid Pattern with Parallax */}
<motion.div
className="absolute inset-0 bg-[linear-gradient(to_right,_hsl(var(--border)_/_0.3)_1px,_transparent_1px),_linear-gradient(to_bottom,_hsl(var(--border)_/_0.3)_1px,_transparent_1px)] bg-[size:60px_60px]"
style={{ y: backgroundY }}
/>
{/* Animated gradient orbs with mouse follow */}
<motion.div
className="absolute top-20 right-1/4 w-32 h-32 rounded-full bg-primary/10 blur-3xl pointer-events-none"
style={{ x: orb1X, y: orb1Y }}
animate={{
scale: [1, 1.2, 1],
opacity: [0.3, 0.5, 0.3]
}}
transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<motion.div
className="absolute bottom-40 left-1/4 w-48 h-48 rounded-full bg-primary/5 blur-3xl pointer-events-none"
style={{ x: orb2X, y: orb2Y }}
animate={{
scale: [1.2, 1, 1.2],
opacity: [0.2, 0.4, 0.2]
}}
transition={{
duration: 5,
repeat: Infinity,
ease: "easeInOut",
delay: 1
}}
/>
<motion.div
className="absolute top-1/2 right-1/3 w-24 h-24 rounded-full bg-primary/8 blur-2xl pointer-events-none"
style={{ x: orb3X, y: orb3Y }}
animate={{
scale: [1, 1.3, 1],
opacity: [0.15, 0.3, 0.15]
}}
transition={{
duration: 6,
repeat: Infinity,
ease: "easeInOut",
delay: 2
}}
/>
<motion.div
className="container mx-auto px-6 relative z-10"
style={{ y: contentY }}
>
<div className="max-w-5xl mx-auto text-center">
{/* Badge */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.1 }}
className="inline-flex items-center gap-2 glass-card px-4 py-2 rounded-full mb-8"
>
<Sparkles className="w-4 h-4 text-accent" />
<span className="text-sm text-muted-foreground">AI-Powered No-Code App Builder</span>
</motion.div>
{/* Heading */}
<motion.h1
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.2 }}
className="font-display text-5xl md:text-7xl lg:text-8xl font-bold mb-6"
>
<span className="text-foreground">Convert Websites to</span>
<br />
<span className="text-primary">Native Mobile Apps</span>
</motion.h1>
{/* Subheading */}
<motion.p
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.3 }}
className="text-xl md:text-2xl text-muted-foreground max-w-3xl mx-auto mb-10"
>
Enter your website URL and create professional native apps in 5 minutes.
No coding needed. AI handles everything automatically.
</motion.p>
{/* CTA Buttons */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.4 }}
className="flex flex-col sm:flex-row items-center justify-center gap-4 mb-16"
>
<Button variant="accent" size="xl" className="group" asChild>
<Link to="/builder">
Start Building Free
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
</Link>
</Button>
<Button variant="glass" size="xl" className="group">
<Play className="w-5 h-5" />
Watch Demo
</Button>
</motion.div>
{/* Stats */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.5 }}
className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-3xl mx-auto"
>
<div className="glass-card rounded-2xl p-6 text-center">
<div className="text-3xl font-display font-bold text-primary mb-1">50K+</div>
<div className="text-muted-foreground text-sm">Apps Created</div>
</div>
<div className="glass-card rounded-2xl p-6 text-center">
<div className="text-3xl font-display font-bold text-primary mb-1">5 Min</div>
<div className="text-muted-foreground text-sm">Average Build Time</div>
</div>
<div className="glass-card rounded-2xl p-6 text-center">
<div className="text-3xl font-display font-bold text-primary mb-1">99.9%</div>
<div className="text-muted-foreground text-sm">Uptime SLA</div>
</div>
</motion.div>
</div>
{/* Floating Elements with Parallax */}
<motion.div
initial={{ opacity: 0, x: -50 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.8, delay: 0.7 }}
style={{ y: floatingY }}
className="absolute top-1/3 left-10 hidden lg:block"
>
<motion.div
className="glass-card p-4 rounded-2xl"
animate={{ y: [0, -10, 0] }}
transition={{ duration: 3, repeat: Infinity, ease: "easeInOut" }}
>
<Globe className="w-8 h-8 text-primary" />
</motion.div>
</motion.div>
<motion.div
initial={{ opacity: 0, x: 50 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.8, delay: 0.9 }}
style={{ y: floatingY }}
className="absolute top-1/2 right-10 hidden lg:block"
>
<motion.div
className="glass-card p-4 rounded-2xl"
animate={{ y: [0, -15, 0] }}
transition={{ duration: 4, repeat: Infinity, ease: "easeInOut", delay: 1 }}
>
<Zap className="w-8 h-8 text-accent" />
</motion.div>
</motion.div>
</motion.div>
</section>
);
};
export default HeroSection;