update why nearle page
This commit is contained in:
196
src/components/why-nearle/BeforeAfterFlow.tsx
Normal file
196
src/components/why-nearle/BeforeAfterFlow.tsx
Normal file
@@ -0,0 +1,196 @@
|
||||
"use client";
|
||||
|
||||
import { motion, useReducedMotion } from "framer-motion";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
import { fadeUp, staggerContainer, viewport } from "@/lib/animations";
|
||||
|
||||
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
|
||||
|
||||
const TRADITIONAL = [
|
||||
{ icon: "edit_note", label: "Manual Catalog" },
|
||||
{ icon: "store", label: "Offline Store" },
|
||||
{ icon: "directions_walk", label: "Walk-in Customers" },
|
||||
{ icon: "receipt_long", label: "Manual Billing" },
|
||||
];
|
||||
|
||||
const NEARLE = [
|
||||
{ icon: "auto_awesome", label: "ProductLLM" },
|
||||
{ icon: "storefront", label: "Digital Storefront" },
|
||||
{ icon: "shopping_bag", label: "Omnichannel Ordering" },
|
||||
{ icon: "travel_explore", label: "AI Powered Discovery" },
|
||||
];
|
||||
|
||||
const nodeVariant = {
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.5, ease: EASE } },
|
||||
};
|
||||
|
||||
const connectorVariant = {
|
||||
hidden: { scaleY: 0 },
|
||||
visible: { scaleY: 1, transition: { duration: 0.5, ease: EASE } },
|
||||
};
|
||||
|
||||
function FlowColumn({
|
||||
eyebrow,
|
||||
items,
|
||||
tone,
|
||||
reduce,
|
||||
}: {
|
||||
eyebrow: string;
|
||||
items: { icon: string; label: string }[];
|
||||
tone: "muted" | "brand";
|
||||
reduce: boolean | null;
|
||||
}) {
|
||||
const isBrand = tone === "brand";
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
variants={{ hidden: {}, visible: { transition: { staggerChildren: 0.12 } } }}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true, amount: 0.2 }}
|
||||
className={`relative flex flex-col items-center rounded-[32px] border p-8 md:p-10 ${
|
||||
isBrand
|
||||
? "border-white/10 bg-gradient-to-br from-[#1A0322] via-[#2B0040] to-[#0A000D] shadow-[0_24px_60px_rgba(20,0,30,0.32)]"
|
||||
: "border-[#6330D6]/10 bg-[#FAF7FD] shadow-[0_14px_40px_rgba(22,0,29,0.05)]"
|
||||
}`}
|
||||
>
|
||||
<motion.p
|
||||
variants={nodeVariant}
|
||||
className={`text-xs font-black uppercase tracking-widest ${
|
||||
isBrand ? "text-[#C9A2FF]" : "text-[#5E5866]"
|
||||
}`}
|
||||
>
|
||||
{eyebrow}
|
||||
</motion.p>
|
||||
|
||||
<div className="mt-8 flex w-full max-w-[300px] flex-col items-center">
|
||||
{items.map((item, i) => (
|
||||
<div key={item.label} className="flex w-full flex-col items-center">
|
||||
<motion.div
|
||||
variants={nodeVariant}
|
||||
whileHover={reduce ? undefined : { y: -4, scale: 1.02 }}
|
||||
transition={{ duration: 0.25, ease: EASE }}
|
||||
className={`flex w-full items-center gap-4 rounded-2xl border px-5 py-4 ${
|
||||
isBrand
|
||||
? "border-white/10 bg-white/[0.06] hover:border-[#C9A2FF]/40 hover:bg-white/[0.1]"
|
||||
: "border-[#6330D6]/10 bg-white shadow-[0_8px_22px_rgba(22,0,29,0.04)]"
|
||||
} transition-colors duration-300`}
|
||||
>
|
||||
<div
|
||||
className={`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl ${
|
||||
isBrand ? "bg-white/10 text-[#C9A2FF]" : "bg-[#6330D6]/[0.08] text-[#6330D6]"
|
||||
}`}
|
||||
>
|
||||
<MaterialIcon icon={item.icon} size={22} />
|
||||
</div>
|
||||
<p
|
||||
className={`font-display font-black leading-tight ${
|
||||
isBrand ? "text-white" : "text-[#16001D]"
|
||||
} text-[15px] md:text-base`}
|
||||
>
|
||||
{item.label}
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Animated connector + travelling pulse */}
|
||||
{i < items.length - 1 && (
|
||||
<div className="relative my-1.5 h-8 w-0.5">
|
||||
<motion.span
|
||||
variants={connectorVariant}
|
||||
className={`absolute inset-0 origin-top rounded-full ${
|
||||
isBrand ? "bg-[#C9A2FF]/40" : "bg-[#6330D6]/25"
|
||||
}`}
|
||||
/>
|
||||
{!reduce && (
|
||||
<motion.span
|
||||
aria-hidden="true"
|
||||
className={`absolute left-1/2 top-0 h-2 w-2 -translate-x-1/2 rounded-full ${
|
||||
isBrand
|
||||
? "bg-[#C9A2FF] shadow-[0_0_10px_2px_rgba(201,162,255,0.6)]"
|
||||
: "bg-[#7C3AED] shadow-[0_0_10px_2px_rgba(124,58,237,0.5)]"
|
||||
}`}
|
||||
animate={{ y: [0, 26], opacity: [0, 1, 0] }}
|
||||
transition={{
|
||||
repeat: Infinity,
|
||||
duration: 1.8,
|
||||
ease: "easeInOut",
|
||||
delay: i * 0.3,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
export function BeforeAfterFlow() {
|
||||
const reduce = useReducedMotion();
|
||||
|
||||
return (
|
||||
<section className="section section-soft w-full border-b border-[#6330D6]/10 overflow-hidden">
|
||||
<div className="page-container">
|
||||
<motion.div
|
||||
variants={staggerContainer}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={viewport}
|
||||
className="text-center max-w-[720px] mx-auto"
|
||||
>
|
||||
<motion.span
|
||||
variants={fadeUp}
|
||||
className="inline-flex items-center rounded-full bg-[#6330D6]/[0.08] px-3.5 py-1 text-xs font-black uppercase tracking-widest text-[#6330D6]"
|
||||
>
|
||||
Before vs After
|
||||
</motion.span>
|
||||
<motion.h2
|
||||
variants={fadeUp}
|
||||
className="font-display font-black text-[#16001D] mt-4 tracking-tight"
|
||||
style={{ fontSize: "clamp(30px, 3vw, 48px)", lineHeight: 1.1 }}
|
||||
>
|
||||
The same store, reimagined
|
||||
</motion.h2>
|
||||
</motion.div>
|
||||
|
||||
<div className="relative mt-14 grid gap-6 md:grid-cols-2 md:items-start md:gap-8">
|
||||
<FlowColumn
|
||||
eyebrow="Traditional Commerce"
|
||||
items={TRADITIONAL}
|
||||
tone="muted"
|
||||
reduce={reduce}
|
||||
/>
|
||||
|
||||
{/* Center VS badge (desktop) */}
|
||||
<motion.div
|
||||
aria-hidden="true"
|
||||
initial={{ opacity: 0, scale: 0.6 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
viewport={{ once: true, amount: 0.5 }}
|
||||
transition={{ duration: 0.5, delay: 0.25, ease: EASE }}
|
||||
className="pointer-events-none absolute left-1/2 top-1/2 z-20 hidden h-14 w-14 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border border-[#6330D6]/15 bg-white text-xs font-black uppercase tracking-widest text-[#6330D6] shadow-[0_10px_30px_rgba(99,48,214,0.22)] md:flex"
|
||||
>
|
||||
{!reduce && (
|
||||
<motion.span
|
||||
className="absolute inset-0 rounded-full border-2 border-[#7C3AED]"
|
||||
animate={{ scale: [1, 1.45], opacity: [0.5, 0] }}
|
||||
transition={{ repeat: Infinity, duration: 2.2, ease: "easeOut" }}
|
||||
/>
|
||||
)}
|
||||
VS
|
||||
</motion.div>
|
||||
|
||||
<FlowColumn
|
||||
eyebrow="Nearle AI Commerce"
|
||||
items={NEARLE}
|
||||
tone="brand"
|
||||
reduce={reduce}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user