feat: Synth button shows track dropdown for quick instrument assign

Synth button opens a dropdown listing all tracks instead of opening
the modal directly. Selecting a track opens the instrument selector
for that track. No need to close modal and click each track's Synth.
This commit is contained in:
2026-07-29 11:49:34 +07:00
parent 30ce0eb306
commit 7bfdd72850
3 changed files with 32 additions and 5 deletions
+23 -2
View File
@@ -6778,6 +6778,19 @@ const App = () => {
if (id === 'export') setShowExportPanel(true); else if (id === 'ai') setShowAIPanel(true); else if (id === 'python_tools') setShowPythonToolsPanel(true); else if (id === 'selection') setShowSelectionPanel(true);
};
const [instrumentSelectorTrackId, setInstrumentSelectorTrackId] = useState(null);
const [synthTrackDropdownId, setSynthTrackDropdownId] = useState(null);
const [synthBtnRect, setSynthBtnRect] = useState(null);
const synthDropdownRef = useRef(null);
useEffect(function() {
var handler = function(e) {
if (synthDropdownRef.current && !synthDropdownRef.current.contains(e.target)) {
setSynthTrackDropdownId(null);
setSynthBtnRect(null);
}
};
document.addEventListener('mousedown', handler);
return function() { document.removeEventListener('mousedown', handler); };
}, []);
const [fxSelectorTrackId, setFxSelectorTrackId] = useState(null);
const handleSetTrackFx = (trackId, fxType) => {
updateActiveTracks(prev => prev.map(t => t.id === trackId ? { ...t, fxType } : t));
@@ -17047,7 +17060,7 @@ const App = () => {
})), " FX: ", /*#__PURE__*/React.createElement("span", {
className: "text-zinc-500 font-normal"
}, track.fxType || "None")), /*#__PURE__*/React.createElement("button", {
onClick: (e) => { e.stopPropagation(); openInstrumentSelector(track.id); },
onClick: (e) => { e.stopPropagation(); var r = e.currentTarget.getBoundingClientRect(); setSynthBtnRect({ top: r.bottom + 4, left: r.left }); setSynthTrackDropdownId(synthTrackDropdownId === track.id ? null : track.id); },
className: "px-2.5 py-1 bg-zinc-800 hover:bg-zinc-700 text-amber-400 border border-amber-800 rounded text-xs font-bold flex items-center gap-1 max-w-[120px]"
}, /*#__PURE__*/React.createElement("span", {
className: "inline-flex items-center shrink-0"
@@ -18329,7 +18342,15 @@ const App = () => {
}), /*#__PURE__*/React.createElement(AIPresetModal, {
isOpen: aiPresetModalOpen,
onClose: () => { setAiPresetModalOpen(false); setAiPresetVersion(v => v + 1); }
}), instrumentSelectorTrackId && /*#__PURE__*/React.createElement("div", {
}), synthTrackDropdownId && synthBtnRect && /*#__PURE__*/React.createElement("div", {
ref: synthDropdownRef,
className: "fixed z-[100] bg-[#1e1e1e] border border-zinc-700 rounded shadow-xl w-[200px] max-h-[260px] overflow-y-auto py-1",
style: { top: synthBtnRect.top + 'px', left: synthBtnRect.left + 'px' }
}, activeTracks.map(function(at) { return /*#__PURE__*/React.createElement("button", {
key: at.id,
onClick: function(ev) { ev.stopPropagation(); setSynthTrackDropdownId(null); setSynthBtnRect(null); openInstrumentSelector(at.id); },
className: "w-full text-left px-3 py-1.5 text-xs hover:bg-zinc-700 flex items-center gap-2 border-b border-zinc-800 last:border-0"
}, /*#__PURE__*/React.createElement("span", { className: "text-[9px] text-zinc-500 font-mono shrink-0 w-16 truncate" }, at.name), /*#__PURE__*/React.createElement("span", { className: "truncate text-zinc-400" }, at.instrumentName || 'No Synth')); })), instrumentSelectorTrackId && /*#__PURE__*/React.createElement("div", {
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm",
onClick: closeInstrumentSelector
}, /*#__PURE__*/React.createElement("div", {