From 235fc3913ce7cfff46f766911ddd3e981f4ea6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Wed, 19 Nov 2025 12:12:26 +0100 Subject: [PATCH] fix: position bars at bottom, always visible, no inner containers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major improvements to automation and effects bars: - Both bars now positioned at bottom of waveform (not top) - Bars are always visible when track is expanded (no show/hide buttons) - Effects bar at absolute bottom - Automation bar above effects, dynamically positioned based on effects state - Removed inner container from effects - direct rendering with EffectDevice - Removed close buttons (X icons) - bars are permanent - Effects render directly with gap-3 padding, no TrackExtensions wrapper - Automation controls preserved (AutomationLane unchanged) This creates a cleaner, always-accessible interface where users can quickly expand/collapse automation or effects without toggling visibility. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- components/tracks/TrackList.tsx | 221 ++++++++++++++------------------ 1 file changed, 97 insertions(+), 124 deletions(-) diff --git a/components/tracks/TrackList.tsx b/components/tracks/TrackList.tsx index f926307..879fbe2 100644 --- a/components/tracks/TrackList.tsx +++ b/components/tracks/TrackList.tsx @@ -11,6 +11,7 @@ import { createEffect, type EffectType, EFFECT_NAMES } from '@/lib/audio/effects import { AutomationLane } from '@/components/automation/AutomationLane'; import type { AutomationPoint as AutomationPointType } from '@/types/automation'; import { createAutomationPoint } from '@/lib/audio/automation/utils'; +import { EffectDevice } from '@/components/effects/EffectDevice'; export interface TrackListProps { tracks: TrackType[]; @@ -292,12 +293,93 @@ export function TrackList({ renderWaveformOnly={true} /> - {/* Automation Bar - Integrated at top */} - {!track.collapsed && track.automation?.showAutomation && ( -
- {/* Automation Header - Always visible */} + {/* Effects Bar - Always visible at bottom */} + {!track.collapsed && ( +
+ {/* Effects Header - Collapsible */}
{ + onUpdateTrack(track.id, { effectsExpanded: !track.effectsExpanded }); + }} + > + {track.effectsExpanded ? ( + + ) : ( + + )} + Effects + + ({track.effectChain.effects.length}) + +
+ + {/* Effects Content - Collapsible, no inner container */} + {track.effectsExpanded && ( +
+
+ {track.effectChain.effects.length === 0 ? ( +
+ No effects. Click + to add an effect. +
+ ) : ( + track.effectChain.effects.map((effect) => ( + { + const updatedChain = { + ...track.effectChain, + effects: track.effectChain.effects.map((e) => + e.id === effect.id ? { ...e, enabled: !e.enabled } : e + ), + }; + onUpdateTrack(track.id, { effectChain: updatedChain }); + }} + onRemove={() => { + const updatedChain = { + ...track.effectChain, + effects: track.effectChain.effects.filter((e) => e.id !== effect.id), + }; + onUpdateTrack(track.id, { effectChain: updatedChain }); + }} + onUpdateParameters={(params) => { + const updatedChain = { + ...track.effectChain, + effects: track.effectChain.effects.map((e) => + e.id === effect.id ? { ...e, parameters: params } : e + ), + }; + onUpdateTrack(track.id, { effectChain: updatedChain }); + }} + onToggleExpanded={() => { + const updatedEffects = track.effectChain.effects.map((e) => + e.id === effect.id ? { ...e, expanded: !e.expanded } : e + ); + onUpdateTrack(track.id, { + effectChain: { ...track.effectChain, effects: updatedEffects }, + }); + }} + /> + )) + )} +
+
+ )} +
+ )} + + {/* Automation Bar - Always visible above effects bar at bottom */} + {!track.collapsed && ( +
+ {/* Automation Header - Collapsible */} +
{ const currentLane = track.automation.lanes.find( l => l.parameterId === track.automation.selectedParameterId @@ -312,38 +394,22 @@ export function TrackList({ } }} > -
- {track.automation.lanes.find(l => l.parameterId === track.automation.selectedParameterId)?.visible ? ( - - ) : ( - - )} - Automation - - {track.automation.selectedParameterId || 'Volume'} - -
- + {track.automation.lanes.find(l => l.parameterId === track.automation.selectedParameterId)?.visible ? ( + + ) : ( + + )} + Automation + + {track.automation.selectedParameterId || 'Volume'} +
{/* Automation Lane Content - Collapsible */} {track.automation.lanes .filter((lane) => lane.parameterId === track.automation.selectedParameterId && lane.visible) .map((lane) => ( -
+
)} - - {/* Effects Bar - Integrated below automation or at top */} - {!track.collapsed && track.showEffects && ( -
l.parameterId === track.automation.selectedParameterId)?.visible - ? '164px' // 32px header + 132px automation lane - : track.automation?.showAutomation - ? '32px' // Just header - : '0px' - }} - > - {/* Effects Header - Always visible */} -
{ - onUpdateTrack(track.id, { effectsExpanded: !track.effectsExpanded }); - }} - > -
- {track.effectsExpanded ? ( - - ) : ( - - )} - Effects - - ({track.effectChain.effects.length}) - -
- -
- - {/* Effects Content - Collapsible */} - {track.effectsExpanded && ( -
- { - const updatedChain = { - ...track.effectChain, - effects: track.effectChain.effects.map((e) => - e.id === effectId ? { ...e, enabled: !e.enabled } : e - ), - }; - onUpdateTrack(track.id, { effectChain: updatedChain }); - }} - onRemoveEffect={(effectId) => { - const updatedChain = { - ...track.effectChain, - effects: track.effectChain.effects.filter((e) => e.id !== effectId), - }; - onUpdateTrack(track.id, { effectChain: updatedChain }); - }} - onUpdateEffect={(effectId, parameters) => { - const updatedChain = { - ...track.effectChain, - effects: track.effectChain.effects.map((e) => - e.id === effectId ? { ...e, parameters } : e - ), - }; - onUpdateTrack(track.id, { effectChain: updatedChain }); - }} - onAddEffect={(effectType) => { - const newEffect = createEffect( - effectType, - EFFECT_NAMES[effectType] - ); - const updatedChain = { - ...track.effectChain, - effects: [...track.effectChain.effects, newEffect], - }; - onUpdateTrack(track.id, { effectChain: updatedChain }); - }} - /> -
- )} -
- )}
))}