update d2c brands

This commit is contained in:
2026-07-02 18:08:29 +05:30
parent e7e1d1479c
commit 60147da53e
3 changed files with 231 additions and 33 deletions

View File

@@ -0,0 +1,85 @@
"use client";
import { motion, useReducedMotion } from "framer-motion";
const NODES = [
{ cx: 60, cy: 80 }, { cx: 220, cy: 40 }, { cx: 380, cy: 120 },
{ cx: 520, cy: 60 }, { cx: 680, cy: 140 }, { cx: 140, cy: 260 },
{ cx: 320, cy: 300 }, { cx: 480, cy: 260 }, { cx: 620, cy: 320 },
{ cx: 80, cy: 420 }, { cx: 260, cy: 460 }, { cx: 440, cy: 420 },
{ cx: 600, cy: 480 }, { cx: 740, cy: 400 },
];
const LINES: [number, number][] = [
[0, 1], [1, 2], [2, 3], [3, 4], [0, 5], [1, 6], [2, 7], [3, 8], [4, 8],
[5, 6], [6, 7], [7, 8], [5, 9], [6, 10], [7, 11], [8, 12], [9, 10], [10, 11], [11, 12], [12, 13], [8, 13],
];
const PARTICLES = [
{ cx: 100, cy: 500 }, { cx: 260, cy: 80 }, { cx: 420, cy: 520 }, { cx: 580, cy: 100 },
{ cx: 720, cy: 480 }, { cx: 40, cy: 250 }, { cx: 380, cy: 200 }, { cx: 660, cy: 260 },
];
/** Ambient network backdrop for Section 1 — nodes, routes, and drifting particles at very low opacity. Purely decorative. */
export function NetworkBackground() {
const reduce = useReducedMotion();
return (
<div className="pointer-events-none absolute inset-0 overflow-hidden opacity-[0.07]" aria-hidden="true">
<motion.div
className="absolute left-1/2 top-1/2 h-[520px] w-[520px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-[#6330D6] blur-[130px]"
animate={reduce ? undefined : { opacity: [0.45, 0.9, 0.45] }}
transition={{ duration: 8, repeat: Infinity, ease: "easeInOut" }}
/>
<svg
className="absolute inset-0 h-full w-full"
viewBox="0 0 800 600"
fill="none"
preserveAspectRatio="xMidYMid slice"
>
{LINES.map(([a, b], i) => {
const n1 = NODES[a];
const n2 = NODES[b];
return (
<motion.line
key={`l-${a}-${b}`}
x1={n1.cx}
y1={n1.cy}
x2={n2.cx}
y2={n2.cy}
stroke="#6330D6"
strokeWidth={1}
strokeDasharray="4 7"
animate={reduce ? undefined : { strokeDashoffset: [0, -44] }}
transition={{ duration: 6 + (i % 5), repeat: Infinity, ease: "linear" }}
/>
);
})}
{NODES.map((n, i) => (
<motion.circle
key={`n-${i}`}
cx={n.cx}
cy={n.cy}
fill="#6330D6"
animate={reduce ? undefined : { r: [3, 5, 3], opacity: [0.4, 1, 0.4] }}
initial={{ r: 3, opacity: 0.6 }}
transition={{ duration: 3 + (i % 4), repeat: Infinity, ease: "easeInOut", delay: (i % 5) * 0.4 }}
/>
))}
{PARTICLES.map((p, i) => (
<motion.circle
key={`p-${i}`}
cx={p.cx}
r={2}
fill="#6330D6"
initial={{ cy: p.cy, opacity: 0 }}
animate={reduce ? undefined : { cy: [p.cy, p.cy - 46, p.cy], opacity: [0, 0.85, 0] }}
transition={{ duration: 7 + (i % 4), repeat: Infinity, ease: "easeInOut", delay: i * 0.6 }}
/>
))}
</svg>
</div>
);
}

View File

@@ -0,0 +1,55 @@
"use client";
import { motion, useReducedMotion } from "framer-motion";
const EASE = [0.22, 1, 0.36, 1] as [number, number, number, number];
/** One-shot workflow connector for the Partnership Process — draws once on scroll into view, then a glow dot travels Step 1 → Step 4 and stops. No looping. Desktop-only (aligns to the single-row xl:grid-cols-4 layout). */
export function PartnershipConnector({ steps }: { steps: number }) {
const reduce = useReducedMotion();
const positions = Array.from({ length: steps }, (_, i) => ((i + 0.5) / steps) * 100);
const start = positions[0];
const end = positions[positions.length - 1];
const lineDuration = 0.9;
const dotDuration = 1.1;
return (
<div className="relative mb-3 hidden h-6 xl:block" aria-hidden="true">
<motion.div
className="absolute top-1/2 h-0 origin-left -translate-y-1/2 border-t-2 border-dashed border-[#6330D6]/20"
style={{ left: `${start}%`, right: `${100 - end}%` }}
initial={{ scaleX: 0 }}
whileInView={{ scaleX: 1 }}
viewport={{ once: true, amount: 0.4 }}
transition={reduce ? { duration: 0 } : { duration: lineDuration, ease: EASE }}
/>
{positions.map((left, i) => (
<motion.div
key={i}
className="absolute top-1/2 h-2.5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full bg-[#6330D6]/40"
style={{ left: `${left}%` }}
initial={{ opacity: 0, scale: 0.4 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true, amount: 0.4 }}
transition={reduce ? { duration: 0 } : { duration: 0.35, ease: EASE, delay: lineDuration * 0.6 }}
/>
))}
<motion.div
className="absolute top-1/2 h-2.5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full bg-[#6330D6] shadow-[0_0_14px_4px_rgba(99,48,214,0.55)]"
initial={{ left: `${start}%`, opacity: 0 }}
whileInView={{ left: `${end}%`, opacity: 1 }}
viewport={{ once: true, amount: 0.4 }}
transition={
reduce
? { duration: 0 }
: {
left: { duration: dotDuration, ease: EASE, delay: lineDuration },
opacity: { duration: 0.2, delay: lineDuration },
}
}
/>
</div>
);
}