forked from averyfelts/Lofi_Generator
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
52 lines
1.2 KiB
TypeScript
52 lines
1.2 KiB
TypeScript
'use client';
|
|
|
|
import { useMemo } from 'react';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface TimelineRulerProps {
|
|
durationBars: number;
|
|
pixelsPerBar: number;
|
|
className?: string;
|
|
}
|
|
|
|
export function TimelineRuler({
|
|
durationBars,
|
|
pixelsPerBar,
|
|
className,
|
|
}: TimelineRulerProps) {
|
|
const markers = useMemo(() => {
|
|
const items: { bar: number; isMajor: boolean }[] = [];
|
|
for (let bar = 0; bar <= durationBars; bar++) {
|
|
items.push({ bar, isMajor: bar % 4 === 0 });
|
|
}
|
|
return items;
|
|
}, [durationBars]);
|
|
|
|
return (
|
|
<div
|
|
className={cn('relative h-6 bg-muted/30 border-b border-border/50', className)}
|
|
style={{ width: durationBars * pixelsPerBar }}
|
|
>
|
|
{markers.map(({ bar, isMajor }) => (
|
|
<div
|
|
key={bar}
|
|
className="absolute top-0 flex flex-col items-center"
|
|
style={{ left: bar * pixelsPerBar }}
|
|
>
|
|
<div
|
|
className={cn(
|
|
'w-px',
|
|
isMajor ? 'h-4 bg-muted-foreground/60' : 'h-2 bg-muted-foreground/30'
|
|
)}
|
|
/>
|
|
{isMajor && (
|
|
<span className="text-[9px] font-mono text-muted-foreground/80 mt-0.5">
|
|
{bar + 1}
|
|
</span>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|