refactor: move automation controls to left sidebar, simplify layout
Major automation UX improvements: - Moved all automation controls to left sidebar (180px, matching track controls) - Parameter dropdown selector - Automation mode button (R/W/T/L with color coding) - Height adjustment buttons (+/-) - Automation canvas now fills right side (matching waveform width exactly) - Removed AutomationHeader component (no longer needed) - Removed eye icon (automation visibility controlled by "A" button on track) Two-column layout consistency: - Left: 180px sidebar with all controls - Right: Flexible canvas area matching waveform width - Perfect vertical alignment between waveform and automation Simplified AutomationLane component: - Now only renders the canvas area with points - All controls handled in parent Track component - Cleaner, more maintainable code structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,8 +2,7 @@
|
||||
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils/cn';
|
||||
import type { AutomationLane as AutomationLaneType, AutomationPoint as AutomationPointType, AutomationMode } from '@/types/automation';
|
||||
import { AutomationHeader } from './AutomationHeader';
|
||||
import type { AutomationLane as AutomationLaneType, AutomationPoint as AutomationPointType } from '@/types/automation';
|
||||
import { AutomationPoint } from './AutomationPoint';
|
||||
|
||||
export interface AutomationLaneProps {
|
||||
@@ -16,10 +15,6 @@ export interface AutomationLaneProps {
|
||||
onUpdatePoint?: (pointId: string, updates: Partial<AutomationPointType>) => void;
|
||||
onRemovePoint?: (pointId: string) => void;
|
||||
className?: string;
|
||||
// Parameter selection
|
||||
availableParameters?: Array<{ id: string; name: string }>;
|
||||
selectedParameterId?: string;
|
||||
onParameterChange?: (parameterId: string) => void;
|
||||
}
|
||||
|
||||
export function AutomationLane({
|
||||
@@ -32,9 +27,6 @@ export function AutomationLane({
|
||||
onUpdatePoint,
|
||||
onRemovePoint,
|
||||
className,
|
||||
availableParameters,
|
||||
selectedParameterId,
|
||||
onParameterChange,
|
||||
}: AutomationLaneProps) {
|
||||
const canvasRef = React.useRef<HTMLCanvasElement>(null);
|
||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||
@@ -294,54 +286,32 @@ export function AutomationLane({
|
||||
if (!lane.visible) return null;
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-col', className)} style={{ height: lane.height + 30 }}>
|
||||
{/* Header */}
|
||||
<AutomationHeader
|
||||
parameterName={lane.parameterName}
|
||||
currentValue={getCurrentValue()}
|
||||
visible={lane.visible}
|
||||
mode={lane.mode}
|
||||
color={lane.color}
|
||||
onToggleVisible={() => onUpdateLane?.({ visible: !lane.visible })}
|
||||
onModeChange={(mode: AutomationMode) => onUpdateLane?.({ mode })}
|
||||
onHeightChange={(delta) => {
|
||||
const newHeight = Math.max(60, Math.min(180, lane.height + delta));
|
||||
onUpdateLane?.({ height: newHeight });
|
||||
}}
|
||||
formatter={lane.valueRange.formatter}
|
||||
availableParameters={availableParameters}
|
||||
selectedParameterId={selectedParameterId}
|
||||
onParameterChange={onParameterChange}
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={cn('relative bg-background/30 overflow-hidden cursor-crosshair', className)}
|
||||
style={{ height: lane.height }}
|
||||
>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
className="absolute inset-0 w-full h-full"
|
||||
onClick={handleCanvasClick}
|
||||
/>
|
||||
|
||||
{/* Lane canvas area */}
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="relative flex-1 bg-background/30 overflow-hidden cursor-crosshair"
|
||||
style={{ height: lane.height }}
|
||||
>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
className="absolute inset-0 w-full h-full"
|
||||
onClick={handleCanvasClick}
|
||||
{/* Automation points */}
|
||||
{lane.points.map((point) => (
|
||||
<AutomationPoint
|
||||
key={point.id}
|
||||
point={point}
|
||||
x={timeToX(point.time)}
|
||||
y={valueToY(point.value)}
|
||||
isSelected={selectedPointId === point.id}
|
||||
onDragStart={handlePointDragStart}
|
||||
onDrag={handlePointDrag}
|
||||
onDragEnd={handlePointDragEnd}
|
||||
onClick={handlePointClick}
|
||||
onDoubleClick={handlePointDoubleClick}
|
||||
/>
|
||||
|
||||
{/* Automation points */}
|
||||
{lane.points.map((point) => (
|
||||
<AutomationPoint
|
||||
key={point.id}
|
||||
point={point}
|
||||
x={timeToX(point.time)}
|
||||
y={valueToY(point.value)}
|
||||
isSelected={selectedPointId === point.id}
|
||||
onDragStart={handlePointDragStart}
|
||||
onDrag={handlePointDrag}
|
||||
onDragEnd={handlePointDragEnd}
|
||||
onClick={handlePointClick}
|
||||
onDoubleClick={handlePointDoubleClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user