style: apply oxfmt baseline formatting across all source files (#25)

## Summary
- Run `oxfmt .` across the entire codebase to establish formatted baseline
- 299 files changed — mechanical formatting only, no logic changes
- Double quotes, semicolons, 2-space indent, trailing commas, 100 print width

Part 3/4 of [VA-851](https://linear.app/heygen/issue/VA-851/pre-migration-configure-eslint-prettier-and-conventional-commits)

## Test plan
- [x] `pnpm format:check` — all 426 files pass
- [x] `pnpm -r typecheck` — all packages pass
- [x] `pnpm build` — all packages build
- [x] All 348 tests pass
This commit is contained in:
Vance Ingalls
2026-03-23 17:15:14 -07:00
committed by GitHub
parent 323ff8f860
commit 20be2ea1c2
299 changed files with 27750 additions and 16792 deletions
@@ -18,33 +18,31 @@ interface AgentActivityTrackProps {
duration: number;
}
export const AgentActivityTrack = memo(function AgentActivityTrack({ agents, duration }: AgentActivityTrackProps) {
export const AgentActivityTrack = memo(function AgentActivityTrack({
agents,
duration,
}: AgentActivityTrackProps) {
if (agents.length === 0 || duration <= 0) return null;
return (
<div className="border-t border-neutral-800/30">
{/* Section header */}
<div className="flex items-center gap-1.5 px-2 py-1 text-[9px] text-neutral-600 font-medium uppercase tracking-wider">
<svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="4" /></svg>
<svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor">
<circle cx="12" cy="12" r="4" />
</svg>
Agent Activity
</div>
{agents.map((agent) => (
<div
key={agent.agentId}
className="relative flex"
style={{ height: TRACK_H }}
>
<div key={agent.agentId} className="relative flex" style={{ height: TRACK_H }}>
{/* Gutter: agent name */}
<div
className="flex-shrink-0 flex items-center justify-center"
style={{ width: GUTTER }}
title={agent.name}
>
<div
className="w-2 h-2 rounded-full"
style={{ backgroundColor: agent.color }}
/>
<div className="w-2 h-2 rounded-full" style={{ backgroundColor: agent.color }} />
</div>
{/* Lane */}
@@ -77,10 +75,7 @@ export const AgentActivityTrack = memo(function AgentActivityTrack({ agents, dur
style={{ left: `${leftPct}%` }}
>
{event.type === "create" ? (
<div
className="w-2 h-2 rotate-45"
style={{ backgroundColor: agent.color }}
/>
<div className="w-2 h-2 rotate-45" style={{ backgroundColor: agent.color }} />
) : (
<div
className="w-1.5 h-1.5 rounded-full"
+104 -94
View File
@@ -11,110 +11,120 @@ interface PlayerProps {
portrait?: boolean;
}
export const Player = forwardRef<HTMLIFrameElement, PlayerProps>(({ projectId, directUrl, onLoad, portrait }, ref) => {
const containerRef = useRef<HTMLDivElement>(null);
const [scale, setScale] = useState(1);
const dimsRef = useRef({ w: portrait ? NATIVE_H : NATIVE_W, h: portrait ? NATIVE_W : NATIVE_H });
const [dims, setDims] = useState(dimsRef.current);
const loadCountRef = useRef(0);
export const Player = forwardRef<HTMLIFrameElement, PlayerProps>(
({ projectId, directUrl, onLoad, portrait }, ref) => {
const containerRef = useRef<HTMLDivElement>(null);
const [scale, setScale] = useState(1);
const dimsRef = useRef({
w: portrait ? NATIVE_H : NATIVE_W,
h: portrait ? NATIVE_W : NATIVE_H,
});
const [dims, setDims] = useState(dimsRef.current);
const loadCountRef = useRef(0);
const updateScale = useCallback(() => {
const el = containerRef.current;
if (!el) return;
const rect = el.getBoundingClientRect();
const d = dimsRef.current;
setScale(Math.min(rect.width / d.w, rect.height / d.h));
}, []);
const updateScale = useCallback(() => {
const el = containerRef.current;
if (!el) return;
const rect = el.getBoundingClientRect();
const d = dimsRef.current;
setScale(Math.min(rect.width / d.w, rect.height / d.h));
}, []);
useMountEffect(() => {
updateScale();
const ro = new ResizeObserver(updateScale);
if (containerRef.current) ro.observe(containerRef.current);
useMountEffect(() => {
updateScale();
const ro = new ResizeObserver(updateScale);
if (containerRef.current) ro.observe(containerRef.current);
// Listen for stage-size messages from the runtime
const handleMessage = (e: MessageEvent) => {
const data = e.data;
if ((data?.source === "hf-preview" || data?.source === "hf-preview") && data?.type === "stage-size" && data.width > 0 && data.height > 0) {
if (dimsRef.current.w !== data.width || dimsRef.current.h !== data.height) {
dimsRef.current = { w: data.width, h: data.height };
setDims(dimsRef.current);
updateScale();
}
}
};
window.addEventListener("message", handleMessage);
return () => {
ro.disconnect();
window.removeEventListener("message", handleMessage);
};
});
const handleLoad = useCallback(() => {
loadCountRef.current++;
// Auto-detect dimensions from the composition's data-width/data-height
try {
const iframeEl = typeof ref === "function" ? null : ref?.current;
const doc = iframeEl?.contentDocument;
if (doc) {
const root = doc.querySelector("[data-composition-id]");
if (root) {
const dw = parseInt(root.getAttribute("data-width") || "0", 10);
const dh = parseInt(root.getAttribute("data-height") || "0", 10);
if (dw > 0 && dh > 0 && (dw !== dimsRef.current.w || dh !== dimsRef.current.h)) {
dimsRef.current = { w: dw, h: dh };
// Listen for stage-size messages from the runtime
const handleMessage = (e: MessageEvent) => {
const data = e.data;
if (
(data?.source === "hf-preview" || data?.source === "hf-preview") &&
data?.type === "stage-size" &&
data.width > 0 &&
data.height > 0
) {
if (dimsRef.current.w !== data.width || dimsRef.current.h !== data.height) {
dimsRef.current = { w: data.width, h: data.height };
setDims(dimsRef.current);
// Recalc scale with new dims
const el = containerRef.current;
if (el) {
const rect = el.getBoundingClientRect();
setScale(Math.min(rect.width / dw, rect.height / dh));
updateScale();
}
}
};
window.addEventListener("message", handleMessage);
return () => {
ro.disconnect();
window.removeEventListener("message", handleMessage);
};
});
const handleLoad = useCallback(() => {
loadCountRef.current++;
// Auto-detect dimensions from the composition's data-width/data-height
try {
const iframeEl = typeof ref === "function" ? null : ref?.current;
const doc = iframeEl?.contentDocument;
if (doc) {
const root = doc.querySelector("[data-composition-id]");
if (root) {
const dw = parseInt(root.getAttribute("data-width") || "0", 10);
const dh = parseInt(root.getAttribute("data-height") || "0", 10);
if (dw > 0 && dh > 0 && (dw !== dimsRef.current.w || dh !== dimsRef.current.h)) {
dimsRef.current = { w: dw, h: dh };
setDims(dimsRef.current);
// Recalc scale with new dims
const el = containerRef.current;
if (el) {
const rect = el.getBoundingClientRect();
setScale(Math.min(rect.width / dw, rect.height / dh));
}
}
}
}
} catch {
// Cross-origin
}
} catch {
// Cross-origin
}
if (loadCountRef.current > 1) {
const el = containerRef.current;
if (el) {
el.classList.remove("preview-revealing");
void el.offsetWidth;
el.classList.add("preview-revealing");
const onEnd = () => el.classList.remove("preview-revealing");
el.addEventListener("animationend", onEnd, { once: true });
if (loadCountRef.current > 1) {
const el = containerRef.current;
if (el) {
el.classList.remove("preview-revealing");
void el.offsetWidth;
el.classList.add("preview-revealing");
const onEnd = () => el.classList.remove("preview-revealing");
el.addEventListener("animationend", onEnd, { once: true });
}
}
}
onLoad();
}, [onLoad, ref]);
onLoad();
}, [onLoad, ref]);
return (
<div
ref={containerRef}
className="w-full h-full max-w-full max-h-full overflow-hidden shadow-float border border-neutral-800 bg-black flex items-center justify-center rounded-card-inner"
>
<iframe
ref={ref}
src={directUrl || `/api/projects/${projectId}/preview`}
onLoad={handleLoad}
sandbox="allow-scripts allow-same-origin"
allow="autoplay; fullscreen"
referrerPolicy="no-referrer"
title="Project Preview"
style={{
width: dims.w,
height: dims.h,
border: "none",
transform: `scale(${scale})`,
transformOrigin: "center center",
flexShrink: 0,
}}
/>
</div>
);
});
return (
<div
ref={containerRef}
className="w-full h-full max-w-full max-h-full overflow-hidden shadow-float border border-neutral-800 bg-black flex items-center justify-center rounded-card-inner"
>
<iframe
ref={ref}
src={directUrl || `/api/projects/${projectId}/preview`}
onLoad={handleLoad}
sandbox="allow-scripts allow-same-origin"
allow="autoplay; fullscreen"
referrerPolicy="no-referrer"
title="Project Preview"
style={{
width: dims.w,
height: dims.h,
border: "none",
transform: `scale(${scale})`,
transformOrigin: "center center",
flexShrink: 0,
}}
/>
</div>
);
},
);
Player.displayName = "Player";
@@ -16,7 +16,11 @@ interface PlayerControlsProps {
onSeek: (time: number) => void;
}
export const PlayerControls = memo(function PlayerControls({ onTogglePlay, onSeek, ...overrides }: PlayerControlsProps) {
export const PlayerControls = memo(function PlayerControls({
onTogglePlay,
onSeek,
...overrides
}: PlayerControlsProps) {
// Subscribe to only the fields we render — each selector prevents cascading re-renders
const storeIsPlaying = usePlayerStore((s) => s.isPlaying);
const storeDuration = usePlayerStore((s) => s.duration);
@@ -165,9 +169,14 @@ export const PlayerControls = memo(function PlayerControls({ onTogglePlay, onSee
{SPEED_OPTIONS.map((rate) => (
<button
key={rate}
onClick={() => { setPlaybackRate(rate); setShowSpeedMenu(false); }}
onClick={() => {
setPlaybackRate(rate);
setShowSpeedMenu(false);
}}
className={`block w-full px-3 py-1 text-xs text-left font-mono tabular-nums transition-colors ${
rate === playbackRate ? "text-white bg-neutral-800" : "text-neutral-400 hover:text-white hover:bg-neutral-800"
rate === playbackRate
? "text-white bg-neutral-800"
: "text-neutral-400 hover:text-white hover:bg-neutral-800"
}`}
>
{rate}x
@@ -36,7 +36,6 @@ export function PreviewPanel({
renderStatus,
children,
}: PreviewPanelProps) {
const renderState = renderStatus?.state ?? "idle";
return (
@@ -52,71 +51,102 @@ export function PreviewPanel({
{hasProject && projectId ? (
<>
{/* Player — takes all remaining space, constrained for portrait */}
<div className="flex items-center justify-center p-2 overflow-hidden" style={{ minHeight: 0, minWidth: 0 }}>
<Player ref={iframeRef} projectId={projectId} onLoad={onIframeLoad} portrait={portrait} />
<div
className="flex items-center justify-center p-2 overflow-hidden"
style={{ minHeight: 0, minWidth: 0 }}
>
<Player
ref={iframeRef}
projectId={projectId}
onLoad={onIframeLoad}
portrait={portrait}
/>
</div>
{/* Controls — fixed height */}
<div className="bg-neutral-950 border-t border-neutral-800 flex-shrink-0">
<PlayerControls
onTogglePlay={onTogglePlay}
onSeek={onSeek}
/>
<PlayerControls onTogglePlay={onTogglePlay} onSeek={onSeek} />
</div>
{/* Timeline — capped height, internal scroll */}
<div className="bg-neutral-950 flex-shrink-0 overflow-y-auto" style={{ maxHeight: "100px" }}>
<div
className="bg-neutral-950 flex-shrink-0 overflow-y-auto"
style={{ maxHeight: "100px" }}
>
<Timeline onSeek={onSeek} />
</div>
{/* Render status — only shown when actively rendering, complete, or error */}
{renderStatus && (renderState === "rendering" || renderState === "complete" || renderState === "error") && (
<div className="bg-neutral-950 border-t border-neutral-800 px-4 py-2 flex items-center justify-end gap-2 flex-shrink-0">
{renderState === "rendering" && (
<div className="flex-1">
<div className="flex items-center gap-2">
<div className="flex-1 h-1.5 bg-neutral-800 rounded-full overflow-hidden">
<div
className="h-full bg-blue-500 rounded-full transition-[width] duration-200"
style={{ width: `${renderStatus.progress ?? 0}%` }}
/>
{renderStatus &&
(renderState === "rendering" ||
renderState === "complete" ||
renderState === "error") && (
<div className="bg-neutral-950 border-t border-neutral-800 px-4 py-2 flex items-center justify-end gap-2 flex-shrink-0">
{renderState === "rendering" && (
<div className="flex-1">
<div className="flex items-center gap-2">
<div className="flex-1 h-1.5 bg-neutral-800 rounded-full overflow-hidden">
<div
className="h-full bg-blue-500 rounded-full transition-[width] duration-200"
style={{ width: `${renderStatus.progress ?? 0}%` }}
/>
</div>
<span className="text-xs text-neutral-400 flex-shrink-0">
{renderStatus.stage || "Rendering..."}
</span>
</div>
<span className="text-xs text-neutral-400 flex-shrink-0">
{renderStatus.stage || "Rendering..."}
</span>
</div>
</div>
)}
{renderState === "complete" && (
<div className="flex items-center gap-1.5 text-xs text-green-400">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
<polyline points="22 4 12 14.01 9 11.01" />
</svg>
<span>Complete</span>
</div>
)}
{renderState === "error" && (
<div className="flex items-center gap-2 text-xs text-red-400">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="8" x2="12" y2="12" />
<line x1="12" y1="16" x2="12.01" y2="16" />
</svg>
<span className="truncate">{renderStatus.error}</span>
{renderStatus.onRender && (
<button
type="button"
onClick={renderStatus.onRender}
className="flex-shrink-0 px-2 py-0.5 text-xs text-neutral-300 hover:text-white hover:bg-neutral-800 rounded transition-colors"
)}
{renderState === "complete" && (
<div className="flex items-center gap-1.5 text-xs text-green-400">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
Retry
</button>
)}
</div>
)}
</div>
)}
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
<polyline points="22 4 12 14.01 9 11.01" />
</svg>
<span>Complete</span>
</div>
)}
{renderState === "error" && (
<div className="flex items-center gap-2 text-xs text-red-400">
<svg
width="12"
height="12"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="8" x2="12" y2="12" />
<line x1="12" y1="16" x2="12.01" y2="16" />
</svg>
<span className="truncate">{renderStatus.error}</span>
{renderStatus.onRender && (
<button
type="button"
onClick={renderStatus.onRender}
className="flex-shrink-0 px-2 py-0.5 text-xs text-neutral-300 hover:text-white hover:bg-neutral-800 rounded transition-colors"
>
Retry
</button>
)}
</div>
)}
</div>
)}
{/* Optional custom slot */}
{children}
@@ -140,7 +170,9 @@ export function PreviewPanel({
</svg>
</div>
<p className="text-sm text-neutral-600">Preview will appear here</p>
<p className="text-xs text-neutral-700 mt-1">Send a message to generate a video composition</p>
<p className="text-xs text-neutral-700 mt-1">
Send a message to generate a video composition
</p>
</div>
</div>
)}
@@ -25,7 +25,16 @@ interface TrackStyle {
/* ── Icons from Figma HyperFrames design system ── */
const ICON_BASE = "/icons/timeline";
function TimelineIcon({ src }: { src: string }) {
return <img src={src} alt="" width={12} height={12} style={{ filter: "brightness(0) invert(1)" }} draggable={false} />;
return (
<img
src={src}
alt=""
width={12}
height={12}
style={{ filter: "brightness(0) invert(1)" }}
draggable={false}
/>
);
}
const IconCaptions = <TimelineIcon src={`${ICON_BASE}/captions.svg`} />;
const IconImage = <TimelineIcon src={`${ICON_BASE}/image.svg`} />;
@@ -125,7 +134,9 @@ function generateTicks(duration: number): { major: number[]; minor: number[] } {
const minor: number[] = [];
for (let t = 0; t <= duration + 0.001; t += minorInterval) {
const rounded = Math.round(t * 100) / 100;
const isMajor = Math.abs(rounded % majorInterval) < 0.01 || Math.abs(rounded % majorInterval - majorInterval) < 0.01;
const isMajor =
Math.abs(rounded % majorInterval) < 0.01 ||
Math.abs((rounded % majorInterval) - majorInterval) < 0.01;
if (isMajor) major.push(rounded);
else minor.push(rounded);
}
@@ -198,10 +209,14 @@ export const Timeline = memo(function Timeline({ onSeek, onDrillDown }: Timeline
[seekFromX],
);
const handlePointerMove = useCallback(
(e: React.PointerEvent) => { if (isDragging.current) seekFromX(e.clientX); },
(e: React.PointerEvent) => {
if (isDragging.current) seekFromX(e.clientX);
},
[seekFromX],
);
const handlePointerUp = useCallback(() => { isDragging.current = false; }, []);
const handlePointerUp = useCallback(() => {
isDragging.current = false;
}, []);
const tracks = useMemo(() => {
const map = new Map<number, typeof elements>();
@@ -226,7 +241,11 @@ export const Timeline = memo(function Timeline({ onSeek, onDrillDown }: Timeline
if (!timelineReady) return null;
if (elements.length === 0) {
return <div className="px-3 py-3 text-2xs text-neutral-600 border-t border-neutral-800/50">No timeline elements</div>;
return (
<div className="px-3 py-3 text-2xs text-neutral-600 border-t border-neutral-800/50">
No timeline elements
</div>
);
}
const totalH = RULER_H + tracks.length * TRACK_H;
@@ -243,22 +262,48 @@ export const Timeline = memo(function Timeline({ onSeek, onDrillDown }: Timeline
>
<div className="relative" style={{ height: totalH }}>
{/* Grid lines */}
<svg className="absolute pointer-events-none" style={{ left: GUTTER }} width={`calc(100% - ${GUTTER}px)`} height={totalH}>
<svg
className="absolute pointer-events-none"
style={{ left: GUTTER }}
width={`calc(100% - ${GUTTER}px)`}
height={totalH}
>
{major.map((t) => (
<line key={`g-${t}`} x1={`${(t / duration) * 100}%`} y1={RULER_H} x2={`${(t / duration) * 100}%`} y2={totalH} stroke="rgba(255,255,255,0.035)" strokeWidth="1" />
<line
key={`g-${t}`}
x1={`${(t / duration) * 100}%`}
y1={RULER_H}
x2={`${(t / duration) * 100}%`}
y2={totalH}
stroke="rgba(255,255,255,0.035)"
strokeWidth="1"
/>
))}
</svg>
{/* Ruler */}
<div className="relative border-b border-neutral-800/40" style={{ height: RULER_H, marginLeft: GUTTER }}>
<div
className="relative border-b border-neutral-800/40"
style={{ height: RULER_H, marginLeft: GUTTER }}
>
{minor.map((t) => (
<div key={`m-${t}`} className="absolute bottom-0" style={{ left: `${(t / duration) * 100}%` }}>
<div
key={`m-${t}`}
className="absolute bottom-0"
style={{ left: `${(t / duration) * 100}%` }}
>
<div className="w-px h-[3px] bg-neutral-700/40" />
</div>
))}
{major.map((t) => (
<div key={`M-${t}`} className="absolute bottom-0 flex flex-col items-center" style={{ left: `${(t / duration) * 100}%` }}>
<span className="text-[9px] text-neutral-500 font-mono tabular-nums leading-none mb-0.5">{formatTick(t)}</span>
<div
key={`M-${t}`}
className="absolute bottom-0 flex flex-col items-center"
style={{ left: `${(t / duration) * 100}%` }}
>
<span className="text-[9px] text-neutral-500 font-mono tabular-nums leading-none mb-0.5">
{formatTick(t)}
</span>
<div className="w-px h-[5px] bg-neutral-600/60" />
</div>
))}
@@ -268,9 +313,16 @@ export const Timeline = memo(function Timeline({ onSeek, onDrillDown }: Timeline
{tracks.map(([trackNum, els]) => {
const ts = trackStyles.get(trackNum) ?? DEFAULT;
return (
<div key={trackNum} className="relative flex" style={{ height: TRACK_H, backgroundColor: ts.row }}>
<div
key={trackNum}
className="relative flex"
style={{ height: TRACK_H, backgroundColor: ts.row }}
>
{/* Gutter: colored icon badge (Figma HyperFrames style) */}
<div className="flex-shrink-0 flex items-center justify-center" style={{ width: GUTTER }}>
<div
className="flex-shrink-0 flex items-center justify-center"
style={{ width: GUTTER }}
>
<div
className="flex items-center justify-center"
style={{
@@ -314,7 +366,9 @@ export const Timeline = memo(function Timeline({ onSeek, onDrillDown }: Timeline
backgroundImage: isComposition
? `repeating-linear-gradient(135deg, transparent, transparent 3px, rgba(255,255,255,0.08) 3px, rgba(255,255,255,0.08) 6px)`
: undefined,
border: isSelected ? `2px solid rgba(255,255,255,0.9)` : `1px solid rgba(255,255,255,${isHovered ? 0.3 : 0.15})`,
border: isSelected
? `2px solid rgba(255,255,255,0.9)`
: `1px solid rgba(255,255,255,${isHovered ? 0.3 : 0.15})`,
boxShadow: isSelected
? `0 0 0 1px ${style.clip}, 0 2px 8px rgba(0,0,0,0.4)`
: isBeingEdited
@@ -327,9 +381,11 @@ export const Timeline = memo(function Timeline({ onSeek, onDrillDown }: Timeline
transform: isHovered && !isSelected ? "scaleY(1.04)" : "scaleY(1)",
zIndex: isSelected ? 10 : isHovered ? 5 : 1,
}}
title={isComposition
? `${el.compositionSrc} \u2022 Double-click to open`
: `${el.id || el.tag} \u2022 ${el.start.toFixed(1)}s \u2013 ${(el.start + el.duration).toFixed(1)}s`}
title={
isComposition
? `${el.compositionSrc} \u2022 Double-click to open`
: `${el.id || el.tag} \u2022 ${el.start.toFixed(1)}s \u2013 ${(el.start + el.duration).toFixed(1)}s`
}
onPointerEnter={() => setHoveredClip(clipKey)}
onPointerLeave={() => setHoveredClip(null)}
onPointerDown={(e) => e.stopPropagation()}
@@ -370,8 +426,19 @@ export const Timeline = memo(function Timeline({ onSeek, onDrillDown }: Timeline
}}
>
{/* Mini cursor arrow */}
<svg width="8" height="10" viewBox="0 0 12 16" fill="none" style={{ flexShrink: 0 }}>
<path d="M1 1L11 7L6 8L4 14L1 1Z" fill={activeEdit.agentColor} stroke="white" strokeWidth="0.8" />
<svg
width="8"
height="10"
viewBox="0 0 12 16"
fill="none"
style={{ flexShrink: 0 }}
>
<path
d="M1 1L11 7L6 8L4 14L1 1Z"
fill={activeEdit.agentColor}
stroke="white"
strokeWidth="0.8"
/>
</svg>
<span
className="text-[8px] font-semibold px-1 py-px rounded whitespace-nowrap"
@@ -416,13 +483,15 @@ export const Timeline = memo(function Timeline({ onSeek, onDrillDown }: Timeline
>
<div className="absolute top-0 bottom-0 left-1/2 -translate-x-1/2 w-px bg-white/90" />
<div className="absolute left-1/2 -translate-x-1/2" style={{ top: 0 }}>
<div style={{
width: 0,
height: 0,
borderLeft: "5px solid transparent",
borderRight: "5px solid transparent",
borderTop: "7px solid rgba(255,255,255,0.95)",
}} />
<div
style={{
width: 0,
height: 0,
borderLeft: "5px solid transparent",
borderRight: "5px solid transparent",
borderTop: "7px solid rgba(255,255,255,0.95)",
}}
/>
</div>
</div>
</div>