Files
audio-ui/components/settings/GlobalSettingsDialog.tsx
Sebastian Krüger dc9647731d feat: redesign track controls to Ableton Live style
Major UI Redesign:
- Reduced track control width from 288px to 192px (33% narrower)
- Replaced horizontal sliders with vertical fader and circular knob
- More compact, professional appearance matching Ableton Live
- Global settings dialog replaces inline recording settings

New Components Created:
- VerticalFader.tsx: Vertical volume control with integrated level meter
  - Shows volume dB at top, level dB at bottom
  - Level meter displayed as background gradient
  - Draggable handle for precise control

- CircularKnob.tsx: Rotary pan control
  - SVG-based rotary knob with arc indicator
  - Vertical drag interaction (200px sensitivity)
  - Displays L/C/R values

- GlobalSettingsDialog.tsx: Centralized settings
  - Tabbed interface (Recording, Playback, Interface)
  - Recording settings moved from inline to dialog
  - Accessible via gear icon in header
  - Modal dialog with backdrop

Track Control Panel Changes:
- Track name: More compact (text-xs)
- Buttons: Smaller (h-6 w-6), text-based S/M buttons
- Record button: Circle indicator instead of icon
- Pan: Circular knob (40px) instead of horizontal slider
- Volume: Vertical fader with integrated meter
- Removed: Inline recording settings panel

Header Changes:
- Added Settings button (gear icon) before ThemeToggle
- Opens GlobalSettingsDialog on click
- Clean, accessible from anywhere

Props Cleanup:
- Removed recordingSettings props from Track/TrackList
- Removed onInputGainChange, onRecordMonoChange, onSampleRateChange props
- Settings now managed globally via dialog

Technical Details:
- VerticalFader uses mouse drag for smooth control
- CircularKnob rotates -135° to +135° (270° range)
- Global event listeners for drag interactions
- Proper cleanup on unmount

Benefits:
 33% narrower tracks = more tracks visible
 Professional Ableton-style appearance
 Cleaner, less cluttered interface
 Global settings accessible anywhere
 Better use of vertical space
 Consistent with industry-standard DAWs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 16:15:04 +01:00

190 lines
7.0 KiB
TypeScript

'use client';
import * as React from 'react';
import { X } from 'lucide-react';
import { Button } from '@/components/ui/Button';
import { RecordingSettings } from '@/components/recording/RecordingSettings';
import { cn } from '@/lib/utils/cn';
import type { RecordingSettings as RecordingSettingsType } from '@/lib/hooks/useRecording';
export interface GlobalSettingsDialogProps {
open: boolean;
onClose: () => void;
recordingSettings: RecordingSettingsType;
onInputGainChange: (gain: number) => void;
onRecordMonoChange: (mono: boolean) => void;
onSampleRateChange: (sampleRate: number) => void;
}
type TabType = 'recording' | 'playback' | 'interface';
export function GlobalSettingsDialog({
open,
onClose,
recordingSettings,
onInputGainChange,
onRecordMonoChange,
onSampleRateChange,
}: GlobalSettingsDialogProps) {
const [activeTab, setActiveTab] = React.useState<TabType>('recording');
if (!open) return null;
return (
<>
{/* Backdrop */}
<div
className="fixed inset-0 bg-background/80 backdrop-blur-sm z-40"
onClick={onClose}
/>
{/* Dialog */}
<div className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-2xl z-50">
<div className="bg-card border border-border rounded-lg shadow-2xl overflow-hidden">
{/* Header */}
<div className="flex items-center justify-between px-6 py-4 border-b border-border">
<h2 className="text-lg font-semibold">Settings</h2>
<Button
variant="ghost"
size="icon-sm"
onClick={onClose}
title="Close"
>
<X className="h-4 w-4" />
</Button>
</div>
{/* Tabs */}
<div className="flex border-b border-border bg-muted/30">
<button
onClick={() => setActiveTab('recording')}
className={cn(
'px-6 py-3 text-sm font-medium transition-colors relative',
activeTab === 'recording'
? 'text-foreground bg-card'
: 'text-muted-foreground hover:text-foreground hover:bg-muted/50'
)}
>
Recording
{activeTab === 'recording' && (
<div className="absolute bottom-0 left-0 right-0 h-0.5 bg-primary" />
)}
</button>
<button
onClick={() => setActiveTab('playback')}
className={cn(
'px-6 py-3 text-sm font-medium transition-colors relative',
activeTab === 'playback'
? 'text-foreground bg-card'
: 'text-muted-foreground hover:text-foreground hover:bg-muted/50'
)}
>
Playback
{activeTab === 'playback' && (
<div className="absolute bottom-0 left-0 right-0 h-0.5 bg-primary" />
)}
</button>
<button
onClick={() => setActiveTab('interface')}
className={cn(
'px-6 py-3 text-sm font-medium transition-colors relative',
activeTab === 'interface'
? 'text-foreground bg-card'
: 'text-muted-foreground hover:text-foreground hover:bg-muted/50'
)}
>
Interface
{activeTab === 'interface' && (
<div className="absolute bottom-0 left-0 right-0 h-0.5 bg-primary" />
)}
</button>
</div>
{/* Content */}
<div className="p-6 max-h-[60vh] overflow-y-auto custom-scrollbar">
{activeTab === 'recording' && (
<div className="space-y-4">
<div>
<h3 className="text-sm font-medium mb-3">Recording Settings</h3>
<RecordingSettings
settings={recordingSettings}
onInputGainChange={onInputGainChange}
onRecordMonoChange={onRecordMonoChange}
onSampleRateChange={onSampleRateChange}
className="border-0 bg-transparent p-0"
/>
</div>
<div className="pt-4 border-t border-border">
<h3 className="text-sm font-medium mb-2">Note</h3>
<p className="text-sm text-muted-foreground">
These settings apply globally to all recordings. Arm a track (red button)
to enable recording on that specific track.
</p>
</div>
</div>
)}
{activeTab === 'playback' && (
<div className="space-y-4">
<div>
<h3 className="text-sm font-medium mb-2">Playback Settings</h3>
<p className="text-sm text-muted-foreground mb-4">
Configure audio playback preferences.
</p>
<div className="space-y-3 text-sm text-muted-foreground">
<div className="flex items-center justify-between p-3 bg-muted/50 rounded">
<span>Buffer Size</span>
<span className="font-mono">Auto</span>
</div>
<div className="flex items-center justify-between p-3 bg-muted/50 rounded">
<span>Output Latency</span>
<span className="font-mono">~20ms</span>
</div>
<p className="text-xs italic">
Advanced playback settings coming soon...
</p>
</div>
</div>
</div>
)}
{activeTab === 'interface' && (
<div className="space-y-4">
<div>
<h3 className="text-sm font-medium mb-2">Interface Settings</h3>
<p className="text-sm text-muted-foreground mb-4">
Customize the editor appearance and behavior.
</p>
<div className="space-y-3 text-sm text-muted-foreground">
<div className="flex items-center justify-between p-3 bg-muted/50 rounded">
<span>Theme</span>
<span>Use theme toggle in header</span>
</div>
<div className="flex items-center justify-between p-3 bg-muted/50 rounded">
<span>Default Track Height</span>
<span className="font-mono">180px</span>
</div>
<p className="text-xs italic">
More interface options coming soon...
</p>
</div>
</div>
</div>
)}
</div>
{/* Footer */}
<div className="flex items-center justify-end gap-2 px-6 py-4 border-t border-border bg-muted/30">
<Button variant="default" onClick={onClose}>
Done
</Button>
</div>
</div>
</div>
</>
);
}