File size: 2,009 Bytes
7312c42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { forwardRef } from 'react'
import { Plus } from 'lucide-react'
import { Button, type ButtonProps } from '@/components/ui/button'
import { cn } from '@/lib/utils'

export interface TrackSegmentGap {
  startFrame: number
  endFrame: number
}

interface TrackGapAddButtonProps extends Omit<ButtonProps, 'children' | 'aria-label'> {
  gap: TrackSegmentGap
  totalLength: number
  width: number
  ariaLabel: string
}

export function getTrackSegmentGaps(
  segments: ReadonlyArray<{ start_frame: number; end_frame: number }>,
): TrackSegmentGap[] {
  const sorted = [...segments].sort((left, right) => left.start_frame - right.start_frame)
  if (sorted.length === 0) return []

  const gaps: TrackSegmentGap[] = sorted[0].start_frame > 0
    ? [{ startFrame: 0, endFrame: sorted[0].start_frame }]
    : []
  let coveredEnd = sorted[0].end_frame
  for (const segment of sorted.slice(1)) {
    if (segment.start_frame > coveredEnd) {
      gaps.push({ startFrame: coveredEnd, endFrame: segment.start_frame })
    }
    coveredEnd = Math.max(coveredEnd, segment.end_frame)
  }
  return gaps
}

export const TrackGapAddButton = forwardRef<HTMLButtonElement, TrackGapAddButtonProps>(function TrackGapAddButton({
  gap,
  totalLength,
  width,
  ariaLabel,
  onClick,
  className,
  style,
  ...buttonProps
}, ref) {
  const centerFrame = gap.startFrame + (gap.endFrame - gap.startFrame) / 2
  const left = centerFrame / Math.max(totalLength, 1) * width

  return (
    <Button
      {...buttonProps}
      ref={ref}
      type="button"
      variant="secondary"
      size="icon"
      data-testid={`track-gap-add-${gap.startFrame}-${gap.endFrame}`}
      className={cn(
        'absolute top-1/2 z-10 h-5 w-5 -translate-x-1/2 -translate-y-1/2 cursor-pointer',
        className,
      )}
      style={{ ...style, left }}
      aria-label={ariaLabel}
      onClick={(event) => {
        event.stopPropagation()
        onClick?.(event)
      }}
    >
      <Plus className="h-2.5 w-2.5" />
    </Button>
  )
})