Skip to content

Commit 9f091cf

Browse files
committed
feat: add velocity color preset support to OverlaySettingsPanel and ReplayComparisonSidebar
1 parent 7e61ecd commit 9f091cf

3 files changed

Lines changed: 50 additions & 12 deletions

File tree

app/components/OverlaySettingsPanel.tsx

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useMemo } from 'react';
44
import { RotateCcwIcon } from 'lucide-react';
55
import { Switch } from '@/components/ui/switch';
66
import { SidebarPanel } from './SidebarPanel';
7+
import type { VelocityColorPreset } from '../lib/trajectory-types';
78

89
const BODY_TRACK_LAYOUT = [
910
{
@@ -70,6 +71,7 @@ interface OverlaySettingsPanelProps {
7071
onHideAllTracks: () => void;
7172
onToggleTrajectoryTrack: (trackName: string) => void;
7273
onRemoveMetadata?: () => void;
74+
velocityColorPreset?: VelocityColorPreset | null;
7375
}
7476

7577
export function OverlaySettingsPanel({
@@ -88,6 +90,7 @@ export function OverlaySettingsPanel({
8890
onHideAllTracks,
8991
onToggleTrajectoryTrack,
9092
onRemoveMetadata,
93+
velocityColorPreset,
9194
}: OverlaySettingsPanelProps) {
9295
const visibleTrackNameSet = useMemo(() => new Set(visibleTrajectoryTrackNames), [visibleTrajectoryTrackNames]);
9396
const availableTrackNameSet = useMemo(() => new Set(availableTrajectoryTrackNames), [availableTrajectoryTrackNames]);
@@ -159,6 +162,29 @@ export function OverlaySettingsPanel({
159162
</div>
160163
</div>
161164

165+
{showTrajectory && velocityColorPreset && (
166+
<div>
167+
<p className="mb-2 text-[10px] font-semibold uppercase tracking-widest text-gray-400 dark:text-gray-500">
168+
Legend
169+
</p>
170+
<div className="grid grid-cols-3 gap-2 rounded-lg border border-gray-100 px-4 py-3 dark:border-gray-700 dark:bg-gray-800/60">
171+
{([
172+
{ label: 'Slower Velocity', bgr: velocityColorPreset.slowBgr },
173+
{ label: 'Average Velocity', bgr: velocityColorPreset.midBgr },
174+
{ label: 'Faster Velocity', bgr: velocityColorPreset.fastBgr },
175+
] as const).map(({ label, bgr }) => (
176+
<div key={label} className="flex items-center gap-2">
177+
<div
178+
className="h-4 w-4 shrink-0 rounded-sm border border-black/10 dark:border-white/10"
179+
style={{ backgroundColor: `rgb(${bgr[2]}, ${bgr[1]}, ${bgr[0]})` }}
180+
/>
181+
<span className="text-[11px] font-medium leading-tight text-gray-600 dark:text-gray-400">{label}</span>
182+
</div>
183+
))}
184+
</div>
185+
</div>
186+
)}
187+
162188
{showTrajectory && (
163189
<div>
164190
<div className="mb-2 flex items-center justify-between">
@@ -176,9 +202,9 @@ export function OverlaySettingsPanel({
176202
step={0.1}
177203
value={trajectoryHistorySeconds}
178204
onChange={(event) => onSetTrajectoryHistorySeconds(parseFloat(event.target.value))}
179-
className="h-3 w-full cursor-pointer appearance-none rounded-lg bg-gray-300 accent-cyan-600 hover:accent-cyan-700 dark:bg-gray-700"
205+
className="h-3 w-full cursor-pointer appearance-none rounded-lg bg-gray-300 accent-amber-600 hover:accent-amber-700 dark:bg-gray-700"
180206
/>
181-
<div className="mt-2 flex items-center justify-between text-[11px] font-medium text-cyan-700 dark:text-cyan-300">
207+
<div className="mt-2 flex items-center justify-between text-[11px] font-medium text-amber-700 dark:text-amber-300">
182208
<span>0.0s keeps the full history visible</span>
183209
<span>Limit trail length client-side</span>
184210
</div>
@@ -197,7 +223,7 @@ export function OverlaySettingsPanel({
197223
<button
198224
type="button"
199225
onClick={allTracksVisible ? onHideAllTracks : onShowAllTracks}
200-
className="rounded-full border border-cyan-200 bg-cyan-50 px-3 py-1.5 text-[11px] font-semibold text-cyan-700 transition-colors hover:bg-cyan-100 dark:border-cyan-900 dark:bg-cyan-950/50 dark:text-cyan-300"
226+
className="rounded-full border border-amber-200 bg-amber-50 px-3 py-1.5 text-[11px] font-semibold text-amber-700 transition-colors hover:bg-amber-100 dark:border-amber-900 dark:bg-amber-950/50 dark:text-amber-300"
201227
>
202228
{allTracksVisible ? 'Hide All' : 'Show All'}
203229
</button>
@@ -206,12 +232,12 @@ export function OverlaySettingsPanel({
206232

207233
{availableTrajectoryTrackNames.length > 0 ? (
208234
<fieldset className="space-y-4">
209-
<div className="relative h-88 w-full overflow-hidden rounded-2xl border border-cyan-100 bg-gradient-to-b from-cyan-50 to-white px-4 py-5 dark:border-cyan-950/60 dark:from-cyan-950/20 dark:to-gray-900">
210-
<div className="pointer-events-none absolute left-1/2 top-[16%] h-[44%] w-px -translate-x-1/2 bg-cyan-200 dark:bg-cyan-900" />
211-
<div className="pointer-events-none absolute left-1/2 top-[26%] h-px w-[46%] -translate-x-1/2 bg-cyan-200 dark:bg-cyan-900" />
212-
<div className="pointer-events-none absolute left-1/2 top-[60%] h-px w-[22%] -translate-x-1/2 bg-cyan-200 dark:bg-cyan-900" />
213-
<div className="pointer-events-none absolute left-[40%] top-[60%] h-[24%] w-px bg-cyan-200 dark:bg-cyan-900" />
214-
<div className="pointer-events-none absolute left-[60%] top-[60%] h-[24%] w-px bg-cyan-200 dark:bg-cyan-900" />
235+
<div className="relative h-88 w-full overflow-hidden rounded-2xl border border-amber-100 bg-gradient-to-b from-amber-50 to-white px-4 py-5 dark:border-amber-950/60 dark:from-amber-950/20 dark:to-gray-900">
236+
<div className="pointer-events-none absolute left-1/2 top-[16%] h-[44%] w-px -translate-x-1/2 bg-amber-200 dark:bg-amber-900" />
237+
<div className="pointer-events-none absolute left-1/2 top-[26%] h-px w-[46%] -translate-x-1/2 bg-amber-200 dark:bg-amber-900" />
238+
<div className="pointer-events-none absolute left-1/2 top-[60%] h-px w-[22%] -translate-x-1/2 bg-amber-200 dark:bg-amber-900" />
239+
<div className="pointer-events-none absolute left-[40%] top-[60%] h-[24%] w-px bg-amber-200 dark:bg-amber-900" />
240+
<div className="pointer-events-none absolute left-[60%] top-[60%] h-[24%] w-px bg-amber-200 dark:bg-amber-900" />
215241

216242
{BODY_TRACK_LAYOUT.map((track) => {
217243
const isAvailable = availableTrackNameSet.has(track.trackName);
@@ -230,8 +256,8 @@ export function OverlaySettingsPanel({
230256
disabled={!isAvailable}
231257
className={`absolute min-w-26 rounded-full border px-3 py-2 text-center text-xs font-semibold shadow-sm transition-all ${track.className} ${isAvailable
232258
? isVisible
233-
? 'border-cyan-500 bg-cyan-500 text-white shadow-cyan-200 dark:border-cyan-400 dark:bg-cyan-400 dark:text-cyan-950 dark:shadow-transparent'
234-
: 'border-gray-200 bg-white text-gray-500 hover:border-cyan-300 hover:text-cyan-700 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:border-cyan-700 dark:hover:text-cyan-300'
259+
? 'border-amber-500 bg-amber-500 text-white shadow-amber-200 dark:border-amber-400 dark:bg-amber-400 dark:text-amber-950 dark:shadow-transparent'
260+
: 'border-gray-200 bg-white text-gray-500 hover:border-amber-300 hover:text-amber-700 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:border-amber-700 dark:hover:text-amber-300'
235261
: 'cursor-not-allowed border-dashed border-gray-200 bg-gray-100 text-gray-400 shadow-none dark:border-gray-700 dark:bg-gray-800/70 dark:text-gray-500'
236262
}`}
237263
>

app/components/replay/ReplayComparisonSidebar.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { SwipeStatsPanel } from '../SwipeStatsPanel';
55
import { VideoControlPanel } from '../VideoControlPanel';
66
import { OnboardingContent } from './OnboardingContent';
77
import type { KeyMoment } from '../../lib/key-moments';
8+
import type { VelocityColorPreset } from '../../lib/trajectory-types';
89

910
interface ReplayComparisonSidebarProps {
1011
// Video control
@@ -57,6 +58,7 @@ interface ReplayComparisonSidebarProps {
5758
onHideAllTracks: () => void;
5859
onToggleTrajectoryTrack: (trackName: string) => void;
5960
onRemoveMetadata?: () => void;
61+
velocityColorPreset?: VelocityColorPreset | null;
6062
}
6163

6264
export function ReplayComparisonSidebar({
@@ -107,6 +109,7 @@ export function ReplayComparisonSidebar({
107109
onHideAllTracks,
108110
onToggleTrajectoryTrack,
109111
onRemoveMetadata,
112+
velocityColorPreset,
110113
}: ReplayComparisonSidebarProps) {
111114
return (
112115
<div className="w-md shrink-0 h-full overflow-y-auto bg-gray-50 dark:bg-gray-950 border-l border-gray-200 dark:border-gray-700">
@@ -166,6 +169,7 @@ export function ReplayComparisonSidebar({
166169
onHideAllTracks={onHideAllTracks}
167170
onToggleTrajectoryTrack={onToggleTrajectoryTrack}
168171
onRemoveMetadata={onRemoveMetadata}
172+
velocityColorPreset={velocityColorPreset}
169173
/>}
170174
</div>
171175
</div>

app/components/replay/ReplayComparisonWorkspace.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { useOverlaySettings } from '../../hooks/useOverlaySettings';
1616
import { useVideoControl } from '../../hooks/useVideoControl';
1717
import { useVideoFps } from '../../hooks/useVideoFps';
1818
import type { KeyMoment } from '../../lib/key-moments';
19-
import type { TrajectoryMetadata } from '../../lib/trajectory-types';
19+
import type { TrajectoryMetadata, VelocityColorPreset } from '../../lib/trajectory-types';
2020
import type { PresetComparison } from '../../lib/presets';
2121

2222
export interface SplitViewContentProps {
@@ -74,6 +74,13 @@ export function ReplayComparisonWorkspace({
7474
const [shortcutsOpen, setShortcutsOpen] = useState(false);
7575
const hasVideoByIndex: [boolean, boolean] = [Boolean(videoUrls[0]), Boolean(videoUrls[1])];
7676

77+
const velocityColorPreset = useMemo<VelocityColorPreset | null>(() => {
78+
const meta = overlayMetadataByIndex[0] ?? overlayMetadataByIndex[1];
79+
if (!meta) return null;
80+
const presetName = meta.style.defaultVelocityColorPreset;
81+
return meta.style.velocityColorPresets[presetName] ?? null;
82+
}, [overlayMetadataByIndex]);
83+
7784
const splitResetRef1 = useRef<(() => void) | null>(null);
7885
const splitResetRef2 = useRef<(() => void) | null>(null);
7986
const overlayResetRef = useRef<(() => void) | null>(null);
@@ -330,6 +337,7 @@ export function ReplayComparisonWorkspace({
330337
onHideAllTracks={hideAllTrajectoryTracks}
331338
onToggleTrajectoryTrack={toggleTrajectoryTrack}
332339
onRemoveMetadata={onRemoveMetadata}
340+
velocityColorPreset={velocityColorPreset}
333341
/>
334342
</div>
335343
);

0 commit comments

Comments
 (0)