Lofi_Generator/components/mixer/ChannelStrip.tsx
Nicholai d3158e4c6a feat(timeline-mixer): WIP timeline and mixer components
work in progress implementation of:
- mixer with channel strips, faders, pan knobs, level meters
- timeline with ruler, playhead, sections, keyframe tracks
- pattern and progression pickers for drums/chords
- automation lanes and mute tracks
- loop bracket for loop region selection
- export modal placeholder

known issues:
- drum pattern changes don't update audio engine
- timeline keyframes not connected to scheduler
- some UI bugs remain

this is a checkpoint commit for further iteration
2026-01-20 18:22:10 -07:00

103 lines
2.4 KiB
TypeScript

'use client';
import { Button } from '@/components/ui/button';
import { VerticalFader } from './VerticalFader';
import { LevelMeter } from './LevelMeter';
import { PanKnob } from './PanKnob';
import { cn } from '@/lib/utils';
interface ChannelStripProps {
name: string;
icon?: React.ReactNode;
volume: number;
pan: number;
muted: boolean;
soloed: boolean;
level: number;
onVolumeChange: (volume: number) => void;
onPanChange: (pan: number) => void;
onMuteToggle: () => void;
onSoloToggle: () => void;
showPan?: boolean;
showSolo?: boolean;
className?: string;
}
export function ChannelStrip({
name,
icon,
volume,
pan,
muted,
soloed,
level,
onVolumeChange,
onPanChange,
onMuteToggle,
onSoloToggle,
showPan = true,
showSolo = true,
className,
}: ChannelStripProps) {
return (
<div
className={cn(
'flex flex-col items-center gap-1.5 p-2 rounded-lg bg-card/50 border border-border/50',
'min-w-[64px]',
className
)}
>
<div className="flex items-center gap-1 text-xs text-muted-foreground">
{icon}
<span className="font-medium">{name}</span>
</div>
{showPan && <PanKnob value={pan} onChange={onPanChange} size={24} />}
<div className="flex gap-1.5 items-end">
<div className="flex flex-col items-center gap-1">
<VerticalFader
value={volume}
onChange={onVolumeChange}
min={0}
max={1}
height={64}
/>
<span className="text-[9px] font-mono text-muted-foreground">
{Math.round(volume * 100)}
</span>
</div>
<LevelMeter level={muted ? 0 : level} className="h-16" />
</div>
<div className="flex gap-1">
{showSolo && (
<Button
variant={soloed ? 'default' : 'outline'}
size="sm"
className={cn(
'h-6 w-6 p-0 text-[10px] font-bold',
soloed && 'bg-yellow-500 hover:bg-yellow-600 text-black'
)}
onClick={onSoloToggle}
>
S
</Button>
)}
<Button
variant={muted ? 'default' : 'outline'}
size="sm"
className={cn(
'h-6 w-6 p-0 text-[10px] font-bold',
muted && 'bg-red-500 hover:bg-red-600'
)}
onClick={onMuteToggle}
>
M
</Button>
</div>
</div>
);
}