fix: cho phép chỉnh sửa MIDI ở main session và section tab
This commit is contained in:
+140
-25
@@ -105,6 +105,7 @@ class ClientMIDIRecorder {
|
|||||||
this.bpm = bpm;
|
this.bpm = bpm;
|
||||||
this.timeSigNum = timeSigNumerator;
|
this.timeSigNum = timeSigNumerator;
|
||||||
this.isRecording = false;
|
this.isRecording = false;
|
||||||
|
this.tempMidiItemId = null;
|
||||||
|
|
||||||
this.activeNotes = new Map(); // Store pitch -> { noteId, startBeat, velocity }
|
this.activeNotes = new Map(); // Store pitch -> { noteId, startBeat, velocity }
|
||||||
this.recordedNotes = [];
|
this.recordedNotes = [];
|
||||||
@@ -708,6 +709,27 @@ const WaveformLane = ({
|
|||||||
ctx.fillStyle = '#c4b5fd';
|
ctx.fillStyle = '#c4b5fd';
|
||||||
ctx.font = 'bold 9px sans-serif';
|
ctx.font = 'bold 9px sans-serif';
|
||||||
ctx.fillText(midi.name || 'MIDI', Math.max(midiStartLocal + 4, 4), 14);
|
ctx.fillText(midi.name || 'MIDI', Math.max(midiStartLocal + 4, 4), 14);
|
||||||
|
|
||||||
|
const midiNotes = midi.notes || [];
|
||||||
|
if (midiNotes.length > 0) {
|
||||||
|
const secondsPerBeat = 60.0 / (parseInt(bpm) || 120);
|
||||||
|
const pitchMin = 36;
|
||||||
|
const pitchMax = 84;
|
||||||
|
midiNotes.forEach(note => {
|
||||||
|
const noteStartSec = (note.start_beat || 0) * secondsPerBeat;
|
||||||
|
const noteDurSec = Math.max(0.02, (note.duration_beats || 0.25) * secondsPerBeat);
|
||||||
|
const noteStartLocal = (midi.startTime + noteStartSec) * zoom - scrollLeft;
|
||||||
|
const nw = noteDurSec * zoom;
|
||||||
|
if (noteStartLocal + nw < midiStartLocal || noteStartLocal > midiStartLocal + midiWidth) return;
|
||||||
|
|
||||||
|
const pitchFrac = Math.max(0, Math.min(1, (note.pitch - pitchMin) / (pitchMax - pitchMin)));
|
||||||
|
const ny = 18 + (1.0 - pitchFrac) * (height - 26);
|
||||||
|
const nh = Math.max(2, (height - 26) / (pitchMax - pitchMin) * 1.5);
|
||||||
|
|
||||||
|
ctx.fillStyle = '#a78bfa';
|
||||||
|
ctx.fillRect(Math.max(noteStartLocal, midiStartLocal + 2), ny, Math.max(2, nw), nh);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (recordingState === 'RECORDING' && track.isArmed && track.inputSource?.deviceType === 'MIDI_KEYBOARD') {
|
if (recordingState === 'RECORDING' && track.isArmed && track.inputSource?.deviceType === 'MIDI_KEYBOARD') {
|
||||||
@@ -755,7 +777,7 @@ const WaveformLane = ({
|
|||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
ctx.strokeRect(hlLeftLocal, 0, hlWidth, height);
|
ctx.strokeRect(hlLeftLocal, 0, hlWidth, height);
|
||||||
}
|
}
|
||||||
}, [track, zoom, timelineWidth, viewportWidth, isSelected, markers, selectionMode, localSelectionTrackId, localSelLeft, localSelRight, snapValue, bpm, scrollLeft]);
|
}, [track, zoom, timelineWidth, viewportWidth, isSelected, markers, selectionMode, localSelectionTrackId, localSelLeft, localSelRight, snapValue, bpm, scrollLeft, recordingState, recTempMidiNotes, recStartTimelineTime]);
|
||||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
||||||
key: "virtual-spacer",
|
key: "virtual-spacer",
|
||||||
style: {
|
style: {
|
||||||
@@ -7589,6 +7611,22 @@ const App = () => {
|
|||||||
for (let track of armedTracks) {
|
for (let track of armedTracks) {
|
||||||
if (track.inputSource.deviceType === 'MIDI_KEYBOARD') {
|
if (track.inputSource.deviceType === 'MIDI_KEYBOARD') {
|
||||||
const midiRec = new ClientMIDIRecorder(context, parseInt(bpm) || 120, 4);
|
const midiRec = new ClientMIDIRecorder(context, parseInt(bpm) || 120, 4);
|
||||||
|
const tempMidiItemId = 'midi_rec_' + Date.now() + '_' + track.id;
|
||||||
|
midiRec.tempMidiItemId = tempMidiItemId;
|
||||||
|
|
||||||
|
updateActiveTracks(prev => prev.map(t => {
|
||||||
|
if (t.id !== track.id) return t;
|
||||||
|
return {
|
||||||
|
...t,
|
||||||
|
midiItems: [...(t.midiItems || []), {
|
||||||
|
id: tempMidiItemId,
|
||||||
|
name: 'Recording...',
|
||||||
|
startTime: startTimelineTime,
|
||||||
|
duration: 4,
|
||||||
|
notes: []
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
midiRec.onNoteOn = (pitch, currentBeat) => {
|
midiRec.onNoteOn = (pitch, currentBeat) => {
|
||||||
const canvas = trackVuRefs.current[track.id];
|
const canvas = trackVuRefs.current[track.id];
|
||||||
@@ -7596,18 +7634,45 @@ const App = () => {
|
|||||||
drawVuMeter(canvas, 0);
|
drawVuMeter(canvas, 0);
|
||||||
setTimeout(() => drawVuMeter(canvas, -60), 100);
|
setTimeout(() => drawVuMeter(canvas, -60), 100);
|
||||||
}
|
}
|
||||||
setRecTempMidiNotes([...midiRec.recordedNotes, ...Array.from(midiRec.activeNotes.values()).map(n => ({
|
const allNotes = [...midiRec.recordedNotes, ...Array.from(midiRec.activeNotes.values()).map(n => ({
|
||||||
...n,
|
...n,
|
||||||
duration_beats: currentBeat - n.start_beat
|
duration_beats: currentBeat - n.start_beat
|
||||||
}))]);
|
}))];
|
||||||
|
setRecTempMidiNotes(allNotes);
|
||||||
|
if (midiRec.tempMidiItemId) {
|
||||||
|
updateActiveTracks(prev => prev.map(t => {
|
||||||
|
if (t.id !== track.id) return t;
|
||||||
|
return {
|
||||||
|
...t,
|
||||||
|
midiItems: t.midiItems.map(m => m.id === midiRec.tempMidiItemId ? {
|
||||||
|
...m,
|
||||||
|
notes: allNotes
|
||||||
|
} : m)
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
midiRec.onNoteOff = () => {
|
midiRec.onNoteOff = () => {
|
||||||
const currentBeat = (context.currentTime - midiRec.recStartAudioTime - midiRec.latencyCompSec) / (60.0 / midiRec.bpm) + (midiRec.recStartBar * 4);
|
const currentBeat = (context.currentTime - midiRec.recStartAudioTime - midiRec.latencyCompSec) / (60.0 / midiRec.bpm) + (midiRec.recStartBar * 4);
|
||||||
setRecTempMidiNotes([...midiRec.recordedNotes, ...Array.from(midiRec.activeNotes.values()).map(n => ({
|
const activeNotesArray = Array.from(midiRec.activeNotes.values()).map(n => ({
|
||||||
...n,
|
...n,
|
||||||
duration_beats: currentBeat - n.start_beat
|
duration_beats: currentBeat - n.start_beat
|
||||||
}))]);
|
}));
|
||||||
|
const allNotes = [...midiRec.recordedNotes, ...activeNotesArray];
|
||||||
|
setRecTempMidiNotes(allNotes);
|
||||||
|
if (midiRec.tempMidiItemId) {
|
||||||
|
updateActiveTracks(prev => prev.map(t => {
|
||||||
|
if (t.id !== track.id) return t;
|
||||||
|
return {
|
||||||
|
...t,
|
||||||
|
midiItems: t.midiItems.map(m => m.id === midiRec.tempMidiItemId ? {
|
||||||
|
...m,
|
||||||
|
notes: allNotes
|
||||||
|
} : m)
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
midiRec.start(startTimelineTime / (secondsPerBeat * 4), track.inputSource.deviceId);
|
midiRec.start(startTimelineTime / (secondsPerBeat * 4), track.inputSource.deviceId);
|
||||||
@@ -7670,10 +7735,42 @@ const App = () => {
|
|||||||
for (let trackId in midiRecorders) {
|
for (let trackId in midiRecorders) {
|
||||||
const midiRec = midiRecorders[trackId];
|
const midiRec = midiRecorders[trackId];
|
||||||
const recordedNotes = midiRec.stop();
|
const recordedNotes = midiRec.stop();
|
||||||
if (recordedNotes.length > 0) {
|
|
||||||
|
if (midiRec.tempMidiItemId) {
|
||||||
|
const totalDurationBeats = recordedNotes.length > 0 ? Math.max(4.0, ...recordedNotes.map(n => n.start_beat + n.duration_beats)) : 4.0;
|
||||||
|
|
||||||
|
updateActiveTracks(prev => prev.map(t => {
|
||||||
|
if (t.id !== trackId) return t;
|
||||||
|
const itemIndex = (t.midiItems || []).findIndex(m => m.id === midiRec.tempMidiItemId);
|
||||||
|
if (itemIndex >= 0) {
|
||||||
|
const updatedItems = [...t.midiItems];
|
||||||
|
updatedItems[itemIndex] = {
|
||||||
|
...updatedItems[itemIndex],
|
||||||
|
name: recordedNotes.length > 0 ? 'Recorded MIDI' : 'Empty MIDI',
|
||||||
|
notes: recordedNotes,
|
||||||
|
duration: Math.ceil(totalDurationBeats / 4)
|
||||||
|
};
|
||||||
|
return { ...t, midiItems: updatedItems };
|
||||||
|
}
|
||||||
|
const newMidiItem = {
|
||||||
|
id: 'midi_rec_' + Date.now(),
|
||||||
|
name: 'Recorded MIDI',
|
||||||
|
startTime: recordingStartTimeRef.current,
|
||||||
|
duration: Math.ceil(totalDurationBeats / 4),
|
||||||
|
notes: recordedNotes
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
...t,
|
||||||
|
midiItems: [...(t.midiItems || []), newMidiItem]
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (recordedNotes.length > 0) {
|
||||||
|
hasRecordedAnything = true;
|
||||||
|
}
|
||||||
|
} else if (recordedNotes.length > 0) {
|
||||||
hasRecordedAnything = true;
|
hasRecordedAnything = true;
|
||||||
const totalDurationBeats = Math.max(4.0, ...recordedNotes.map(n => n.start_beat + n.duration_beats));
|
const totalDurationBeats = Math.max(4.0, ...recordedNotes.map(n => n.start_beat + n.duration_beats));
|
||||||
|
|
||||||
const newMidiItem = {
|
const newMidiItem = {
|
||||||
id: 'midi_rec_' + Date.now(),
|
id: 'midi_rec_' + Date.now(),
|
||||||
name: 'Recorded MIDI',
|
name: 'Recorded MIDI',
|
||||||
@@ -7681,7 +7778,6 @@ const App = () => {
|
|||||||
duration: Math.ceil(totalDurationBeats / 4),
|
duration: Math.ceil(totalDurationBeats / 4),
|
||||||
notes: recordedNotes
|
notes: recordedNotes
|
||||||
};
|
};
|
||||||
|
|
||||||
updateActiveTracks(prev => prev.map(t => {
|
updateActiveTracks(prev => prev.map(t => {
|
||||||
if (t.id !== trackId) return t;
|
if (t.id !== trackId) return t;
|
||||||
return {
|
return {
|
||||||
@@ -8008,7 +8104,7 @@ const App = () => {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const startY = e.clientY;
|
const startY = e.clientY;
|
||||||
const track = tracks.find(t => t.id === trackId);
|
const track = tracks.find(t => t.id === trackId);
|
||||||
const startHeight = track ? track.height || 96 : 96;
|
const startHeight = track ? track.height || 140 : 140;
|
||||||
const handleMouseMove = moveEvent => {
|
const handleMouseMove = moveEvent => {
|
||||||
const deltaY = moveEvent.clientY - startY;
|
const deltaY = moveEvent.clientY - startY;
|
||||||
const newHeight = Math.max(110, Math.min(300, startHeight + deltaY));
|
const newHeight = Math.max(110, Math.min(300, startHeight + deltaY));
|
||||||
@@ -8026,6 +8122,20 @@ const App = () => {
|
|||||||
};
|
};
|
||||||
const deleteTrack = trackId => {
|
const deleteTrack = trackId => {
|
||||||
const sessionTab = sessionTabs.find(s => s.id === activeTab);
|
const sessionTab = sessionTabs.find(s => s.id === activeTab);
|
||||||
|
const trackList = sessionTab ? sessionTab.tracks : tracks;
|
||||||
|
const track = trackList.find(t => t.id === trackId);
|
||||||
|
if (!track) return;
|
||||||
|
|
||||||
|
const hasClips = (track.clips && track.clips.length > 0) || !!track.buffer;
|
||||||
|
const hasMidi = track.midiItems && track.midiItems.length > 0;
|
||||||
|
const hasSections = track.sections && track.sections.length > 0;
|
||||||
|
const isTrackEmpty = !hasClips && !hasMidi && !hasSections;
|
||||||
|
|
||||||
|
if (!isTrackEmpty) {
|
||||||
|
showToast('Không thể xoá track chứa dữ liệu. Vui lòng xoá hết các item trước khi xoá track.', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (sessionTab) {
|
if (sessionTab) {
|
||||||
updateActiveTracks(prev => {
|
updateActiveTracks(prev => {
|
||||||
const filtered = prev.filter(t => t.id !== trackId);
|
const filtered = prev.filter(t => t.id !== trackId);
|
||||||
@@ -8033,11 +8143,6 @@ const App = () => {
|
|||||||
return filtered;
|
return filtered;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const track = tracks.find(t => t.id === trackId);
|
|
||||||
if (track && track.sections && track.sections.length > 0) {
|
|
||||||
showToast('Không thể xoá track chứa Section item.', 'warning');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const beforeSnap = captureTrackSnapshot(trackId);
|
const beforeSnap = captureTrackSnapshot(trackId);
|
||||||
setTracks(prev => {
|
setTracks(prev => {
|
||||||
const filtered = prev.filter(t => t.id !== trackId);
|
const filtered = prev.filter(t => t.id !== trackId);
|
||||||
@@ -8435,6 +8540,7 @@ const App = () => {
|
|||||||
setIsPlaying(true);
|
setIsPlaying(true);
|
||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
|
setTimeout(() => lucide.createIcons(), 50);
|
||||||
};
|
};
|
||||||
const toggleTrackMute = trackId => {
|
const toggleTrackMute = trackId => {
|
||||||
const beforeSnap = captureTrackSnapshot(trackId);
|
const beforeSnap = captureTrackSnapshot(trackId);
|
||||||
@@ -8453,6 +8559,7 @@ const App = () => {
|
|||||||
if (next.length > MAX_UNDO) next.shift();
|
if (next.length > MAX_UNDO) next.shift();
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
|
setTimeout(() => lucide.createIcons(), 50);
|
||||||
};
|
};
|
||||||
const updateTrackVolumeDb = (trackId, val) => {
|
const updateTrackVolumeDb = (trackId, val) => {
|
||||||
const beforeSnap = captureTrackSnapshot(trackId);
|
const beforeSnap = captureTrackSnapshot(trackId);
|
||||||
@@ -8648,6 +8755,7 @@ const App = () => {
|
|||||||
if (t.id !== trackId) return t;
|
if (t.id !== trackId) return t;
|
||||||
return { ...t, isArmed: !t.isArmed };
|
return { ...t, isArmed: !t.isArmed };
|
||||||
}));
|
}));
|
||||||
|
setTimeout(() => lucide.createIcons(), 50);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleTrackMonitor = trackId => {
|
const toggleTrackMonitor = trackId => {
|
||||||
@@ -8655,6 +8763,7 @@ const App = () => {
|
|||||||
if (t.id !== trackId) return t;
|
if (t.id !== trackId) return t;
|
||||||
return { ...t, monitoringEnabled: !t.monitoringEnabled };
|
return { ...t, monitoringEnabled: !t.monitoringEnabled };
|
||||||
}));
|
}));
|
||||||
|
setTimeout(() => lucide.createIcons(), 50);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateTrackInputSource = (trackId, type, deviceId) => {
|
const updateTrackInputSource = (trackId, type, deviceId) => {
|
||||||
@@ -11928,7 +12037,7 @@ const App = () => {
|
|||||||
}, activeTab === 'main' || sessionTabs.some(s => s.id === activeTab) ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
}, activeTab === 'main' || sessionTabs.some(s => s.id === activeTab) ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
||||||
ref: tcpContainerRef,
|
ref: tcpContainerRef,
|
||||||
onScroll: handleTCPScroll,
|
onScroll: handleTCPScroll,
|
||||||
className: "w-[300px] shrink-0 z-20 bg-[#262626] overflow-hidden flex flex-col border-r border-zinc-900",
|
className: "w-[300px] shrink-0 z-20 bg-[#262626] overflow-y-auto flex flex-col border-r border-zinc-900 no-scrollbar",
|
||||||
style: {
|
style: {
|
||||||
scrollbarWidth: 'none',
|
scrollbarWidth: 'none',
|
||||||
msOverflowStyle: 'none'
|
msOverflowStyle: 'none'
|
||||||
@@ -11993,10 +12102,11 @@ const App = () => {
|
|||||||
className: "w-3.5 h-3.5"
|
className: "w-3.5 h-3.5"
|
||||||
})), " Thêm Track Mới")) : activeTracks.map((track, idx) => {
|
})), " Thêm Track Mới")) : activeTracks.map((track, idx) => {
|
||||||
const isSelected = selectedTrackId === track.id;
|
const isSelected = selectedTrackId === track.id;
|
||||||
|
const autoHeight = track.height || (track.isArmed ? 164 : 140);
|
||||||
return /*#__PURE__*/React.createElement("div", {
|
return /*#__PURE__*/React.createElement("div", {
|
||||||
key: track.id,
|
key: track.id,
|
||||||
style: {
|
style: {
|
||||||
height: `${track.height || 96}px`
|
height: `${autoHeight}px`
|
||||||
},
|
},
|
||||||
className: `shrink-0 relative flex flex-col justify-between p-2.5 bg-[#1e1e1e] border-r border-zinc-900 cursor-pointer border-l-4 border-b border-[#141414] overflow-hidden ${isSelected ? 'border-cyan-500 bg-[#252525]' : 'border-transparent hover:bg-zinc-800/20'}`,
|
className: `shrink-0 relative flex flex-col justify-between p-2.5 bg-[#1e1e1e] border-r border-zinc-900 cursor-pointer border-l-4 border-b border-[#141414] overflow-hidden ${isSelected ? 'border-cyan-500 bg-[#252525]' : 'border-transparent hover:bg-zinc-800/20'}`,
|
||||||
onClick: () => setSelectedTrackId(track.id)
|
onClick: () => setSelectedTrackId(track.id)
|
||||||
@@ -12102,26 +12212,30 @@ const App = () => {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleTrackMute(track.id);
|
toggleTrackMute(track.id);
|
||||||
},
|
},
|
||||||
className: `px-1 py-0.5 text-[10px] rounded font-mono font-bold border transition ${track.muted ? 'bg-red-950 text-red-400 border-red-700' : 'bg-zinc-800 text-zinc-400 border-transparent hover:text-zinc-200'}`
|
title: "Mute",
|
||||||
}, "M"), /*#__PURE__*/React.createElement("button", {
|
className: `px-1.5 py-0.5 text-[10px] rounded font-mono font-bold border transition flex items-center gap-0.5 ${track.muted ? 'bg-red-950 text-red-400 border-red-700' : 'bg-zinc-800 text-zinc-400 border-transparent hover:text-zinc-200'}`
|
||||||
|
}, /*#__PURE__*/React.createElement("i", { "data-lucide": track.muted ? "volume-x" : "volume-2", className: "w-3 h-3" })), /*#__PURE__*/React.createElement("button", {
|
||||||
onClick: e => {
|
onClick: e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleTrackSoloEvaluate(track.id);
|
toggleTrackSoloEvaluate(track.id);
|
||||||
},
|
},
|
||||||
className: `px-1 py-0.5 text-[10px] rounded font-mono font-bold border transition ${soloedTrackId === track.id || track.solo ? 'bg-amber-950 text-amber-400 border-amber-600' : 'bg-zinc-800 text-zinc-400 border-transparent hover:text-zinc-200'}`
|
title: "Solo",
|
||||||
}, "S"), /*#__PURE__*/React.createElement("button", {
|
className: `px-1.5 py-0.5 text-[10px] rounded font-mono font-bold border transition flex items-center gap-0.5 ${soloedTrackId === track.id || track.solo ? 'bg-amber-950 text-amber-400 border-amber-600' : 'bg-zinc-800 text-zinc-400 border-transparent hover:text-zinc-200'}`
|
||||||
|
}, /*#__PURE__*/React.createElement("i", { "data-lucide": soloedTrackId === track.id || track.solo ? "headphones" : "headphones-off", className: "w-3 h-3" })), /*#__PURE__*/React.createElement("button", {
|
||||||
onClick: e => {
|
onClick: e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleTrackArm(track.id);
|
toggleTrackArm(track.id);
|
||||||
},
|
},
|
||||||
className: `px-1 py-0.5 text-[10px] rounded font-mono font-bold border transition ${track.isArmed ? 'bg-red-600 text-white border-red-500 hover:bg-red-500' : 'bg-zinc-800 text-zinc-400 border-transparent hover:text-zinc-200'}`
|
title: "ARM (Record)",
|
||||||
}, "R"), /*#__PURE__*/React.createElement("button", {
|
className: `px-1.5 py-0.5 text-[10px] rounded font-mono font-bold border transition flex items-center gap-0.5 ${track.isArmed ? 'bg-red-600 text-white border-red-500 hover:bg-red-500' : 'bg-zinc-800 text-zinc-400 border-transparent hover:text-zinc-200'}`
|
||||||
|
}, /*#__PURE__*/React.createElement("i", { "data-lucide": "circle", className: `w-2.5 h-2.5 ${track.isArmed ? 'fill-white' : ''}` })), /*#__PURE__*/React.createElement("button", {
|
||||||
onClick: e => {
|
onClick: e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleTrackMonitor(track.id);
|
toggleTrackMonitor(track.id);
|
||||||
},
|
},
|
||||||
className: `px-1 py-0.5 text-[10px] rounded font-mono font-bold border transition ${track.monitoringEnabled ? 'bg-amber-600 text-white border-amber-500 hover:bg-amber-500' : 'bg-zinc-800 text-zinc-500 border-transparent hover:text-zinc-305'}`
|
title: "Input Monitor",
|
||||||
}, "I"), /*#__PURE__*/React.createElement("button", {
|
className: `px-1.5 py-0.5 text-[10px] rounded font-mono font-bold border transition flex items-center gap-0.5 ${track.monitoringEnabled ? 'bg-amber-600 text-white border-amber-500 hover:bg-amber-500' : 'bg-zinc-800 text-zinc-500 border-transparent hover:text-zinc-305'}`
|
||||||
|
}, /*#__PURE__*/React.createElement("i", { "data-lucide": track.monitoringEnabled ? "mic" : "mic-off", className: "w-3 h-3" })), /*#__PURE__*/React.createElement("button", {
|
||||||
onClick: e => {
|
onClick: e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
deleteTrack(track.id);
|
deleteTrack(track.id);
|
||||||
@@ -12310,10 +12424,11 @@ const App = () => {
|
|||||||
className: "flex-1 flex flex-col divide-y divide-[#141414] relative bg-[#111111] min-h-full"
|
className: "flex-1 flex flex-col divide-y divide-[#141414] relative bg-[#111111] min-h-full"
|
||||||
}, activeTracks.map((track, idx) => {
|
}, activeTracks.map((track, idx) => {
|
||||||
const isSelected = selectedTrackId === track.id;
|
const isSelected = selectedTrackId === track.id;
|
||||||
|
const autoHeight = track.height || (track.isArmed ? 164 : 140);
|
||||||
return /*#__PURE__*/React.createElement("div", {
|
return /*#__PURE__*/React.createElement("div", {
|
||||||
key: track.id,
|
key: track.id,
|
||||||
style: {
|
style: {
|
||||||
height: `${track.height || 96}px`
|
height: `${autoHeight}px`
|
||||||
},
|
},
|
||||||
className: `shrink-0 relative border-b border-[#141414] hover:bg-zinc-850/5 transition-colors ${isSelected ? 'bg-zinc-800/10' : ''}`,
|
className: `shrink-0 relative border-b border-[#141414] hover:bg-zinc-850/5 transition-colors ${isSelected ? 'bg-zinc-800/10' : ''}`,
|
||||||
onDragOver: e => e.preventDefault(),
|
onDragOver: e => e.preventDefault(),
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Reference in New Issue
Block a user