P4: Production hardening — reconnect, auto-scene-load, service cleanup
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* FxInsertSlot — a single FX insert on a channel strip.
|
||||
*
|
||||
* Shows:
|
||||
* - Plugin name
|
||||
* - Bypass toggle button
|
||||
* - Wet/dry mix slider
|
||||
* - Remove button
|
||||
*/
|
||||
import React, { useCallback } from 'react';
|
||||
import type { FxInsert } from '../../hooks/useFxInserts';
|
||||
import './FxInsertPanel.css';
|
||||
|
||||
interface FxInsertSlotProps {
|
||||
insert: FxInsert;
|
||||
accentColor: string;
|
||||
onToggleBypass: (id: string, currentBypassed: boolean) => void;
|
||||
onWetDryChange: (id: string, wetDry: number) => void;
|
||||
onRemove: (id: string) => void;
|
||||
}
|
||||
|
||||
const FxInsertSlot: React.FC<FxInsertSlotProps> = ({
|
||||
insert,
|
||||
accentColor,
|
||||
onToggleBypass,
|
||||
onWetDryChange,
|
||||
onRemove,
|
||||
}) => {
|
||||
const handleBypass = useCallback(() => {
|
||||
onToggleBypass(insert.id, insert.bypassed);
|
||||
}, [insert.id, insert.bypassed, onToggleBypass]);
|
||||
|
||||
const handleWetDry = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
onWetDryChange(insert.id, parseFloat(e.target.value));
|
||||
},
|
||||
[insert.id, onWetDryChange],
|
||||
);
|
||||
|
||||
const handleRemove = useCallback(() => {
|
||||
onRemove(insert.id);
|
||||
}, [insert.id, onRemove]);
|
||||
|
||||
const wetDryPercent = Math.round(insert.wet_dry_mix * 100);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`fx-insert-slot ${insert.bypassed ? 'bypassed' : ''}`}
|
||||
style={
|
||||
{
|
||||
'--fx-accent': accentColor,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
{/* Header: plugin name + bypass + remove */}
|
||||
<div className="fx-insert-header">
|
||||
<span
|
||||
className={`fx-insert-bypass-btn ${insert.bypassed ? 'active' : ''}`}
|
||||
onClick={handleBypass}
|
||||
title={insert.bypassed ? 'Enable insert' : 'Bypass insert'}
|
||||
>
|
||||
{insert.bypassed ? 'OFF' : 'ON'}
|
||||
</span>
|
||||
<span className="fx-insert-name" title={insert.plugin_name}>
|
||||
{insert.plugin_name}
|
||||
</span>
|
||||
<button
|
||||
className="fx-insert-remove"
|
||||
onClick={handleRemove}
|
||||
title="Remove insert"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Wet/dry mix slider */}
|
||||
{!insert.bypassed && (
|
||||
<div className="fx-insert-wetdry">
|
||||
<label className="fx-insert-wetdry-label">Mix</label>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
value={insert.wet_dry_mix}
|
||||
onChange={handleWetDry}
|
||||
className="fx-insert-wetdry-slider"
|
||||
title={`Wet/Dry: ${wetDryPercent}%`}
|
||||
/>
|
||||
<span className="fx-insert-wetdry-readout">{wetDryPercent}%</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { FxInsertSlot };
|
||||
export default FxInsertSlot;
|
||||
Reference in New Issue
Block a user