mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-24 14:55:37 +00:00
feat(captions): add setting to toggle timeline hover-to-add
This commit is contained in:
@@ -2778,6 +2778,18 @@ export function SettingsPanel({
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3 rounded-lg bg-foreground/[0.03] px-2.5 py-2">
|
||||
<div className="text-[10px] text-muted-foreground">
|
||||
{tSettings("captions.timelineQuickAdd", "Hover to add on timeline")}
|
||||
</div>
|
||||
<Switch
|
||||
checked={autoCaptionSettings.timelineQuickAdd}
|
||||
onCheckedChange={(timelineQuickAdd) =>
|
||||
updateAutoCaptionSettings({ timelineQuickAdd })
|
||||
}
|
||||
className="data-[state=checked]:bg-[#2563EB] scale-75"
|
||||
/>
|
||||
</div>
|
||||
<label className="flex items-center justify-between rounded-lg bg-foreground/[0.03] px-2.5 py-2">
|
||||
<span className="text-[10px] text-muted-foreground">
|
||||
{tSettings("captions.textColor", "Text color")}
|
||||
|
||||
@@ -6848,6 +6848,7 @@ export default function VideoEditor() {
|
||||
onCaptionDelete={handleCaptionDelete}
|
||||
onCaptionAdded={handleCaptionAdded}
|
||||
captionsEnabled={autoCaptionSettings.enabled}
|
||||
captionQuickAddEnabled={autoCaptionSettings.timelineQuickAdd}
|
||||
annotationRegions={annotationRegions}
|
||||
onAnnotationAdded={handleAnnotationAdded}
|
||||
onAnnotationSpanChange={handleAnnotationSpanChange}
|
||||
|
||||
@@ -759,6 +759,10 @@ export function normalizeProjectEditor(editor: Partial<ProjectEditorState>): Pro
|
||||
typeof rawAutoCaptionSettings.enabled === "boolean"
|
||||
? rawAutoCaptionSettings.enabled
|
||||
: DEFAULT_AUTO_CAPTION_SETTINGS.enabled,
|
||||
timelineQuickAdd:
|
||||
typeof rawAutoCaptionSettings.timelineQuickAdd === "boolean"
|
||||
? rawAutoCaptionSettings.timelineQuickAdd
|
||||
: DEFAULT_AUTO_CAPTION_SETTINGS.timelineQuickAdd,
|
||||
language:
|
||||
typeof rawAutoCaptionSettings.language === "string" &&
|
||||
rawAutoCaptionSettings.language.trim()
|
||||
|
||||
@@ -74,6 +74,7 @@ export interface TimelineEditorProps {
|
||||
onCaptionDelete?: (id: string) => void;
|
||||
onCaptionAdded?: (span: Span) => void;
|
||||
captionsEnabled?: boolean;
|
||||
captionQuickAddEnabled?: boolean;
|
||||
selectedCaptionId?: string | null;
|
||||
onSelectCaption?: (id: string | null) => void;
|
||||
videoPath?: string | null;
|
||||
@@ -155,6 +156,7 @@ const TimelineEditor = forwardRef<TimelineEditorHandle, TimelineEditorProps>(
|
||||
onCaptionDelete,
|
||||
onCaptionAdded,
|
||||
captionsEnabled = false,
|
||||
captionQuickAddEnabled = true,
|
||||
selectedCaptionId,
|
||||
onSelectCaption,
|
||||
videoPath,
|
||||
@@ -477,6 +479,7 @@ const TimelineEditor = forwardRef<TimelineEditorHandle, TimelineEditorProps>(
|
||||
onAddCaptionAtMs={addCaptionAtMs}
|
||||
canPlaceCaptionAtMs={canPlaceCaptionAtMs}
|
||||
captionsEnabled={captionsEnabled}
|
||||
captionQuickAddEnabled={captionQuickAddEnabled}
|
||||
onSelectZoom={handleSelectZoom}
|
||||
onSelectClip={handleSelectClip}
|
||||
onSelectAnnotation={handleSelectAnnotation}
|
||||
|
||||
@@ -64,6 +64,7 @@ interface TimelineCanvasProps {
|
||||
onAddCaptionAtMs?: (startMs: number) => void;
|
||||
canPlaceCaptionAtMs?: (startMs: number) => boolean;
|
||||
captionsEnabled?: boolean;
|
||||
captionQuickAddEnabled?: boolean;
|
||||
selectedZoomId: string | null;
|
||||
selectedClipId?: string | null;
|
||||
selectedAnnotationId?: string | null;
|
||||
@@ -160,12 +161,13 @@ function useTimelineLaneHover({
|
||||
const onClick = useCallback(
|
||||
(event: MouseEvent<HTMLDivElement>) => {
|
||||
event.stopPropagation();
|
||||
if (!onAddAtMs || hoverMs === null) return;
|
||||
// Respect the lane's enabled flag so a hidden ghost can't still add on click.
|
||||
if (!enabled || !onAddAtMs || hoverMs === null) return;
|
||||
const startMs = Math.max(0, Math.min(hoverMs, videoDurationMs));
|
||||
if (canPlaceAtMs && !canPlaceAtMs(startMs)) return;
|
||||
onAddAtMs(startMs);
|
||||
},
|
||||
[canPlaceAtMs, onAddAtMs, videoDurationMs, hoverMs],
|
||||
[enabled, canPlaceAtMs, onAddAtMs, videoDurationMs, hoverMs],
|
||||
);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
@@ -215,6 +217,7 @@ interface TimelineHoverParams {
|
||||
onAddCaptionAtMs?: (startMs: number) => void;
|
||||
canPlaceCaptionAtMs?: (startMs: number) => boolean;
|
||||
captionsEnabled?: boolean;
|
||||
captionQuickAddEnabled?: boolean;
|
||||
isDragging: boolean;
|
||||
valueToPixels: (value: number) => number;
|
||||
}
|
||||
@@ -230,6 +233,7 @@ function useTimelineHover({
|
||||
onAddCaptionAtMs,
|
||||
canPlaceCaptionAtMs,
|
||||
captionsEnabled,
|
||||
captionQuickAddEnabled = true,
|
||||
isDragging,
|
||||
valueToPixels,
|
||||
}: TimelineHoverParams) {
|
||||
@@ -289,7 +293,7 @@ function useTimelineHover({
|
||||
videoDurationMs,
|
||||
valueToPixels,
|
||||
ghostDurationMs: Math.min(DEFAULT_CAPTION_DURATION_MS, videoDurationMs),
|
||||
enabled: Boolean(captionsEnabled),
|
||||
enabled: Boolean(captionsEnabled) && captionQuickAddEnabled,
|
||||
isDragging,
|
||||
onAddAtMs: onAddCaptionAtMs,
|
||||
canPlaceAtMs: canPlaceCaptionAtMs,
|
||||
@@ -731,6 +735,7 @@ export default function TimelineCanvas({
|
||||
onAddCaptionAtMs,
|
||||
canPlaceCaptionAtMs,
|
||||
captionsEnabled,
|
||||
captionQuickAddEnabled,
|
||||
onSelectZoom,
|
||||
onSelectClip,
|
||||
onSelectAnnotation,
|
||||
@@ -954,6 +959,7 @@ export default function TimelineCanvas({
|
||||
onAddCaptionAtMs,
|
||||
canPlaceCaptionAtMs,
|
||||
captionsEnabled,
|
||||
captionQuickAddEnabled,
|
||||
isDragging,
|
||||
valueToPixels,
|
||||
});
|
||||
|
||||
@@ -553,6 +553,8 @@ export type AutoCaptionAnimation = "none" | "fade" | "rise" | "pop";
|
||||
|
||||
export interface AutoCaptionSettings {
|
||||
enabled: boolean;
|
||||
/** Show the hover ghost on the timeline caption track for click-to-add. */
|
||||
timelineQuickAdd: boolean;
|
||||
language: string;
|
||||
fontFamily: string;
|
||||
fontSize: number;
|
||||
@@ -568,6 +570,7 @@ export interface AutoCaptionSettings {
|
||||
|
||||
export const DEFAULT_AUTO_CAPTION_SETTINGS: AutoCaptionSettings = {
|
||||
enabled: false,
|
||||
timelineQuickAdd: true,
|
||||
language: "auto",
|
||||
fontFamily: getDefaultCaptionFontFamily(),
|
||||
fontSize: 30,
|
||||
|
||||
@@ -168,6 +168,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "Select a caption on the timeline to edit it.",
|
||||
"enabled": "Show",
|
||||
"timelineQuickAdd": "Hover to add on timeline",
|
||||
"language": "Language",
|
||||
"downloading": "Downloading...",
|
||||
"deleteModel": "Delete Model",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "Selecciona un subtítulo en la línea de tiempo para editarlo.",
|
||||
"enabled": "Mostrar",
|
||||
"timelineQuickAdd": "Pasar el cursor para añadir en la línea de tiempo",
|
||||
"language": "Idioma",
|
||||
"downloading": "Descargando...",
|
||||
"deleteModel": "Eliminar modelo",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "Sélectionnez un sous-titre sur la timeline pour le modifier.",
|
||||
"enabled": "Afficher",
|
||||
"timelineQuickAdd": "Survoler pour ajouter sur la timeline",
|
||||
"language": "Langue",
|
||||
"downloading": "Téléchargement...",
|
||||
"deleteModel": "Supprimer le modèle",
|
||||
|
||||
@@ -142,6 +142,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "Seleziona un sottotitolo sulla timeline per modificarlo.",
|
||||
"enabled": "Mostra",
|
||||
"timelineQuickAdd": "Passa il mouse per aggiungere sulla timeline",
|
||||
"language": "Lingua",
|
||||
"downloading": "Download in corso...",
|
||||
"deleteModel": "Elimina modello",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "타임라인에서 자막을 선택하여 편집하세요.",
|
||||
"enabled": "표시",
|
||||
"timelineQuickAdd": "타임라인에 마우스를 올려 추가",
|
||||
"language": "언어",
|
||||
"downloading": "다운로드 중...",
|
||||
"deleteModel": "모델 삭제",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "Selecteer een ondertitel op de tijdlijn om deze te bewerken.",
|
||||
"enabled": "Tonen",
|
||||
"timelineQuickAdd": "Aanwijzen om toe te voegen op tijdlijn",
|
||||
"language": "Taal",
|
||||
"downloading": "Downloaden...",
|
||||
"deleteModel": "Model verwijderen",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "Selecione uma legenda na linha do tempo para editá-la.",
|
||||
"enabled": "Mostrar",
|
||||
"timelineQuickAdd": "Passe o cursor para adicionar na linha do tempo",
|
||||
"language": "Idioma",
|
||||
"downloading": "Baixando...",
|
||||
"deleteModel": "Excluir modelo",
|
||||
|
||||
@@ -142,6 +142,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "Выберите субтитры на таймлайне, чтобы отредактировать их.",
|
||||
"enabled": "Показать",
|
||||
"timelineQuickAdd": "Наведите курсор, чтобы добавить на таймлайн",
|
||||
"language": "Язык",
|
||||
"downloading": "Загрузка...",
|
||||
"deleteModel": "Удалить модель",
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "在时间轴上选择字幕进行编辑。",
|
||||
"enabled": "显示",
|
||||
"timelineQuickAdd": "悬停以在时间轴上添加",
|
||||
"language": "语言",
|
||||
"downloading": "下载中...",
|
||||
"deleteModel": "删除模型",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"captions": {
|
||||
"selectOnTimeline": "在時間軸上選擇字幕進行編輯。",
|
||||
"enabled": "顯示",
|
||||
"timelineQuickAdd": "懸停以在時間軸上新增",
|
||||
"language": "語言",
|
||||
"downloading": "下載中...",
|
||||
"deleteModel": "刪除模型",
|
||||
|
||||
Reference in New Issue
Block a user