diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx index 8b289e3f5..c3bfd4ea9 100644 --- a/src/components/video-editor/SettingsPanel.tsx +++ b/src/components/video-editor/SettingsPanel.tsx @@ -52,6 +52,7 @@ import type { AutoCaptionSettings, CaptionCue, CropRegion, + CursorClickEffectProfile, CursorClickEffectStyle, CursorStyle, EditorEffectSection, @@ -589,6 +590,8 @@ interface SettingsPanelProps { onZoomClassicModeChange?: (enabled: boolean) => void; cursorClickEffect?: CursorClickEffectStyle; onCursorClickEffectChange?: (effect: CursorClickEffectStyle) => void; + rightClickEffect?: CursorClickEffectProfile; + onRightClickEffectChange?: (profile?: CursorClickEffectProfile) => void; cursorClickEffectColor?: string; onCursorClickEffectColorChange?: (color: string) => void; cursorClickEffectScale?: number; @@ -1037,6 +1040,8 @@ export function SettingsPanel({ onZoomClassicModeChange, cursorClickEffect = DEFAULT_CURSOR_CLICK_EFFECT, onCursorClickEffectChange, + rightClickEffect, + onRightClickEffectChange, cursorClickEffectColor = DEFAULT_CURSOR_CLICK_EFFECT_COLOR, onCursorClickEffectColorChange, cursorClickEffectScale = DEFAULT_CURSOR_CLICK_EFFECT_SCALE, @@ -1249,6 +1254,56 @@ export function SettingsPanel({ Partial> >({}); const [showCursorClickEffectAdvanced, setShowCursorClickEffectAdvanced] = useState(false); + const [clickEffectTarget, setClickEffectTarget] = useState<"left" | "right">("left"); + const activeClickEffect = + clickEffectTarget === "right" + ? (rightClickEffect?.effect ?? cursorClickEffect) + : cursorClickEffect; + const activeClickEffectColor = + clickEffectTarget === "right" + ? (rightClickEffect?.color ?? cursorClickEffectColor) + : cursorClickEffectColor; + const activeClickEffectScale = + clickEffectTarget === "right" + ? (rightClickEffect?.scale ?? cursorClickEffectScale) + : cursorClickEffectScale; + const rightClickFollowsLeft = !rightClickEffect; + const updateActiveClickEffect = (effect: CursorClickEffectStyle) => { + if (clickEffectTarget === "left") { + onCursorClickEffectChange?.(effect); + return; + } + + onRightClickEffectChange?.({ + effect, + color: activeClickEffectColor, + scale: activeClickEffectScale, + }); + }; + const updateActiveClickEffectColor = (color: string) => { + if (clickEffectTarget === "left") { + onCursorClickEffectColorChange?.(color); + return; + } + + onRightClickEffectChange?.({ + effect: activeClickEffect, + color, + scale: activeClickEffectScale, + }); + }; + const updateActiveClickEffectScale = (scale: number) => { + if (clickEffectTarget === "left") { + onCursorClickEffectScaleChange?.(scale); + return; + } + + onRightClickEffectChange?.({ + effect: activeClickEffect, + color: activeClickEffectColor, + scale, + }); + }; const cursorPreviewUrls = builtInCursorPreviewUrls; const showDevMotionControls = import.meta.env.DEV; const cursorStyleOptions = BUILTIN_CURSOR_STYLE_OPTIONS; @@ -1579,6 +1634,7 @@ export function SettingsPanel({ onCursorSpringMassMultiplierChange?.(initialEditorPreferences.cursorSpringMassMultiplier); onCursorClickEffectChange?.(initialEditorPreferences.cursorClickEffect); onCursorClickEffectColorChange?.(initialEditorPreferences.cursorClickEffectColor); + onRightClickEffectChange?.(initialEditorPreferences.rightClickEffect); onCursorClickEffectScaleChange?.(initialEditorPreferences.cursorClickEffectScale); onCursorClickEffectOpacityChange?.(initialEditorPreferences.cursorClickEffectOpacity); onCursorClickEffectDurationMsChange?.(initialEditorPreferences.cursorClickEffectDurationMs); @@ -3311,14 +3367,85 @@ export function SettingsPanel({ formatValue={(v) => `${v.toFixed(2)}×`} parseInput={(text) => parseFloat(text.replace(/×$/, ""))} /> +
+
+ {tSettings("effects.cursorClickEffects.target", "Click button")} +
+ { + if (value === "left" || value === "right") { + setClickEffectTarget(value); + } + }} + className="grid grid-cols-2 gap-1 rounded-lg bg-foreground/[0.04] p-1" + aria-label={tSettings( + "effects.cursorClickEffects.target", + "Click button", + )} + > + + {tSettings("effects.cursorClickEffects.left", "Left click")} + + + {tSettings( + "effects.cursorClickEffects.right", + "Right click", + )} + + + {clickEffectTarget === "right" ? ( +
+
+
+ {tSettings( + "effects.cursorClickEffects.followLeft", + "Follow left click", + )} +
+
+ {tSettings( + "effects.cursorClickEffects.followLeftDescription", + "Use the left-click effect until you customize this profile.", + )} +
+
+ { + onRightClickEffectChange?.( + checked + ? undefined + : { + effect: cursorClickEffect, + color: cursorClickEffectColor, + scale: cursorClickEffectScale, + }, + ); + }} + aria-label={tSettings( + "effects.cursorClickEffects.followLeft", + "Follow left click", + )} + /> +
+ ) : null} +
onCursorClickEffectChange?.(effectId)} + activeEffectId={activeClickEffect} + effectColor={activeClickEffectColor} + onApply={updateActiveClickEffect} showAdvanced={showCursorClickEffectAdvanced} onToggleAdvanced={() => setShowCursorClickEffectAdvanced((current) => !current) @@ -3330,9 +3457,9 @@ export function SettingsPanel({ - onCursorClickEffectColorChange?.(event.target.value) + updateActiveClickEffectColor(event.target.value) } className="sr-only" /> @@ -3346,14 +3473,14 @@ export function SettingsPanel({
{CLICK_EFFECT_COLOR_OPTIONS.map((color) => { const isSelected = - cursorClickEffectColor.toLowerCase() === + activeClickEffectColor.toLowerCase() === color.toLowerCase(); return (