mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-25 15:25:44 +00:00
feat(editor): add audio region volume control
Expose the existing added-audio volume field in the selected-audio settings panel and keep timeline row hit targets selectable.
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
} from "@/components/ui/select";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||
import { useTheme } from "@/contexts/ThemeContext";
|
||||
import { getAssetPath, getRenderableAssetUrl, getWallpaperThumbnailUrl } from "@/lib/assetPath";
|
||||
import type { ExtensionSettingField } from "@/lib/extensions";
|
||||
import { extensionHost, type FrameInstance } from "@/lib/extensions";
|
||||
@@ -27,7 +28,6 @@ import minimalCursorUrl from "../../../Minimal Cursor.svg";
|
||||
import { useI18n, useScopedT } from "../../contexts/I18nContext";
|
||||
import type { AppLocale } from "../../i18n/config";
|
||||
import { SUPPORTED_LOCALES } from "../../i18n/config";
|
||||
import { useTheme } from "@/contexts/ThemeContext";
|
||||
import { AnnotationSettingsPanel } from "./AnnotationSettingsPanel";
|
||||
import { loadEditorPreferences, saveEditorPreferences } from "./editorPreferences";
|
||||
import { SliderControl } from "./SliderControl";
|
||||
@@ -50,9 +50,6 @@ import type {
|
||||
ZoomMode,
|
||||
ZoomTransitionEasing,
|
||||
} from "./types";
|
||||
import {
|
||||
isZeroPadding,
|
||||
} from "./videoPlayback/layoutUtils";
|
||||
import {
|
||||
DEFAULT_AUTO_CAPTION_SETTINGS,
|
||||
DEFAULT_CROP_REGION,
|
||||
@@ -76,6 +73,7 @@ import {
|
||||
SPEED_OPTIONS,
|
||||
} from "./types";
|
||||
import { fromCursorSwaySliderValue, toCursorSwaySliderValue } from "./videoPlayback/cursorSway";
|
||||
import { isZeroPadding } from "./videoPlayback/layoutUtils";
|
||||
import {
|
||||
cursorSetAssets,
|
||||
getCursorStyleSizeMultiplier,
|
||||
@@ -348,6 +346,10 @@ interface SettingsPanelProps {
|
||||
onClipSpeedChange?: (speed: number) => void;
|
||||
onClipMutedChange?: (muted: boolean) => void;
|
||||
onClipDelete?: (id: string) => void;
|
||||
selectedAudioId?: string | null;
|
||||
selectedAudioVolume?: number | null;
|
||||
onAudioVolumeChange?: (volume: number) => void;
|
||||
onAudioDelete?: (id: string) => void;
|
||||
shadowIntensity?: number;
|
||||
onShadowChange?: (intensity: number) => void;
|
||||
backgroundBlur?: number;
|
||||
@@ -721,6 +723,10 @@ export function SettingsPanel({
|
||||
onClipSpeedChange,
|
||||
onClipMutedChange,
|
||||
onClipDelete,
|
||||
selectedAudioId,
|
||||
selectedAudioVolume,
|
||||
onAudioVolumeChange,
|
||||
onAudioDelete,
|
||||
shadowIntensity = 0.67,
|
||||
onShadowChange,
|
||||
backgroundBlur = 0,
|
||||
@@ -3031,7 +3037,7 @@ export function SettingsPanel({
|
||||
<div
|
||||
className={cn(
|
||||
"flex-shrink-0 border-t border-foreground/10 bg-editor-header p-4 pt-3",
|
||||
!selectedTrimId && !selectedSpeedId && "hidden",
|
||||
!selectedTrimId && !selectedSpeedId && !selectedAudioId && "hidden",
|
||||
)}
|
||||
>
|
||||
{selectedTrimId && (
|
||||
@@ -3094,6 +3100,39 @@ export function SettingsPanel({
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedAudioId && (
|
||||
<div>
|
||||
<div className="mb-3 flex items-center justify-between">
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
{tSettings("audio.volumeTitle", "Audio Volume")}
|
||||
</span>
|
||||
<span className="rounded-full bg-[#2563EB]/10 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wider text-[#2563EB]">
|
||||
{Math.round((selectedAudioVolume ?? 1) * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
<SliderControl
|
||||
label={tSettings("audio.volume", "Volume")}
|
||||
value={selectedAudioVolume ?? 1}
|
||||
defaultValue={1}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
onChange={(v) => onAudioVolumeChange?.(v)}
|
||||
formatValue={(v) => `${Math.round(v * 100)}%`}
|
||||
parseInput={(text) => parseFloat(text.replace(/%$/, "")) / 100}
|
||||
/>
|
||||
<Button
|
||||
onClick={() => selectedAudioId && onAudioDelete?.(selectedAudioId)}
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
className="mt-2 h-8 w-full gap-2 border border-red-500/20 bg-red-500/10 text-xs text-red-400 transition-all hover:border-red-500/30 hover:bg-red-500/20"
|
||||
>
|
||||
<Trash2 className="h-3 w-3" />
|
||||
{tSettings("audio.deleteRegion", "Delete Audio")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3257,6 +3257,23 @@ export default function VideoEditor() {
|
||||
);
|
||||
}, []);
|
||||
|
||||
const handleAudioVolumeChange = useCallback((volume: number) => {
|
||||
if (!selectedAudioId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Number.isFinite(volume)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextVolume = Math.max(0, Math.min(1, volume));
|
||||
setAudioRegions((prev) =>
|
||||
prev.map((region) =>
|
||||
region.id === selectedAudioId ? { ...region, volume: nextVolume } : region,
|
||||
),
|
||||
);
|
||||
}, [selectedAudioId]);
|
||||
|
||||
const handleAudioDelete = useCallback(
|
||||
(id: string) => {
|
||||
setAudioRegions((prev) => prev.filter((region) => region.id !== id));
|
||||
@@ -4396,6 +4413,8 @@ export default function VideoEditor() {
|
||||
effectiveSpeedRegions,
|
||||
frame,
|
||||
smokeExportConfig.encodingMode,
|
||||
smokeExportConfig.fps,
|
||||
smokeExportConfig.quality,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -5188,6 +5207,15 @@ export default function VideoEditor() {
|
||||
selectedClipId && handleClipMutedChange(muted)
|
||||
}
|
||||
onClipDelete={handleClipDelete}
|
||||
selectedAudioId={selectedAudioId}
|
||||
selectedAudioVolume={
|
||||
selectedAudioId
|
||||
? (audioRegions.find((r) => r.id === selectedAudioId)
|
||||
?.volume ?? null)
|
||||
: null
|
||||
}
|
||||
onAudioVolumeChange={handleAudioVolumeChange}
|
||||
onAudioDelete={handleAudioDelete}
|
||||
shadowIntensity={shadowIntensity}
|
||||
onShadowChange={setShadowIntensity}
|
||||
backgroundBlur={backgroundBlur}
|
||||
|
||||
@@ -30,7 +30,11 @@ export default function Row({ id, children, label, hint, isEmpty, labelColor = "
|
||||
<span className="text-[11px] text-foreground/15 font-medium">{hint}</span>
|
||||
</div>
|
||||
)}
|
||||
<div ref={setNodeRef} className="relative h-full min-h-0 overflow-hidden" style={rowStyle}>
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
className="relative h-full min-h-[26px] overflow-hidden"
|
||||
style={rowStyle}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user