vzxipsule: Replace the featured rail with an auto-rotating FeaturedCarousel
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/** Rotation timing from the spec ("Featured experts carousel"). */
|
||||
export const FEATURED_INTERVAL_MS = 2800;
|
||||
|
||||
export type FeaturedSlot = "c0" | "l1" | "r1" | "l2" | "r2" | "l3" | "r3";
|
||||
|
||||
/**
|
||||
* Where item `i` sits when `current` is in the center: by its signed offset
|
||||
* from the current index, wrapped so the shorter way round wins. With two
|
||||
* items the other one is a single right neighbor, never an empty pair.
|
||||
*/
|
||||
export function featuredSlot(i: number, current: number, count: number): FeaturedSlot {
|
||||
let off = (((i - current) % count) + count) % count;
|
||||
if (off > count / 2) off -= count;
|
||||
if (off === 0) return "c0";
|
||||
if (off === 1) return "r1";
|
||||
if (off === -1) return "l1";
|
||||
if (off === 2) return "r2";
|
||||
if (off === -2) return "l2";
|
||||
return off > 0 ? "r3" : "l3";
|
||||
}
|
||||
|
||||
export interface FeaturedAutoplay {
|
||||
readonly index: number;
|
||||
readonly paused: boolean;
|
||||
pause(): void;
|
||||
resume(): void;
|
||||
stop(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the index every `intervalMs` while not paused. A single item never
|
||||
* rotates. The caller stops it on unmount.
|
||||
*/
|
||||
export function startFeaturedAutoplay(opts: {
|
||||
count: number;
|
||||
onChange: (index: number) => void;
|
||||
intervalMs?: number;
|
||||
start?: number;
|
||||
}): FeaturedAutoplay {
|
||||
const { count, onChange, intervalMs = FEATURED_INTERVAL_MS } = opts;
|
||||
let index = opts.start ?? 0;
|
||||
let paused = false;
|
||||
const timer =
|
||||
count > 1
|
||||
? setInterval(() => {
|
||||
if (paused) return;
|
||||
index = (index + 1) % count;
|
||||
onChange(index);
|
||||
}, intervalMs)
|
||||
: null;
|
||||
return {
|
||||
get index() { return index; },
|
||||
get paused() { return paused; },
|
||||
pause() { paused = true; },
|
||||
resume() { paused = false; },
|
||||
stop() { if (timer) clearInterval(timer); },
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user