diff --git a/components/layout/SidePanel.tsx b/components/layout/SidePanel.tsx
index 0220c3f..9d3abd5 100644
--- a/components/layout/SidePanel.tsx
+++ b/components/layout/SidePanel.tsx
@@ -9,13 +9,10 @@ import {
Trash2,
Link2,
FolderOpen,
- Volume2,
Music2,
} from 'lucide-react';
import { Button } from '@/components/ui/Button';
-import { Slider } from '@/components/ui/Slider';
import { cn } from '@/lib/utils/cn';
-import { formatDuration } from '@/lib/audio/decoder';
import type { Track } from '@/types/track';
import type { EffectChain, EffectPreset } from '@/lib/audio/effects/chain';
import { EffectRack } from '@/components/effects/EffectRack';
@@ -165,122 +162,17 @@ export function SidePanel({
)}
- {/* Track List */}
+ {/* Track List - Simplified */}
{tracks.length > 0 ? (
Tracks ({tracks.length})
-
- {tracks.map((track) => {
- const isSelected = selectedTrackId === track.id;
- return (
-
onSelectTrack(isSelected ? null : track.id)}
- >
-
-
-
- {String(track.name || 'Untitled Track')}
-
- {track.audioBuffer && (
-
- {formatDuration(track.audioBuffer.duration)}
-
- )}
-
-
-
-
- {/* Track Controls - Always visible */}
-
e.stopPropagation()}>
- {/* Volume */}
-
-
-
-
- {Math.round(track.volume * 100)}%
-
-
-
onUpdateTrack(track.id, { volume: value })}
- min={0}
- max={1}
- step={0.01}
- />
-
-
- {/* Pan */}
-
-
-
-
- {track.pan === 0
- ? 'C'
- : track.pan < 0
- ? `L${Math.round(Math.abs(track.pan) * 100)}`
- : `R${Math.round(track.pan * 100)}`}
-
-
-
onUpdateTrack(track.id, { pan: value })}
- min={-1}
- max={1}
- step={0.01}
- />
-
-
- {/* Solo / Mute */}
-
-
-
-
-
-
- );
- })}
+
+
+ Track controls are located on the left side of each track in the timeline.
+
+
Click a track to select it and apply effects from the Effect Chain tab.
) : (
diff --git a/components/tracks/Track.tsx b/components/tracks/Track.tsx
index 4071103..d6093d7 100644
--- a/components/tracks/Track.tsx
+++ b/components/tracks/Track.tsx
@@ -1,8 +1,10 @@
'use client';
import * as React from 'react';
+import { Volume2, VolumeX, Headphones, Trash2, ChevronDown, ChevronRight } from 'lucide-react';
import type { Track as TrackType } from '@/types/track';
-import { TrackHeader } from './TrackHeader';
+import { Button } from '@/components/ui/Button';
+import { Slider } from '@/components/ui/Slider';
import { cn } from '@/lib/utils/cn';
export interface TrackProps {
@@ -40,6 +42,39 @@ export function Track({
}: TrackProps) {
const canvasRef = React.useRef
(null);
const containerRef = React.useRef(null);
+ const [isEditingName, setIsEditingName] = React.useState(false);
+ const [nameInput, setNameInput] = React.useState(String(track.name || 'Untitled Track'));
+ const inputRef = React.useRef(null);
+
+ const handleNameClick = () => {
+ setIsEditingName(true);
+ setNameInput(String(track.name || 'Untitled Track'));
+ };
+
+ const handleNameBlur = () => {
+ setIsEditingName(false);
+ if (nameInput.trim()) {
+ onNameChange(nameInput.trim());
+ } else {
+ setNameInput(String(track.name || 'Untitled Track'));
+ }
+ };
+
+ const handleNameKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter') {
+ inputRef.current?.blur();
+ } else if (e.key === 'Escape') {
+ setNameInput(String(track.name || 'Untitled Track'));
+ setIsEditingName(false);
+ }
+ };
+
+ React.useEffect(() => {
+ if (isEditingName && inputRef.current) {
+ inputRef.current.focus();
+ inputRef.current.select();
+ }
+ }, [isEditingName]);
// Draw waveform
React.useEffect(() => {
@@ -123,59 +158,173 @@ export function Track({
onSeek(clickTime);
};
- if (track.collapsed) {
- return (
-
-
-
- );
- }
+ const trackHeight = track.collapsed ? 48 : track.height;
return (
-
-
- {track.audioBuffer ? (
-