This commit is contained in:
parent
7d21081780
commit
1ca5e4a3a8
1 changed files with 31 additions and 108 deletions
|
|
@ -279,17 +279,6 @@ function RecordingDetail({ recording: r, data, onBack, allHighlights, setAllHigh
|
|||
'follow-up': 'var(--amber-dim)', meeting: 'var(--green)', personal: 'var(--text2)', work: 'var(--teal)',
|
||||
};
|
||||
|
||||
const progressPct = (currentTime / totalSeconds) * 100;
|
||||
|
||||
// Waveform: fake bars
|
||||
const waveformBars = 120;
|
||||
const waveHeights = useRefRD(null);
|
||||
if (!waveHeights.current) {
|
||||
const rand = (seed) => { let s = seed; return () => { s = (s * 16807) % 2147483647; return (s - 1) / 2147483646; }; };
|
||||
const rng = rand(r.id * 42);
|
||||
waveHeights.current = Array.from({ length: waveformBars }, () => 0.1 + rng() * 0.9);
|
||||
}
|
||||
|
||||
const qualityDetails = [
|
||||
{ label: 'Quality', value: r.quality, cls: `q-${r.quality}` },
|
||||
{ label: 'Sample Rate', value: `${r.sampleRate / 1000} kHz`, cls: '' },
|
||||
|
|
@ -407,110 +396,44 @@ function RecordingDetail({ recording: r, data, onBack, allHighlights, setAllHigh
|
|||
{/* Left: Player + Transcript */}
|
||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
|
||||
|
||||
{/* Player */}
|
||||
{/* Player - simplified with native controls */}
|
||||
<div style={{ padding: '16px 20px', borderBottom: '1px solid var(--border)', background: 'var(--bg2)', flexShrink: 0 }}>
|
||||
{/* Waveform */}
|
||||
<div
|
||||
onClick={seek}
|
||||
style={{ height: 56, display: 'flex', alignItems: 'center', gap: 1, cursor: 'pointer', marginBottom: 8, position: 'relative' }}
|
||||
>
|
||||
{waveHeights.current.map((h, i) => {
|
||||
const barPct = i / waveformBars;
|
||||
const barTime = barPct * totalSeconds;
|
||||
const isPast = barPct <= progressPct / 100;
|
||||
const isActive = Math.abs(barPct - progressPct / 100) < 0.015;
|
||||
{audioLoading && (
|
||||
<div style={{ color: 'var(--text3)', fontSize: 11, fontFamily: 'var(--font-mono)', marginBottom: 8 }}>
|
||||
Loading audio...
|
||||
</div>
|
||||
)}
|
||||
|
||||
// Check if bar is within any highlight range (or near a point highlight)
|
||||
const inHighlight = recHighlights.some(hl => {
|
||||
if (hl.endSeconds != null) {
|
||||
// Range highlight - check if bar is within range
|
||||
return barTime >= hl.startSeconds && barTime <= hl.endSeconds;
|
||||
} else {
|
||||
// Point highlight - check if near
|
||||
return Math.abs(hl.startSeconds - barTime) < (totalSeconds / waveformBars);
|
||||
}
|
||||
});
|
||||
{/* Native audio element with controls */}
|
||||
{audioBlobUrl && (
|
||||
<audio
|
||||
ref={audioRef}
|
||||
src={audioBlobUrl}
|
||||
controls
|
||||
style={{ width: '100%', marginBottom: 12 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
// Check if bar is within the pending highlight being created
|
||||
const inPendingHighlight = showAddHighlight && highlightStartTime != null && (
|
||||
highlightEndTime != null
|
||||
? barTime >= highlightStartTime && barTime <= highlightEndTime
|
||||
: Math.abs(highlightStartTime - barTime) < (totalSeconds / waveformBars)
|
||||
);
|
||||
|
||||
return (
|
||||
<div key={i} style={{
|
||||
flex: 1,
|
||||
height: `${Math.round(h * 100)}%`,
|
||||
background: inPendingHighlight ? 'var(--red)' : inHighlight ? 'var(--amber)' : isPast ? 'var(--teal)' : 'var(--bg4)',
|
||||
borderRadius: 1,
|
||||
minHeight: 2,
|
||||
transition: 'background 0.05s',
|
||||
opacity: isActive ? 1 : 0.85,
|
||||
}} />
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Highlight range markers when creating */}
|
||||
{showAddHighlight && highlightStartTime != null && (
|
||||
<div style={{
|
||||
position: 'absolute', left: `${(highlightStartTime / totalSeconds) * 100}%`, top: 0, bottom: 0,
|
||||
width: 2, background: 'var(--red)', pointerEvents: 'none',
|
||||
}} />
|
||||
)}
|
||||
{showAddHighlight && highlightEndTime != null && (
|
||||
<div style={{
|
||||
position: 'absolute', left: `${(highlightEndTime / totalSeconds) * 100}%`, top: 0, bottom: 0,
|
||||
width: 2, background: 'var(--red)', pointerEvents: 'none',
|
||||
}} />
|
||||
)}
|
||||
|
||||
{/* Playhead */}
|
||||
<div style={{
|
||||
position: 'absolute', left: `${progressPct}%`, top: 0, bottom: 0,
|
||||
width: 2, background: 'var(--amber)', pointerEvents: 'none',
|
||||
boxShadow: '0 0 6px var(--amber)',
|
||||
}} />
|
||||
</div>
|
||||
|
||||
{/* Hidden audio element */}
|
||||
{audioBlobUrl && <audio ref={audioRef} src={audioBlobUrl} preload="metadata" />}
|
||||
{audioLoading && <div style={{ color: 'var(--text3)', fontSize: 11, fontFamily: 'var(--font-mono)' }}>Loading audio...</div>}
|
||||
|
||||
{/* Controls */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||
<button onClick={() => skipTime(-30)} style={{ color: 'var(--text2)', fontFamily: 'var(--font-mono)', fontSize: 11 }}>-30s</button>
|
||||
<button onClick={() => skipTime(-5)} style={{ color: 'var(--text2)', fontFamily: 'var(--font-mono)', fontSize: 11 }}>-5s</button>
|
||||
<button
|
||||
onClick={togglePlay}
|
||||
style={{
|
||||
width: 36, height: 36, borderRadius: '50%',
|
||||
background: 'var(--amber)', color: 'var(--bg)',
|
||||
fontSize: 14, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>{playing ? '⏸' : '▶'}</button>
|
||||
<button onClick={() => skipTime(5)} style={{ color: 'var(--text2)', fontFamily: 'var(--font-mono)', fontSize: 11 }}>+5s</button>
|
||||
<button onClick={() => skipTime(30)} style={{ color: 'var(--text2)', fontFamily: 'var(--font-mono)', fontSize: 11 }}>+30s</button>
|
||||
{/* Extra controls: skip buttons and speed */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<button onClick={() => skipTime(-30)} style={{ color: 'var(--text2)', fontFamily: 'var(--font-mono)', fontSize: 11, padding: '4px 8px', background: 'var(--bg4)', borderRadius: 4 }}>-30s</button>
|
||||
<button onClick={() => skipTime(-5)} style={{ color: 'var(--text2)', fontFamily: 'var(--font-mono)', fontSize: 11, padding: '4px 8px', background: 'var(--bg4)', borderRadius: 4 }}>-5s</button>
|
||||
<button onClick={() => skipTime(5)} style={{ color: 'var(--text2)', fontFamily: 'var(--font-mono)', fontSize: 11, padding: '4px 8px', background: 'var(--bg4)', borderRadius: 4 }}>+5s</button>
|
||||
<button onClick={() => skipTime(30)} style={{ color: 'var(--text2)', fontFamily: 'var(--font-mono)', fontSize: 11, padding: '4px 8px', background: 'var(--bg4)', borderRadius: 4 }}>+30s</button>
|
||||
|
||||
<div style={{ flex: 1 }} />
|
||||
|
||||
{/* Speed */}
|
||||
<div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
||||
{[0.5, 1.0, 1.5, 2.0, 3.0].map(s => (
|
||||
<button key={s} onClick={() => setSpeed(s)} style={{
|
||||
fontFamily: 'var(--font-mono)', fontSize: 10, padding: '2px 7px',
|
||||
borderRadius: 3,
|
||||
background: speed === s ? 'var(--amber)' : 'var(--bg4)',
|
||||
color: speed === s ? 'var(--bg)' : 'var(--text3)',
|
||||
border: '1px solid var(--border)',
|
||||
}}>{s}×</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text2)', minWidth: 100, textAlign: 'right' }}>
|
||||
{formatTime(currentTime)} / {formatTime(totalSeconds)}
|
||||
</div>
|
||||
<span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text3)' }}>Speed:</span>
|
||||
{[0.5, 1.0, 1.5, 2.0, 3.0].map(s => (
|
||||
<button key={s} onClick={() => setSpeed(s)} style={{
|
||||
fontFamily: 'var(--font-mono)', fontSize: 10, padding: '2px 7px',
|
||||
borderRadius: 3,
|
||||
background: speed === s ? 'var(--amber)' : 'var(--bg4)',
|
||||
color: speed === s ? 'var(--bg)' : 'var(--text3)',
|
||||
border: '1px solid var(--border)',
|
||||
}}>{s}×</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue