refactor: use stacked layout for waveform, automation, and effects bars
- Replace absolute positioning with flex column layout - Waveform, automation bar, and effects bar now stacked vertically - Removes gaps between bars naturally with stacked layout - Both bars remain collapsible with no position dependencies 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -206,8 +206,8 @@ export function TrackList({
|
||||
<div className="flex flex-col">
|
||||
{tracks.map((track) => (
|
||||
<React.Fragment key={track.id}>
|
||||
{/* Track Waveform Row with Overlays */}
|
||||
<div className="relative">
|
||||
{/* Track Waveform Row with bars stacked below */}
|
||||
<div className="flex flex-col">
|
||||
<Track
|
||||
track={track}
|
||||
zoom={zoom}
|
||||
@@ -293,90 +293,9 @@ export function TrackList({
|
||||
renderWaveformOnly={true}
|
||||
/>
|
||||
|
||||
{/* Effects Bar - Always visible at bottom */}
|
||||
{/* Automation Bar - Collapsible */}
|
||||
{!track.collapsed && (
|
||||
<div className="absolute bottom-0 left-0 right-0 z-10 pointer-events-auto bg-card/90 backdrop-blur-sm border-b border-border">
|
||||
{/* Effects Header - Collapsible */}
|
||||
<div
|
||||
className="flex items-center gap-2 px-3 py-1.5 cursor-pointer hover:bg-accent/30 transition-colors"
|
||||
onClick={() => {
|
||||
onUpdateTrack(track.id, { effectsExpanded: !track.effectsExpanded });
|
||||
}}
|
||||
>
|
||||
{track.effectsExpanded ? (
|
||||
<ChevronDown className="h-3 w-3 text-muted-foreground" />
|
||||
) : (
|
||||
<ChevronRight className="h-3 w-3 text-muted-foreground" />
|
||||
)}
|
||||
<span className="text-xs font-medium">Effects</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
({track.effectChain.effects.length})
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Effects Content - Collapsible, no inner container */}
|
||||
{track.effectsExpanded && (
|
||||
<div className="h-48 overflow-x-auto custom-scrollbar bg-muted/70 border-t border-border">
|
||||
<div className="flex h-full gap-3 p-3">
|
||||
{track.effectChain.effects.length === 0 ? (
|
||||
<div className="text-xs text-muted-foreground text-center py-8 w-full">
|
||||
No effects. Click + to add an effect.
|
||||
</div>
|
||||
) : (
|
||||
track.effectChain.effects.map((effect) => (
|
||||
<EffectDevice
|
||||
key={effect.id}
|
||||
effect={effect}
|
||||
onToggleEnabled={() => {
|
||||
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 },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Automation Bar - Collapsible, above effects bar at bottom */}
|
||||
{!track.collapsed && (
|
||||
<div
|
||||
className="absolute left-0 right-0 z-10 pointer-events-auto bg-card/90 backdrop-blur-sm"
|
||||
style={{
|
||||
bottom: track.effectsExpanded ? '232px' : '32px' // 32px effects header, or 232px if expanded
|
||||
}}
|
||||
>
|
||||
<div className="bg-card/90 backdrop-blur-sm border-b border-border">
|
||||
{/* Automation Header - Clickable to toggle */}
|
||||
<div
|
||||
className="flex items-center gap-2 px-3 py-1.5 cursor-pointer hover:bg-accent/30 transition-colors"
|
||||
@@ -465,6 +384,82 @@ export function TrackList({
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Effects Bar - Collapsible */}
|
||||
{!track.collapsed && (
|
||||
<div className="bg-card/90 backdrop-blur-sm border-b border-border">
|
||||
{/* Effects Header - Collapsible */}
|
||||
<div
|
||||
className="flex items-center gap-2 px-3 py-1.5 cursor-pointer hover:bg-accent/30 transition-colors"
|
||||
onClick={() => {
|
||||
onUpdateTrack(track.id, { effectsExpanded: !track.effectsExpanded });
|
||||
}}
|
||||
>
|
||||
{track.effectsExpanded ? (
|
||||
<ChevronDown className="h-3 w-3 text-muted-foreground" />
|
||||
) : (
|
||||
<ChevronRight className="h-3 w-3 text-muted-foreground" />
|
||||
)}
|
||||
<span className="text-xs font-medium">Effects</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
({track.effectChain.effects.length})
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Effects Content - Collapsible, no inner container */}
|
||||
{track.effectsExpanded && (
|
||||
<div className="h-48 overflow-x-auto custom-scrollbar bg-muted/70 border-t border-border">
|
||||
<div className="flex h-full gap-3 p-3">
|
||||
{track.effectChain.effects.length === 0 ? (
|
||||
<div className="text-xs text-muted-foreground text-center py-8 w-full">
|
||||
No effects. Click + to add an effect.
|
||||
</div>
|
||||
) : (
|
||||
track.effectChain.effects.map((effect) => (
|
||||
<EffectDevice
|
||||
key={effect.id}
|
||||
effect={effect}
|
||||
onToggleEnabled={() => {
|
||||
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 },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user