feat: instrument selector modal 2-column layout
Modal max-w-md -> max-w-4xl. Font 14px (text-sm). Left column: soundfont list. Right column: instruments of selected SF. All Instruments view when none selected. Search filters both columns.
This commit is contained in:
+43
-25
@@ -17683,7 +17683,7 @@ const App = () => {
|
||||
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm",
|
||||
onClick: closeInstrumentSelector
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "bg-[#262626] border border-[#383838] rounded-xl shadow-2xl w-full max-w-md p-5 text-slate-200",
|
||||
className: "bg-[#262626] border border-[#383838] rounded-xl shadow-2xl w-full max-w-4xl p-5 text-slate-200",
|
||||
onClick: e => e.stopPropagation()
|
||||
},
|
||||
/*#__PURE__*/React.createElement("div", { className: "flex justify-between items-center pb-3 border-b border-[#383838]" },
|
||||
@@ -17696,34 +17696,52 @@ const App = () => {
|
||||
value: sfPresetSearchQuery,
|
||||
onChange: e => setSfPresetSearchQuery(e.target.value),
|
||||
autoFocus: true,
|
||||
className: "w-full bg-black border border-zinc-700 rounded px-2 py-1.5 text-xs outline-none my-3"
|
||||
className: "w-full bg-black border border-zinc-700 rounded px-2 py-1.5 outline-none my-3 text-sm"
|
||||
}),
|
||||
/*#__PURE__*/React.createElement("div", { className: "max-h-72 overflow-y-auto space-y-0.5" },
|
||||
/*#__PURE__*/React.createElement("button", {
|
||||
onClick: () => setTrackInstrumentWithProgram(instrumentSelectorTrackId, null),
|
||||
className: "w-full text-left px-3 py-1.5 text-xs rounded bg-zinc-800 hover:bg-zinc-700 text-zinc-400 mb-1"
|
||||
}, "None (Default Synth)"),(
|
||||
sfPresets === null ? (
|
||||
/*#__PURE__*/React.createElement("p", { className: "text-[10px] text-zinc-500 py-2" }, "Loading instruments...")
|
||||
) : sfPresets.length > 0 ? (
|
||||
/*#__PURE__*/React.createElement("div", { className: "space-y-0.5" },
|
||||
sfPresets
|
||||
.filter(p => !sfPresetSearchQuery || (p.name || '').toLowerCase().includes(sfPresetSearchQuery.toLowerCase()) || (p._sfName || '').toLowerCase().includes(sfPresetSearchQuery.toLowerCase()))
|
||||
.map((p, i) => /*#__PURE__*/React.createElement("button", {
|
||||
key: i,
|
||||
onClick: () => setTrackInstrumentWithProgram(instrumentSelectorTrackId, p._sfId, p.program, p.name || 'Preset ' + p.program, p.bank),
|
||||
className: "w-full text-left px-2 py-1 text-[10px] rounded bg-zinc-800/60 hover:bg-amber-800 text-zinc-300 truncate flex items-center gap-2"
|
||||
},
|
||||
/*#__PURE__*/React.createElement("span", { className: "text-[9px] text-zinc-500 shrink-0" }, p._sfDisplay),
|
||||
p.bank === 128 ? /*#__PURE__*/React.createElement("span", { className: "mr-1" }, "🥁") : null,
|
||||
p.name || 'Preset ' + p.program
|
||||
))
|
||||
/*#__PURE__*/React.createElement("div", { className: "flex gap-4", style: { height: "420px" } },
|
||||
/*#__PURE__*/React.createElement("div", { className: "w-1/3 border-r border-[#383838] overflow-y-auto space-y-0.5 pr-2" },
|
||||
/*#__PURE__*/React.createElement("button", {
|
||||
onClick: () => { setSelectedSoundFontId(null); setSynthCategory(null); },
|
||||
className: "w-full text-left px-3 py-2 text-sm rounded " + (!selectedSoundFontId ? "bg-amber-700 text-white" : "bg-zinc-800 hover:bg-zinc-700 text-zinc-300")
|
||||
}, "All Instruments"),
|
||||
sfPresets === null ? (
|
||||
/*#__PURE__*/React.createElement("p", { className: "text-sm text-zinc-500 py-2" }, "Loading...")
|
||||
) : (
|
||||
[...new Map(sfPresets.map(p => [p._sfId, p])).values()].map(sf => /*#__PURE__*/React.createElement("button", {
|
||||
key: sf._sfId,
|
||||
onClick: () => setSelectedSoundFontId(sf._sfId),
|
||||
className: "w-full text-left px-3 py-2 text-sm rounded " + (selectedSoundFontId === sf._sfId ? "bg-amber-700 text-white" : "bg-zinc-800 hover:bg-zinc-700 text-zinc-300")
|
||||
}, sf._sfName))
|
||||
)
|
||||
),
|
||||
/*#__PURE__*/React.createElement("div", { className: "flex-1 overflow-y-auto space-y-0.5" },
|
||||
/*#__PURE__*/React.createElement("button", {
|
||||
onClick: () => setTrackInstrumentWithProgram(instrumentSelectorTrackId, null),
|
||||
className: "w-full text-left px-3 py-2 text-sm rounded bg-zinc-800 hover:bg-zinc-700 text-zinc-400"
|
||||
}, "None (Default Synth)"),
|
||||
sfPresets === null ? (
|
||||
/*#__PURE__*/React.createElement("p", { className: "text-sm text-zinc-500 py-2" }, "Loading instruments...")
|
||||
) : (
|
||||
sfPresets.length > 0 ? (
|
||||
sfPresets
|
||||
.filter(p => !selectedSoundFontId || p._sfId === selectedSoundFontId)
|
||||
.filter(p => !sfPresetSearchQuery || (p.name || '').toLowerCase().includes(sfPresetSearchQuery.toLowerCase()) || (p._sfName || '').toLowerCase().includes(sfPresetSearchQuery.toLowerCase()))
|
||||
.map((p, i) => /*#__PURE__*/React.createElement("button", {
|
||||
key: i,
|
||||
onClick: () => setTrackInstrumentWithProgram(instrumentSelectorTrackId, p._sfId, p.program, p.name || 'Preset ' + p.program, p.bank),
|
||||
className: "w-full text-left px-3 py-2 text-sm rounded bg-zinc-800/60 hover:bg-amber-800 text-zinc-300 truncate flex items-center gap-2"
|
||||
},
|
||||
/*#__PURE__*/React.createElement("span", { className: "text-xs text-zinc-500 shrink-0" }, p._sfDisplay),
|
||||
p.bank === 128 ? /*#__PURE__*/React.createElement("span", { className: "mr-1" }, "🥁") : null,
|
||||
p.name || 'Preset ' + p.program
|
||||
))
|
||||
) : (
|
||||
/*#__PURE__*/React.createElement("p", { className: "text-sm text-zinc-500 py-2" }, sfPresetSearchQuery ? "Kh\u00f4ng t\u00ecm th\u1ea5y nh\u1ea1c c\u1ee5 ph\u00f9 h\u1ee3p." : "No presets found.")
|
||||
)
|
||||
)
|
||||
) : (
|
||||
/*#__PURE__*/React.createElement("p", { className: "text-[10px] text-zinc-500 py-2" }, sfPresetSearchQuery ? "Kh\u00f4ng t\u00ecm th\u1ea5y nh\u1ea1c c\u1ee5 ph\u00f9 h\u1ee3p." : "No presets found.")
|
||||
)
|
||||
)
|
||||
))), fxSelectorTrackId && /*#__PURE__*/React.createElement("div", {
|
||||
)), fxSelectorTrackId && /*#__PURE__*/React.createElement("div", {
|
||||
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm",
|
||||
onClick: () => setFxSelectorTrackId(null)
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,9 @@
|
||||
### [2026-07-28 07:13] Task: Instrument selector modal — 2 cột + font 14px
|
||||
- **Tóm tắt thay đổi:** Mở rộng modal `max-w-md` → `max-w-4xl`. Font size từ `text-[10px]`/`text-xs` → `text-sm` (14px). Bố cục 2 cột: trái danh sách soundfont, phải instruments của SF đang chọn. Click SF trái → lọc instrument phải. Nút "All Instruments" để xem tất cả. Search filter cả 2 cột.
|
||||
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js`
|
||||
- **Ghi chú/Test (nếu có):** `npm run build` — build passes. Synth button → modal 2 cột → chọn SF trái → instrument phải.
|
||||
---
|
||||
|
||||
### [2026-07-26 18:05] Task: Fix SpessaSynth CDN 404 + AudioWorklet init
|
||||
- **Tóm tắt thay đổi:** Sửa CDN URL từ `@latest/dist/spessasynth_lib.js` (404) → `@4.3.1/dist/index.js` (200). Dùng `WorkletSynthesizer` class + `audioWorklet.addModule(processor.min.js)`, `soundBankManager.addSoundBank()`, `await isReady`. Fallback WorkerSynthesizer nếu AudioWorklet không khả dụng.
|
||||
- **Các file ảnh hưởng:** `app/templates/index.html`, `app/static/js/services/soundfontPlayer.js`, `app/static/js/app.precompiled.js`
|
||||
|
||||
Reference in New Issue
Block a user