fix the mobile responsive

This commit is contained in:
2026-06-04 20:06:39 +05:30
parent d5987b5dd1
commit 3a16bf9267
6 changed files with 192 additions and 52 deletions

View File

@@ -24,23 +24,7 @@ function Counter({ mv }: { mv: MotionValue<number> }) {
return <span ref={ref}>{Math.round(mv.get())}</span>;
}
/** True only while a card's own opacity window is open (with a tiny buffer).
* Lets us keep future/past story cards out of the DOM — and off the compositor
* (each has `will-change`) — until their beat is actually on screen, so no
* workflow state is rendered before activation. Visually identical, since a
* card outside its window is opacity:0 anyway. */
function useInWindow(mv: MotionValue<number>, threshold = 0.01): boolean {
// `mv` is an external mutable store (a MotionValue). useTransform `.set()`s its
// output synchronously while the PARENT renders, so a plain `.on("change") -> setState`
// updates this component during the parent's render (React warns). useSyncExternalStore
// is built for exactly this: it reads a snapshot and reconciles store-changes-during-
// render safely. The snapshot is a primitive boolean, so it never re-renders needlessly.
return useSyncExternalStore(
(onStoreChange) => mv.on("change", onStoreChange),
() => mv.get() > threshold,
() => mv.get() > threshold,
);
}
/** Active step index from scroll progress (1 before the engine starts). */
function stepFromProgress(p: number): number {
@@ -71,6 +55,8 @@ function StepRail({ active }: { active: number }) {
/** One cross-fading workflow card pinned to the lower-left. */
function StoryCard({
step,
index,
opacity,
y,
num,
@@ -78,6 +64,8 @@ function StoryCard({
title,
children,
}: {
step: number;
index: number;
opacity: MotionValue<number>;
y: MotionValue<number>;
num: string;
@@ -85,8 +73,8 @@ function StoryCard({
title: string;
children?: React.ReactNode;
}) {
// Don't mount this beat's card until its cross-fade window opens.
if (!useInWindow(opacity)) return null;
// Don't mount this beat's card until its step is active.
if (step !== index) return null;
return (
<motion.div className="dm-lb-card-story" style={{ opacity, y }}>
<div className="dm-lb-card-story__head">
@@ -230,7 +218,7 @@ export default function LogisticsBrainSection({ connected = false }: { connected
</motion.div>
{/* STEP 01 — Generate Routes */}
<StoryCard opacity={p1o} y={p1y} num="01" kicker="Generate Routes" title="We create many delivery plans at once">
<StoryCard step={step} index={0} opacity={p1o} y={p1y} num="01" kicker="Generate Routes" title="We create many delivery plans at once">
<div className="dm-lb-chips">
{STRATEGIES.map((s) => (
<span key={s} className="dm-lb-chip">{s}</span>
@@ -240,7 +228,7 @@ export default function LogisticsBrainSection({ connected = false }: { connected
</StoryCard>
{/* STEP 02 — Check Constraints (the EV paradox) */}
<StoryCard opacity={p2o} y={p2y} num="02" kicker="Check Constraints" title="Every plan must respect real-world limits">
<StoryCard step={step} index={1} opacity={p2o} y={p2y} num="02" kicker="Check Constraints" title="Every plan must respect real-world limits">
<ul className="dm-lb-constraints">
{CONSTRAINT_LIST.map((c) => (
<li key={c.label}>
@@ -254,7 +242,7 @@ export default function LogisticsBrainSection({ connected = false }: { connected
</StoryCard>
{/* STEP 03 — Score & Compare (the leaderboard) */}
<StoryCard opacity={p3o} y={p3y} num="03" kicker="Score &amp; Compare" title="Each plan is scored by total delivery cost">
<StoryCard step={step} index={2} opacity={p3o} y={p3y} num="03" kicker="Score &amp; Compare" title="Each plan is scored by total delivery cost">
<ul className="dm-lb-board">
{STRATEGY_SCORES.map((s) => (
<li key={s.name} className={s.win ? "is-win" : ""}>
@@ -267,7 +255,7 @@ export default function LogisticsBrainSection({ connected = false }: { connected
</StoryCard>
{/* STEP 04 — Guarantee On-Time */}
<StoryCard opacity={p4o} y={p4y} num="04" kicker="Guarantee On-Time" title="Any plan even 1 minute late is rejected">
<StoryCard step={step} index={3} opacity={p4o} y={p4y} num="04" kicker="Guarantee On-Time" title="Any plan even 1 minute late is rejected">
<div className="dm-lb-sla">
<span className="dm-lb-sla__badge"> On-time only</span>
<span className="dm-lb-sla__x"> Late plan dropped</span>
@@ -276,7 +264,7 @@ export default function LogisticsBrainSection({ connected = false }: { connected
</StoryCard>
{/* STEP 05 — Pick & Dispatch */}
<StoryCard opacity={p5o} y={p5y} num="05" kicker="Pick &amp; Dispatch" title="The winning plan is sent to the fleet">
<StoryCard step={step} index={4} opacity={p5o} y={p5y} num="05" kicker="Pick &amp; Dispatch" title="The winning plan is sent to the fleet">
<div className="dm-lb-winner"> Multi-Trip selected lowest cost, zero delays</div>
<div className="dm-lb-chips">
<span className="dm-lb-chip">EV Bikes</span>