Squashed 'vendor/ruvector/' content from commit b64c2172

git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
commit d803bfe2b1
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
type ChangeCallback = (epoch: number) => void;
export class TimeScrubber {
private root: HTMLElement;
private slider: HTMLInputElement;
private display: HTMLElement;
private changeCallback: ChangeCallback | null = null;
constructor(container: HTMLElement) {
this.root = document.createElement('div');
this.root.className = 'time-scrubber';
const label = document.createElement('span');
label.className = 'time-scrubber-title';
label.textContent = 'Epoch';
this.root.appendChild(label);
this.slider = document.createElement('input');
this.slider.type = 'range';
this.slider.className = 'time-scrubber-range';
this.slider.min = '0';
this.slider.max = '100';
this.slider.value = '0';
this.slider.addEventListener('input', () => this.handleChange());
this.root.appendChild(this.slider);
this.display = document.createElement('span');
this.display.className = 'time-scrubber-label';
this.display.textContent = 'E0';
this.root.appendChild(this.display);
container.appendChild(this.root);
}
setRange(min: number, max: number): void {
this.slider.min = String(min);
this.slider.max = String(max);
const val = Number(this.slider.value);
if (val < min) this.slider.value = String(min);
if (val > max) this.slider.value = String(max);
this.updateDisplay();
}
setValue(epoch: number): void {
this.slider.value = String(epoch);
this.updateDisplay();
}
onChange(callback: ChangeCallback): void {
this.changeCallback = callback;
}
private handleChange(): void {
this.updateDisplay();
this.changeCallback?.(Number(this.slider.value));
}
private updateDisplay(): void {
this.display.textContent = `E${this.slider.value}`;
}
destroy(): void {
this.root.remove();
}
}