(props: CaptionOverlayProps)
| 41 | } |
| 42 | |
| 43 | export function CaptionOverlay(props: CaptionOverlayProps) { |
| 44 | const { project, setProject, editorState, setEditorState, projectHistory } = |
| 45 | useEditorContext(); |
| 46 | const [measuredSize, setMeasuredSize] = createSignal({ width: 1, height: 1 }); |
| 47 | let hiddenMeasureRef: HTMLDivElement | undefined; |
| 48 | |
| 49 | const currentAbsoluteTime = () => |
| 50 | editorState.previewTime ?? editorState.playbackTime ?? 0; |
| 51 | |
| 52 | const settings = createMemo(() => ({ |
| 53 | ...defaultCaptionSettings, |
| 54 | ...project.captions?.settings, |
| 55 | })); |
| 56 | |
| 57 | const activeCaption = createMemo(() => { |
| 58 | if (!settings().enabled) return null; |
| 59 | const time = currentAbsoluteTime(); |
| 60 | const segments = project.timeline?.captionSegments ?? []; |
| 61 | const index = segments.findIndex( |
| 62 | (segment) => time >= segment.start && time < segment.end, |
| 63 | ); |
| 64 | if (index < 0) return null; |
| 65 | const segment = segments[index]; |
| 66 | if (!segment) return null; |
| 67 | return { index, segment }; |
| 68 | }); |
| 69 | |
| 70 | const text = createMemo(() => activeCaption()?.segment.text ?? ""); |
| 71 | |
| 72 | const scaledFontSize = createMemo(() => |
| 73 | Math.max(settings().size * (props.size.height / 1080), 1), |
| 74 | ); |
| 75 | |
| 76 | const margin = createMemo(() => props.size.width * 0.05); |
| 77 | const availableWidth = createMemo(() => |
| 78 | Math.max(props.size.width - margin() * 2, scaledFontSize()), |
| 79 | ); |
| 80 | const fitScale = createMemo(() => { |
| 81 | const padding = scaledFontSize() * 0.5; |
| 82 | const measuredWidth = measuredSize().width + padding * 2; |
| 83 | return measuredWidth > availableWidth() |
| 84 | ? Math.min(Math.max(availableWidth() / measuredWidth, 0.35), 1) |
| 85 | : 1; |
| 86 | }); |
| 87 | const effectiveFontSize = createMemo(() => scaledFontSize() * fitScale()); |
| 88 | |
| 89 | createEffect( |
| 90 | on( |
| 91 | () => |
| 92 | [ |
| 93 | text(), |
| 94 | scaledFontSize(), |
| 95 | availableWidth(), |
| 96 | settings().font, |
| 97 | settings().fontWeight, |
| 98 | fitScale(), |
| 99 | ] as const, |
| 100 | () => { |
nothing calls this directly
no test coverage detected