diff --git a/app/static/js/app.jsx b/app/static/js/app.jsx index 6ba25b8..239a886 100644 --- a/app/static/js/app.jsx +++ b/app/static/js/app.jsx @@ -9311,6 +9311,7 @@ const MediaExplorerPanel = ({ height, clipboardRef }) => { return saved ? JSON.parse(saved) : null; }()); const [synthOpen, setSynthOpen] = React.useState(false); + const [synthFilter, setSynthFilter] = React.useState(''); const [synthList, setSynthList] = React.useState(null); const [synthLoading, setSynthLoading] = React.useState(false); const synthListRef = React.useRef(null); @@ -9840,6 +9841,7 @@ const MediaExplorerPanel = ({ height, clipboardRef }) => { const toggleSynthDropdown = () => { if (synthOpen) { setSynthOpen(false); return; } + setSynthFilter(''); // Clear search filter on open setSynthOpen(true); if (synthListRef.current) return; setSynthLoading(true); @@ -9874,6 +9876,19 @@ const MediaExplorerPanel = ({ height, clipboardRef }) => { } }; + const filteredSynthList = React.useMemo(() => { + if (!synthList) return []; + if (!synthFilter.trim()) return synthList; + const query = synthFilter.toLowerCase().trim(); + return synthList.map(group => { + const presets = (group.presets || []).filter(p => + (p.name || '').toLowerCase().includes(query) || + String(p.program).includes(query) + ); + return { ...group, presets }; + }).filter(group => group.presets.length > 0); + }, [synthList, synthFilter]); + const playMidiPreview = async (f, token) => { // Play real MIDI file through selected synth instrument (SonicSF) if (!f || !window.SonicSF) return; @@ -10451,10 +10466,30 @@ const MediaExplorerPanel = ({ height, clipboardRef }) => { {synthOpen && (