Replace MudSlider seekbar with WaveformSeeker loudness-waveform control
DOM bar chart with clip-overlay progress split; pointer-capture drag; WaveformProfile fetched on load (fire-and-forget, cancellable); flat fallback when no profile; small lazily-loaded waveformSeeker.js for getBoundingClientRect and setPointerCapture.
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/* Geometry only. Colours come from shared --deepdrft-* theme tokens (deepdrft-tokens.css). */
|
||||
|
||||
.waveform-seeker {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
cursor: pointer;
|
||||
touch-action: none; /* let pointer-capture drag own the gesture, not the browser's scroll */
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* The two bar layers stack in the same box. The played layer paints all bars in the accent
|
||||
colour; the unplayed layer paints an identical set in muted and is clipped to the unplayed
|
||||
portion, so the only thing that moves on seek is one clip-path inset (--played-fraction). */
|
||||
.waveform-layer {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 2px;
|
||||
padding: 0 2px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.waveform-bar {
|
||||
flex: 1;
|
||||
min-width: 2px;
|
||||
max-width: 6px;
|
||||
height: var(--bar-height, 2%);
|
||||
min-height: 2px;
|
||||
border-radius: 1px 1px 0 0;
|
||||
}
|
||||
|
||||
.waveform-layer-played .waveform-bar {
|
||||
background: var(--deepdrft-green-accent);
|
||||
}
|
||||
|
||||
.waveform-layer-unplayed {
|
||||
/* Reveal only the unplayed (right) portion; the played portion shows the accent layer beneath. */
|
||||
clip-path: inset(0 0 0 calc(var(--played-fraction, 0) * 100%));
|
||||
transition: clip-path 0.08s linear;
|
||||
}
|
||||
|
||||
.waveform-layer-unplayed .waveform-bar {
|
||||
background: var(--deepdrft-muted);
|
||||
}
|
||||
|
||||
/* Playhead rule at the split point. */
|
||||
.waveform-playhead {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: calc(var(--played-fraction, 0) * 100%);
|
||||
width: 2px;
|
||||
margin-left: -1px;
|
||||
background: var(--deepdrft-green-accent);
|
||||
pointer-events: none;
|
||||
transition: left 0.08s linear;
|
||||
}
|
||||
|
||||
/* Hover preview line — faint vertical rule under the cursor. */
|
||||
.waveform-hover-line {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
margin-left: -0.5px;
|
||||
background: var(--deepdrft-muted);
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Hover time tooltip. */
|
||||
.waveform-hover-time {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 2px);
|
||||
transform: translateX(-50%);
|
||||
padding: 1px 4px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.7rem;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
color: var(--deepdrft-white);
|
||||
background: var(--deepdrft-navy-mid);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.waveform-seeker {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user