feat(04-04): wire BlockInspector into timeline and app.js

- app.js imports BlockInspector and DeleteBlockCommand
- Inspector created with #block-inspector element and timeline.history
- timeline._onSelectBlock callback shows/hides inspector on block select
- inspector._onDelete fires DeleteBlockCommand and hides inspector
- inspector.tracks kept in sync after loadTracks() resolves
- timeline.js block rendering uses blockColor + '1a' for color accent fill
- undo/redo handlers re-trigger _onSelectBlock to refresh inspector values
This commit is contained in:
Claude
2026-04-06 23:54:22 +00:00
parent e82fc4a775
commit 8e084ca8dc
2 changed files with 30 additions and 1 deletions

View File

@@ -2,6 +2,8 @@
// Browser <audio> handles playback; server receives position ticks and sends beat events
import { TimelineCanvas } from './timeline/timeline.js';
import { BlockInspector } from './timeline/inspector.js';
import { DeleteBlockCommand } from './timeline/commands.js';
const WS_URL = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/ws`;
@@ -261,9 +263,28 @@ function initTimeline() {
timeline = new TimelineCanvas(canvas, audio);
// Inspector
const inspectorEl = document.getElementById('block-inspector');
const inspector = new BlockInspector(inspectorEl, timeline.history);
inspector.tracks = timeline.tracks;
// Wire timeline selection → inspector
timeline._onSelectBlock = (block) => {
inspector.show(block);
};
// Wire inspector delete → timeline
inspector._onDelete = (block) => {
const cmd = new DeleteBlockCommand(timeline.tracks, block);
timeline.history.execute(cmd);
timeline.selectedBlock = null;
inspector.hide();
};
// Load device tracks
fetch('/api/devices').then(r => r.json()).then(devices => {
timeline.loadTracks(devices);
inspector.tracks = timeline.tracks; // keep reference in sync
}).catch(e => console.warn('[timeline]', e));
// When audio loads, fetch waveform + beats