UI performance and Mobile responsiveness
This commit is contained in:
parent
c15b7d8ab7
commit
9d02c62292
26
package-lock.json
generated
26
package-lock.json
generated
@ -24,6 +24,7 @@
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^17.2.4",
|
||||
"framer-motion": "^12.33.0",
|
||||
"lenis": "^1.3.17",
|
||||
"lucide-react": "^0.563.0",
|
||||
"mammoth": "^1.11.0",
|
||||
"next": "16.1.6",
|
||||
@ -7328,6 +7329,31 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/lenis": {
|
||||
"version": "1.3.17",
|
||||
"resolved": "https://registry.npmjs.org/lenis/-/lenis-1.3.17.tgz",
|
||||
"integrity": "sha512-k9T9rgcxne49ggJOvXCraWn5dt7u2mO+BNkhyu6yxuEnm9c092kAW5Bus5SO211zUvx7aCCEtzy9UWr0RB+oJw==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/darkroomengineering"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nuxt/kit": ">=3.0.0",
|
||||
"react": ">=17.0.0",
|
||||
"vue": ">=3.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@nuxt/kit": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"vue": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/levn": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^17.2.4",
|
||||
"framer-motion": "^12.33.0",
|
||||
"lenis": "^1.3.17",
|
||||
"lucide-react": "^0.563.0",
|
||||
"mammoth": "^1.11.0",
|
||||
"next": "16.1.6",
|
||||
|
||||
@ -67,7 +67,7 @@ export default function AboutPage() {
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="max-w-3xl mx-auto text-xl text-slate-400 font-medium leading-relaxed"
|
||||
className="max-w-3xl mx-auto text-xl text-slate-300 font-medium leading-relaxed"
|
||||
>
|
||||
We started JUNOHUB with a simple belief: the global supply chain is broken, and
|
||||
technology is the only way to fix it. We're building the infrastructure for a
|
||||
@ -87,7 +87,7 @@ export default function AboutPage() {
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<h2 className="text-4xl font-black text-white mb-8 tracking-tighter uppercase">Our Vision</h2>
|
||||
<div className="space-y-6 text-slate-400 font-medium text-lg leading-relaxed">
|
||||
<div className="space-y-6 text-slate-300 font-medium text-lg leading-relaxed">
|
||||
<p>
|
||||
Every day, millions of dollars are lost due to inefficient communication,
|
||||
lost inventory data, and slow synchronization.
|
||||
@ -115,7 +115,7 @@ export default function AboutPage() {
|
||||
<div key={item.label} className={`p-8 rounded-3xl bg-white/[0.03] border border-white/10 text-center ${i % 2 !== 0 ? 'mt-8' : ''}`}>
|
||||
<item.icon className="w-8 h-8 text-indigo-400 mx-auto mb-4" />
|
||||
<div className="text-2xl font-black text-white">{item.value}</div>
|
||||
<div className="text-[10px] font-bold text-slate-500 uppercase tracking-widest">{item.label}</div>
|
||||
<div className="text-[10px] font-bold text-slate-400 uppercase tracking-widest">{item.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
@ -141,7 +141,7 @@ export default function AboutPage() {
|
||||
<v.icon className="w-7 h-7 text-white" />
|
||||
</div>
|
||||
<h3 className="text-xl font-black text-white mb-4 uppercase tracking-tight">{v.title}</h3>
|
||||
<p className="text-slate-400 text-sm font-medium leading-relaxed">{v.description}</p>
|
||||
<p className="text-slate-300 text-sm font-medium leading-relaxed">{v.description}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
@ -156,7 +156,7 @@ export default function AboutPage() {
|
||||
viewport={{ once: true }}
|
||||
>
|
||||
<h2 className="text-5xl md:text-7xl font-black text-white mb-8 tracking-tighter uppercase">Join the Movement</h2>
|
||||
<p className="text-slate-400 font-medium mb-12 max-w-2xl mx-auto text-lg leading-relaxed">
|
||||
<p className="text-slate-300 font-medium mb-12 max-w-2xl mx-auto text-lg leading-relaxed">
|
||||
We're always looking for ambitious vendors and suppliers to join our
|
||||
expanding ecosystem. Let's build the future together.
|
||||
</p>
|
||||
|
||||
@ -24,6 +24,7 @@ export const viewport = {
|
||||
|
||||
import { Providers } from "@/components/providers";
|
||||
import { ErrorBoundary } from "@/components/ErrorBoundary";
|
||||
import { SmoothScroll } from "@/components/SmoothScroll";
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
@ -33,10 +34,14 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased selection:bg-indigo-500/30`}
|
||||
>
|
||||
<ErrorBoundary>
|
||||
<Providers>{children}</Providers>
|
||||
<Providers>
|
||||
<SmoothScroll>
|
||||
{children}
|
||||
</SmoothScroll>
|
||||
</Providers>
|
||||
</ErrorBoundary>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,21 +1,34 @@
|
||||
import { auth } from "@/auth"
|
||||
"use client"
|
||||
|
||||
import { useMediaQuery } from "@/hooks/useMediaQuery"
|
||||
import { LandingNavbar } from "@/components/landing/LandingNavbar"
|
||||
import { LandingHero } from "@/components/landing/LandingHero"
|
||||
import { LandingFeatures } from "@/components/landing/LandingFeatures"
|
||||
import { LandingSolutions } from "@/components/landing/LandingSolutions"
|
||||
import { LandingFooter } from "@/components/landing/LandingFooter"
|
||||
import { MobileHero } from "@/components/landing/mobile/MobileHero"
|
||||
import { MobileFeatures } from "@/components/landing/mobile/MobileFeatures"
|
||||
|
||||
export default async function HomePage() {
|
||||
const session = await auth()
|
||||
const isLoggedIn = !!session
|
||||
export default function HomePage() {
|
||||
const isMobile = useMediaQuery("(max-width: 768px)")
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#0a0e1a] selection:bg-indigo-500/30">
|
||||
<LandingNavbar isLoggedIn={isLoggedIn} />
|
||||
<LandingNavbar isLoggedIn={false} />
|
||||
<main>
|
||||
<LandingHero />
|
||||
<LandingFeatures />
|
||||
<LandingSolutions />
|
||||
{isMobile ? (
|
||||
<>
|
||||
<MobileHero />
|
||||
<MobileFeatures />
|
||||
<LandingSolutions />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<LandingHero />
|
||||
<LandingFeatures />
|
||||
<LandingSolutions />
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
<LandingFooter />
|
||||
</div>
|
||||
|
||||
32
src/components/SmoothScroll.tsx
Normal file
32
src/components/SmoothScroll.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import Lenis from 'lenis'
|
||||
|
||||
export function SmoothScroll({ children }: { children: React.ReactNode }) {
|
||||
useEffect(() => {
|
||||
const lenis = new Lenis({
|
||||
duration: 1.2,
|
||||
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
|
||||
orientation: 'vertical',
|
||||
gestureOrientation: 'vertical',
|
||||
smoothWheel: true,
|
||||
wheelMultiplier: 1,
|
||||
touchMultiplier: 2,
|
||||
infinite: false,
|
||||
})
|
||||
|
||||
function raf(time: number) {
|
||||
lenis.raf(time)
|
||||
requestAnimationFrame(raf)
|
||||
}
|
||||
|
||||
requestAnimationFrame(raf)
|
||||
|
||||
return () => {
|
||||
lenis.destroy()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return <>{children}</>
|
||||
}
|
||||
@ -8,7 +8,7 @@ export function LandingFooter() {
|
||||
return (
|
||||
<footer className="py-20 border-t border-white/5 relative overflow-hidden">
|
||||
{/* Background Glow */}
|
||||
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-[800px] h-[300px] bg-indigo-600/10 blur-[120px] rounded-full -z-10" />
|
||||
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-[800px] h-[300px] bg-indigo-600/10 blur-[120px] rounded-full -z-10 will-change-transform" />
|
||||
|
||||
<div className="container mx-auto px-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-12 mb-16">
|
||||
@ -19,17 +19,17 @@ export function LandingFooter() {
|
||||
</div>
|
||||
<span className="text-xl font-black tracking-tighter text-white">JUNOHUB</span>
|
||||
</Link>
|
||||
<p className="text-slate-500 font-medium mb-8">
|
||||
<p className="text-slate-300 font-medium mb-8">
|
||||
The next generation of supply chain connectivity. Secure, encrypted, and real-time.
|
||||
</p>
|
||||
<div className="flex items-center gap-4">
|
||||
<a href="#" className="p-2 rounded-lg bg-white/5 border border-white/10 text-slate-400 hover:text-white hover:bg-white/10 transition-all">
|
||||
<a href="#" aria-label="Follow us on Twitter" className="p-2 rounded-lg bg-white/5 border border-white/10 text-slate-300 hover:text-white hover:bg-white/10 transition-all">
|
||||
<Twitter className="w-5 h-5" />
|
||||
</a>
|
||||
<a href="#" className="p-2 rounded-lg bg-white/5 border border-white/10 text-slate-400 hover:text-white hover:bg-white/10 transition-all">
|
||||
<a href="#" aria-label="Connect on LinkedIn" className="p-2 rounded-lg bg-white/5 border border-white/10 text-slate-300 hover:text-white hover:bg-white/10 transition-all">
|
||||
<Linkedin className="w-5 h-5" />
|
||||
</a>
|
||||
<a href="#" className="p-2 rounded-lg bg-white/5 border border-white/10 text-slate-400 hover:text-white hover:bg-white/10 transition-all">
|
||||
<a href="#" aria-label="View our GitHub" className="p-2 rounded-lg bg-white/5 border border-white/10 text-slate-300 hover:text-white hover:bg-white/10 transition-all">
|
||||
<Github className="w-5 h-5" />
|
||||
</a>
|
||||
</div>
|
||||
@ -38,25 +38,25 @@ export function LandingFooter() {
|
||||
<div>
|
||||
<h4 className="text-white font-black uppercase tracking-widest text-sm mb-6">Platform</h4>
|
||||
<ul className="space-y-4">
|
||||
<li><Link href="/platform" className="text-slate-500 hover:text-indigo-400 transition-colors font-medium">Features</Link></li>
|
||||
<li><Link href="/platform" className="text-slate-500 hover:text-indigo-400 transition-colors font-medium">Shopify Sync</Link></li>
|
||||
<li><Link href="/platform" className="text-slate-500 hover:text-indigo-400 transition-colors font-medium">Security</Link></li>
|
||||
<li><Link href="/platform" className="text-slate-500 hover:text-indigo-400 transition-colors font-medium">API</Link></li>
|
||||
<li><Link href="/platform" className="text-slate-300 hover:text-indigo-400 transition-colors font-medium">Features</Link></li>
|
||||
<li><Link href="/platform" className="text-slate-300 hover:text-indigo-400 transition-colors font-medium">Shopify Sync</Link></li>
|
||||
<li><Link href="/platform" className="text-slate-300 hover:text-indigo-400 transition-colors font-medium">Security</Link></li>
|
||||
<li><Link href="/platform" className="text-slate-300 hover:text-indigo-400 transition-colors font-medium">API</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="text-white font-black uppercase tracking-widest text-sm mb-6">Company</h4>
|
||||
<ul className="space-y-4">
|
||||
<li><Link href="/about" className="text-slate-500 hover:text-indigo-400 transition-colors font-medium">About Us</Link></li>
|
||||
<li><Link href="/privacy-policy" className="text-slate-500 hover:text-indigo-400 transition-colors font-medium">Privacy Policy</Link></li>
|
||||
<li><Link href="/terms-of-service" className="text-slate-500 hover:text-indigo-400 transition-colors font-medium">Terms of Service</Link></li>
|
||||
<li><Link href="/about" className="text-slate-300 hover:text-indigo-400 transition-colors font-medium">About Us</Link></li>
|
||||
<li><Link href="/privacy-policy" className="text-slate-300 hover:text-indigo-400 transition-colors font-medium">Privacy Policy</Link></li>
|
||||
<li><Link href="/terms-of-service" className="text-slate-300 hover:text-indigo-400 transition-colors font-medium">Terms of Service</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="text-white font-black uppercase tracking-widest text-sm mb-6">Newsletter</h4>
|
||||
<p className="text-slate-500 font-medium mb-6">Stay updated with the latest in supply chain tech.</p>
|
||||
<p className="text-slate-300 font-medium mb-6">Stay updated with the latest in supply chain tech.</p>
|
||||
|
||||
{/* Status Message */}
|
||||
<form
|
||||
@ -113,6 +113,7 @@ export function LandingFooter() {
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
aria-label="Subscribe to newsletter"
|
||||
className="bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white p-3 rounded-xl transition-all active:scale-95 shadow-lg shadow-indigo-600/20"
|
||||
>
|
||||
<Mail className="w-5 h-5" />
|
||||
@ -124,13 +125,13 @@ export function LandingFooter() {
|
||||
</div>
|
||||
|
||||
<div className="pt-8 border-t border-white/5 flex flex-col md:flex-row items-center justify-between gap-4">
|
||||
<p className="text-sm text-slate-600 font-medium">
|
||||
<p className="text-sm text-slate-400 font-medium">
|
||||
© 2026 JUNOHUB. All rights reserved.
|
||||
</p>
|
||||
<div className="flex items-center gap-6">
|
||||
<Link href="/terms-of-service" className="text-xs text-slate-600 hover:text-slate-400 font-bold uppercase tracking-widest">Terms</Link>
|
||||
<Link href="/privacy-policy" className="text-xs text-slate-600 hover:text-slate-400 font-bold uppercase tracking-widest">Privacy</Link>
|
||||
<Link href="/cookies" className="text-xs text-slate-600 hover:text-slate-400 font-bold uppercase tracking-widest">Cookies</Link>
|
||||
<Link href="/terms-of-service" className="text-xs text-slate-400 hover:text-indigo-300 font-bold uppercase tracking-widest">Terms</Link>
|
||||
<Link href="/privacy-policy" className="text-xs text-slate-400 hover:text-indigo-300 font-bold uppercase tracking-widest">Privacy</Link>
|
||||
<Link href="/cookies" className="text-xs text-slate-400 hover:text-indigo-300 font-bold uppercase tracking-widest">Cookies</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -22,9 +22,9 @@ export function LandingHero() {
|
||||
className="relative min-h-screen flex items-center justify-center pt-20 overflow-hidden"
|
||||
>
|
||||
{/* Background Decorative Elements */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-indigo-600/20 blur-[120px] rounded-full animate-pulse" />
|
||||
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-purple-600/20 blur-[120px] rounded-full animate-pulse delay-700" />
|
||||
<div className="absolute inset-0 z-0 pointer-events-none">
|
||||
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-indigo-600/20 blur-[120px] rounded-full animate-pulse will-change-[transform,opacity]" />
|
||||
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-purple-600/20 blur-[120px] rounded-full animate-pulse delay-700 will-change-[transform,opacity]" />
|
||||
</div>
|
||||
|
||||
{/* Grid Pattern */}
|
||||
@ -54,9 +54,9 @@ export function LandingHero() {
|
||||
|
||||
{/* Main Heading */}
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
initial={{ opacity: 1, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="text-5xl md:text-8xl font-black tracking-tighter text-white mb-8 leading-[0.9]"
|
||||
>
|
||||
THE PULSE OF <br />
|
||||
@ -67,8 +67,8 @@ export function LandingHero() {
|
||||
<motion.p
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 1, delay: 0.4 }}
|
||||
className="max-w-2xl mx-auto text-lg md:text-xl text-slate-400 font-medium mb-12 leading-relaxed"
|
||||
transition={{ duration: 1, delay: 0.2 }}
|
||||
className="max-w-2xl mx-auto text-lg md:text-xl text-slate-300 font-medium mb-12 leading-relaxed"
|
||||
>
|
||||
Bridge the gap between vendors and suppliers with the world's most advanced
|
||||
encrypted ecosystem. Sync Shopify, chat securely, and scale effortlessly.
|
||||
@ -135,7 +135,7 @@ export function LandingHero() {
|
||||
className="absolute top-0 left-0 w-full h-1/3 bg-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<span className="text-[10px] font-black uppercase tracking-[0.3em] text-slate-500">Scroll</span>
|
||||
<span className="text-[10px] font-black uppercase tracking-[0.3em] text-slate-400">Scroll</span>
|
||||
</motion.div>
|
||||
</section>
|
||||
)
|
||||
|
||||
@ -57,7 +57,7 @@ export function LandingNavbar({ isLoggedIn }: LandingNavbarProps) {
|
||||
<Link
|
||||
key={link.name}
|
||||
href={link.href}
|
||||
className="text-sm font-bold text-slate-400 hover:text-white transition-colors"
|
||||
className="text-sm font-bold text-slate-300 hover:text-indigo-400 transition-colors"
|
||||
>
|
||||
{link.name}
|
||||
</Link>
|
||||
@ -84,6 +84,8 @@ export function LandingNavbar({ isLoggedIn }: LandingNavbarProps) {
|
||||
<button
|
||||
className="md:hidden text-white p-1"
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
aria-label={mobileMenuOpen ? "Close menu" : "Open menu"}
|
||||
aria-expanded={mobileMenuOpen}
|
||||
>
|
||||
{mobileMenuOpen ? <X /> : <Menu />}
|
||||
</button>
|
||||
|
||||
@ -57,7 +57,7 @@ export function LandingSolutions() {
|
||||
{sol.title}
|
||||
</h3>
|
||||
|
||||
<p className="text-slate-400 font-medium mb-8 text-lg">
|
||||
<p className="text-slate-300 font-medium mb-8 text-lg">
|
||||
{sol.description}
|
||||
</p>
|
||||
|
||||
|
||||
109
src/components/landing/mobile/MobileFeatures.tsx
Normal file
109
src/components/landing/mobile/MobileFeatures.tsx
Normal file
@ -0,0 +1,109 @@
|
||||
"use client"
|
||||
|
||||
import { motion } from "framer-motion"
|
||||
import {
|
||||
Zap,
|
||||
MessageSquare,
|
||||
BarChart3,
|
||||
ShieldCheck,
|
||||
LayoutDashboard,
|
||||
RefreshCcw,
|
||||
ArrowRight
|
||||
} from "lucide-react"
|
||||
import Link from "next/link"
|
||||
|
||||
const features = [
|
||||
{
|
||||
title: "Shopify Sync",
|
||||
icon: RefreshCcw,
|
||||
color: "text-emerald-400",
|
||||
bg: "bg-emerald-500/10",
|
||||
size: "col-span-1"
|
||||
},
|
||||
{
|
||||
title: "E2E Chat",
|
||||
icon: MessageSquare,
|
||||
color: "text-blue-400",
|
||||
bg: "bg-blue-500/10",
|
||||
size: "col-span-1"
|
||||
},
|
||||
{
|
||||
title: "High Octane Analytics",
|
||||
icon: BarChart3,
|
||||
color: "text-purple-400",
|
||||
bg: "bg-purple-500/10",
|
||||
size: "col-span-2"
|
||||
},
|
||||
{
|
||||
title: "Dashboard",
|
||||
icon: LayoutDashboard,
|
||||
color: "text-orange-400",
|
||||
bg: "bg-orange-500/10",
|
||||
size: "col-span-1"
|
||||
},
|
||||
{
|
||||
title: "Security",
|
||||
icon: ShieldCheck,
|
||||
color: "text-red-400",
|
||||
bg: "bg-red-500/10",
|
||||
size: "col-span-1"
|
||||
},
|
||||
{
|
||||
title: "Global Scalability",
|
||||
icon: Zap,
|
||||
color: "text-yellow-400",
|
||||
bg: "bg-yellow-500/10",
|
||||
size: "col-span-2"
|
||||
}
|
||||
]
|
||||
|
||||
export function MobileFeatures() {
|
||||
return (
|
||||
<section className="py-24 px-6 bg-[#0a0e1a] relative overflow-hidden">
|
||||
{/* Decorative lines */}
|
||||
<div className="absolute top-0 left-0 w-full h-[1px] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
|
||||
|
||||
<div className="mb-16 text-center">
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
whileInView={{ opacity: 1 }}
|
||||
className="text-[10px] font-black text-indigo-400 uppercase tracking-[0.4em] mb-4"
|
||||
>
|
||||
Infrastructure
|
||||
</motion.div>
|
||||
<h2 className="text-4xl font-black text-white mb-6 tracking-tighter uppercase italic">Dominance.</h2>
|
||||
<div className="w-12 h-1 bg-indigo-600 mx-auto rounded-full" />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{features.map((f, i) => (
|
||||
<motion.div
|
||||
key={f.title}
|
||||
initial={{ opacity: 1, scale: 0.95 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: i * 0.05 }}
|
||||
className={`${f.size} p-8 rounded-[2rem] border border-white/5 bg-white/[0.02] flex flex-col items-center justify-center text-center relative overflow-hidden group active:bg-white/5 transition-colors`}
|
||||
>
|
||||
{/* Glow */}
|
||||
<div className={`absolute -top-4 -right-4 w-16 h-16 ${f.bg} blur-[30px] opacity-20`} />
|
||||
|
||||
<div className={`w-14 h-14 rounded-[1.25rem] ${f.bg} flex items-center justify-center mb-4 border border-white/5 shadow-inner`}>
|
||||
<f.icon className={`w-7 h-7 ${f.color}`} />
|
||||
</div>
|
||||
<h3 className="text-xs font-black text-white uppercase tracking-widest">{f.title}</h3>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-20 p-8 rounded-[2.5rem] bg-gradient-to-br from-indigo-600 to-purple-600 text-center relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-white/10 blur-[40px] rounded-full" />
|
||||
<h3 className="text-2xl font-black text-white mb-4 uppercase italic">Ready to sync?</h3>
|
||||
<p className="text-indigo-100 text-sm font-medium mb-8 opacity-90">Join the thousands of vendors scaling with JUNOHUB.</p>
|
||||
<Link href="/signup" className="inline-flex items-center gap-2 px-8 py-4 bg-white text-indigo-600 rounded-2xl font-black text-sm uppercase tracking-wider shadow-lg">
|
||||
Get Started <ArrowRight className="w-4 h-4" />
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
91
src/components/landing/mobile/MobileHero.tsx
Normal file
91
src/components/landing/mobile/MobileHero.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
"use client"
|
||||
|
||||
import { motion } from "framer-motion"
|
||||
import { ArrowRight, Play, ShieldCheck, Zap, Globe, MessageSquare } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
|
||||
const stats = [
|
||||
{ label: "AES-250 READY", icon: ShieldCheck },
|
||||
{ label: "SHOPIFY SYNC", icon: Zap },
|
||||
{ label: "120+ COUNTRIES", icon: Globe },
|
||||
{ label: "E2E CHAT", icon: MessageSquare },
|
||||
]
|
||||
|
||||
export function MobileHero() {
|
||||
return (
|
||||
<section className="relative min-h-[95vh] flex flex-col items-center justify-between px-6 pb-12 pt-16 overflow-hidden bg-[#0a0e1a]">
|
||||
{/* The Pulse Core - Central Visual */}
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full h-full z-0 pointer-events-none flex items-center justify-center">
|
||||
<div className="w-64 h-64 bg-indigo-600/30 blur-[80px] rounded-full animate-pulse will-change-[transform,opacity]" />
|
||||
<div className="absolute w-40 h-40 bg-purple-600/20 blur-[60px] rounded-full animate-pulse delay-700" />
|
||||
<div className="absolute w-[300px] h-[1px] bg-gradient-to-r from-transparent via-indigo-500/20 to-transparent rotate-45" />
|
||||
<div className="absolute w-[300px] h-[1px] bg-gradient-to-r from-transparent via-purple-500/20 to-transparent -rotate-45" />
|
||||
</div>
|
||||
|
||||
<div className="relative z-10 text-center flex flex-col items-center w-full mt-12">
|
||||
{/* Mobile-First Badge */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-white/5 border border-white/10 backdrop-blur-md mb-8"
|
||||
>
|
||||
<span className="flex h-1.5 w-1.5 rounded-full bg-indigo-500 animate-ping" />
|
||||
<span className="text-[10px] font-black uppercase tracking-[0.2em] text-indigo-400">Next-Gen Engine</span>
|
||||
</motion.div>
|
||||
|
||||
{/* Big, Punchy Mobile Header */}
|
||||
<motion.h1
|
||||
initial={{ opacity: 1, y: 0 }}
|
||||
className="text-6xl font-black tracking-tighter text-white mb-6 leading-[0.85] uppercase italic"
|
||||
>
|
||||
THE <br />
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-br from-indigo-400 via-white to-purple-400">PULSE.</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
initial={{ opacity: 1 }}
|
||||
className="text-slate-300 text-sm font-medium mb-12 max-w-[260px] leading-relaxed mx-auto"
|
||||
>
|
||||
Bridge the gap between vendors and suppliers with the world's most advanced
|
||||
encrypted ecosystem.
|
||||
</motion.p>
|
||||
|
||||
{/* Thumb-Zone CTAs */}
|
||||
<div className="flex flex-col w-full gap-4 max-w-[300px]">
|
||||
<Link
|
||||
href="/signup"
|
||||
className="w-full py-5 bg-indigo-600 rounded-2xl font-black text-white shadow-xl shadow-indigo-600/20 flex items-center justify-center gap-2 active:scale-95 transition-all text-sm uppercase tracking-wider"
|
||||
>
|
||||
GET STARTED NOW <ArrowRight className="w-4 h-4" />
|
||||
</Link>
|
||||
|
||||
<button className="w-full py-5 rounded-2xl font-black text-white bg-white/5 border border-white/10 flex items-center justify-center gap-3 active:scale-95 transition-all text-sm uppercase tracking-wider backdrop-blur-sm">
|
||||
<div className="w-8 h-8 rounded-full bg-white/10 flex items-center justify-center">
|
||||
<Play className="w-3 h-3 fill-white ml-0.5" />
|
||||
</div>
|
||||
WATCH DEMO
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Infinite Marquee for Stats - Prevents Overlap */}
|
||||
<div className="relative w-full z-10 mt-auto pt-12 overflow-hidden mb-4">
|
||||
<div className="absolute inset-y-0 left-0 w-12 bg-gradient-to-r from-[#0a0e1a] to-transparent z-20" />
|
||||
<div className="absolute inset-y-0 right-0 w-12 bg-gradient-to-l from-[#0a0e1a] to-transparent z-20" />
|
||||
|
||||
<motion.div
|
||||
animate={{ x: [0, -1000] }}
|
||||
transition={{ duration: 30, repeat: Infinity, ease: "linear" }}
|
||||
className="flex whitespace-nowrap gap-8"
|
||||
>
|
||||
{[...stats, ...stats, ...stats, ...stats].map((s, i) => (
|
||||
<div key={i} className="flex items-center gap-2 px-4 py-2 bg-white/5 rounded-full border border-white/10">
|
||||
<s.icon className="w-3 h-3 text-indigo-400" />
|
||||
<span className="text-[10px] font-black tracking-[0.1em] text-white uppercase whitespace-nowrap">{s.label}</span>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
19
src/hooks/useMediaQuery.ts
Normal file
19
src/hooks/useMediaQuery.ts
Normal file
@ -0,0 +1,19 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
|
||||
export function useMediaQuery(query: string) {
|
||||
const [matches, setMatches] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const media = window.matchMedia(query)
|
||||
if (media.matches !== matches) {
|
||||
setMatches(media.matches)
|
||||
}
|
||||
const listener = () => setMatches(media.matches)
|
||||
window.addEventListener("resize", listener)
|
||||
return () => window.removeEventListener("resize", listener)
|
||||
}, [matches, query])
|
||||
|
||||
return matches
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user