feat: add app download section to landing page and improve hero 3D background responsiveness
This commit is contained in:
@@ -325,6 +325,91 @@ export default function LandingPage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Download App Section */}
|
||||
<section className="py-20 bg-accent relative overflow-hidden">
|
||||
<div className="absolute inset-0 bg-[url('/noise.png')] opacity-10 mix-blend-overlay"></div>
|
||||
|
||||
{/* Background decorative circles */}
|
||||
<div className="absolute top-0 right-0 w-96 h-96 bg-white/10 rounded-full blur-3xl -mr-20 -mt-20"></div>
|
||||
<div className="absolute bottom-0 left-0 w-64 h-64 bg-emerald-900/30 rounded-full blur-3xl -ml-20 -mb-20"></div>
|
||||
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10 flex flex-col md:flex-row items-center justify-between gap-12">
|
||||
<div className="w-full md:w-1/2 text-center md:text-left text-white">
|
||||
<h2 className="text-3xl md:text-5xl font-extrabold mb-6 leading-tight drop-shadow-sm">Ready to ride? <br/>Download the JAIBEN App</h2>
|
||||
<p className="text-white/90 text-lg mb-8 max-w-lg mx-auto md:mx-0 drop-shadow-sm">Get full access to biker rentals, swap station locations, and real-time earnings directly from your smartphone.</p>
|
||||
<div className="flex flex-col sm:flex-row items-center justify-center md:justify-start gap-4">
|
||||
<button
|
||||
onClick={() => router.push('/coming-soon')}
|
||||
className="flex items-center gap-3 bg-black text-white px-6 py-3 rounded-xl hover:bg-slate-900 hover:scale-105 transition-all shadow-xl shadow-black/20 w-full sm:w-auto justify-center"
|
||||
>
|
||||
<svg viewBox="0 0 512 512" className="w-6 h-6 fill-current"><path d="M325.3 234.3L104.6 13l280.8 161.2-60.1 60.1zM47 0C34 6.8 25.3 19.2 25.3 35.3v441.3c0 16.1 8.7 28.5 21.7 35.3l256.6-256L47 0zm425.2 225.6l-58.9-34.1-65.7 64.5 65.7 64.5 60.1-34.1c18-14.3 18-46.5-1.2-60.8zM104.6 499l280.8-161.2-60.1-60.1L104.6 499z"/></svg>
|
||||
<div className="flex flex-col text-left">
|
||||
<span className="text-[10px] leading-none text-slate-300 font-semibold">GET IT ON</span>
|
||||
<span className="text-lg font-bold leading-none mt-1">Google Play</span>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push('/coming-soon')}
|
||||
className="flex items-center gap-3 bg-black text-white px-6 py-3 rounded-xl hover:bg-slate-900 hover:scale-105 transition-all shadow-xl shadow-black/20 w-full sm:w-auto justify-center"
|
||||
>
|
||||
<svg viewBox="0 0 384 512" className="w-6 h-6 fill-current"><path d="M318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7C63.3 141.2 4 184.8 4 273.5q0 39.3 14.4 81.2c12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"/></svg>
|
||||
<div className="flex flex-col text-left">
|
||||
<span className="text-[10px] leading-none text-slate-300 font-semibold">Download on the</span>
|
||||
<span className="text-lg font-bold leading-none mt-1">App Store</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full md:w-1/2 flex justify-center">
|
||||
{/* Abstract Phone Mockup */}
|
||||
<div className="w-64 h-[450px] bg-slate-900 rounded-[3rem] border-[8px] border-slate-800 shadow-[0_30px_60px_rgba(0,0,0,0.4)] relative overflow-hidden flex flex-col -mb-32 md:-mb-40 transform rotate-12 hover:rotate-6 transition-transform duration-500">
|
||||
<div className="h-6 w-1/2 bg-slate-800 absolute top-0 left-1/2 -translate-x-1/2 rounded-b-xl z-20"></div>
|
||||
<div className="flex-1 bg-slate-50 p-4 pt-12 relative flex flex-col gap-4">
|
||||
{/* Mock App Header */}
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="w-10 h-10 bg-accent rounded-full flex items-center justify-center">
|
||||
<Image src="/jaiben.png" alt="Logo" width={24} height={24} className="brightness-0 invert" />
|
||||
</div>
|
||||
<div className="w-8 h-8 bg-slate-200 rounded-full"></div>
|
||||
</div>
|
||||
|
||||
{/* Mock App Banner */}
|
||||
<div className="w-full h-32 bg-gradient-to-br from-accent to-emerald-700 rounded-2xl p-4 shadow-sm relative overflow-hidden">
|
||||
<div className="w-32 h-32 bg-white/10 rounded-full absolute -right-10 -bottom-10 blur-xl"></div>
|
||||
<div className="w-1/2 h-3 bg-white/40 rounded-full mb-2 relative z-10"></div>
|
||||
<div className="w-1/3 h-3 bg-white/20 rounded-full relative z-10"></div>
|
||||
</div>
|
||||
|
||||
{/* Mock App Grid */}
|
||||
<div className="grid grid-cols-2 gap-3 flex-grow">
|
||||
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-3 flex flex-col gap-2">
|
||||
<div className="w-8 h-8 bg-orange-100 rounded-lg"></div>
|
||||
<div className="w-full h-2 bg-slate-200 rounded-full"></div>
|
||||
<div className="w-1/2 h-2 bg-slate-100 rounded-full"></div>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-3 flex flex-col gap-2">
|
||||
<div className="w-8 h-8 bg-purple-100 rounded-lg"></div>
|
||||
<div className="w-full h-2 bg-slate-200 rounded-full"></div>
|
||||
<div className="w-1/2 h-2 bg-slate-100 rounded-full"></div>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-3 flex flex-col gap-2">
|
||||
<div className="w-8 h-8 bg-blue-100 rounded-lg"></div>
|
||||
<div className="w-full h-2 bg-slate-200 rounded-full"></div>
|
||||
<div className="w-1/2 h-2 bg-slate-100 rounded-full"></div>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-3 flex flex-col gap-2">
|
||||
<div className="w-8 h-8 bg-emerald-100 rounded-lg"></div>
|
||||
<div className="w-full h-2 bg-slate-200 rounded-full"></div>
|
||||
<div className="w-1/2 h-2 bg-slate-100 rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="bg-slate-950 pt-20 pb-10 border-t border-slate-800">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Suspense, useMemo, useRef } from 'react';
|
||||
import { Canvas, useFrame, useLoader } from '@react-three/fiber';
|
||||
import { Canvas, useFrame, useLoader, useThree } from '@react-three/fiber';
|
||||
import {
|
||||
Float,
|
||||
ContactShadows,
|
||||
@@ -85,17 +85,24 @@ function AeroxModel() {
|
||||
return clone;
|
||||
}, [obj]);
|
||||
|
||||
const { size } = useThree();
|
||||
const isMobile = size.width < 1024;
|
||||
const targetX = isMobile ? 0 : 2.5;
|
||||
|
||||
useFrame((state) => {
|
||||
if (!group.current) return;
|
||||
const t = state.clock.elapsedTime;
|
||||
// Continuous turntable so all sides are appreciated.
|
||||
group.current.rotation.y = t * 0.4;
|
||||
group.current.position.y = Math.sin(t * 1.5) * 0.08;
|
||||
|
||||
// Smoothly animate position X to be responsive
|
||||
group.current.position.x += (targetX - group.current.position.x) * 0.1;
|
||||
});
|
||||
|
||||
return (
|
||||
<Float speed={1.2} rotationIntensity={0.1} floatIntensity={0.3}>
|
||||
<group ref={group} rotation={[0, -0.5, 0]} position={[2.5, -0.1, -1]}>
|
||||
<group ref={group} rotation={[0, -0.5, 0]} position={[isMobile ? 0 : 2.5, -0.1, -1]}>
|
||||
<primitive object={model} />
|
||||
</group>
|
||||
</Float>
|
||||
|
||||
Reference in New Issue
Block a user