// BlockInspector — compact horizontal strip for editing selected block params // Appears between timeline canvas and transport bar when a block is selected. // All parameter changes go through UpdateParamsCommand for full undo/redo support. import { UpdateParamsCommand } from './commands.js'; export class BlockInspector { constructor(containerEl, history) { this.el = containerEl; // #block-inspector div this.history = history; // CommandHistory reference this.tracks = null; // set by app.js from timeline.tracks this.currentBlock = null; this._onDelete = null; // callback(block) — set by app.js } show(block) { this.currentBlock = block; if (!block) { this.el.style.display = 'none'; return; } this.el.style.display = 'flex'; this._render(block); } hide() { this.currentBlock = null; this.el.style.display = 'none'; } _render(block) { const animName = (block.animation || 'BLOCK').toUpperCase().replace(/_/g, ' '); const color = block.params?.color || '#00ffff'; const speed = block.params?.speed ?? 1.0; const direction = block.params?.direction || 'forward'; const length = block.params?.length ?? 0.3; this.el.innerHTML = ` ${animName}
`; this._wireEvents(block); } _wireEvents(block) { // Color swatch → open hidden color input const swatch = this.el.querySelector('#color-swatch'); const colorInput = this.el.querySelector('#inspector-color'); swatch?.addEventListener('click', () => colorInput?.click()); // Live preview: update swatch as color drags colorInput?.addEventListener('input', (e) => { swatch.style.background = e.target.value; }); // Commit on change (not during drag — avoids command flood) colorInput?.addEventListener('change', (e) => { const oldParams = { ...block.params }; const newParams = { ...block.params, color: e.target.value }; const cmd = new UpdateParamsCommand(this.tracks, block, oldParams, newParams); this.history.execute(cmd); }); // Speed this.el.querySelector('#inspector-speed')?.addEventListener('change', (e) => { const val = parseFloat(e.target.value); if (isNaN(val) || val < 0.1 || val > 10) return; const oldParams = { ...block.params }; const newParams = { ...block.params, speed: val }; const cmd = new UpdateParamsCommand(this.tracks, block, oldParams, newParams); this.history.execute(cmd); }); // Direction this.el.querySelector('#inspector-direction')?.addEventListener('change', (e) => { const oldParams = { ...block.params }; const newParams = { ...block.params, direction: e.target.value }; const cmd = new UpdateParamsCommand(this.tracks, block, oldParams, newParams); this.history.execute(cmd); }); // Length this.el.querySelector('#inspector-length')?.addEventListener('change', (e) => { const val = parseFloat(e.target.value); if (isNaN(val) || val < 0.05 || val > 1) return; const oldParams = { ...block.params }; const newParams = { ...block.params, length: val }; const cmd = new UpdateParamsCommand(this.tracks, block, oldParams, newParams); this.history.execute(cmd); }); // Remove button this.el.querySelector('.inspector-remove')?.addEventListener('click', () => { if (this._onDelete) this._onDelete(block); }); } }