feat: sectioned toolbar + custom component editor
- Redesigned toolbar with I/O, Gates, and Components sections - Component editor: sub-canvas mode to design reusable chips - Save/Cancel with main circuit state preservation - Components persist in localStorage - Custom components render as purple chips with dynamic I/O ports - Component evaluation simulates internal circuit as black box - Toolbar height increased to 56px for section labels - All height references updated consistently Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,12 @@
|
||||
import { state } from './state.js';
|
||||
import { GATE_W, GATE_H } from './constants.js';
|
||||
|
||||
// Avoid circular imports - resize will be called from events.js
|
||||
let resizeCallback = null;
|
||||
export function setResizeCallback(fn) {
|
||||
resizeCallback = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save current circuit as a reusable component
|
||||
* Returns the component ID if successful
|
||||
@@ -204,3 +210,79 @@ export function importComponent(data) {
|
||||
state.customComponents[data.id] = data;
|
||||
return { success: true, component: data };
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter component editor mode
|
||||
*/
|
||||
export function enterComponentEditor() {
|
||||
// Save current main circuit
|
||||
state.savedMainCircuit = {
|
||||
gates: JSON.parse(JSON.stringify(state.gates)),
|
||||
connections: JSON.parse(JSON.stringify(state.connections)),
|
||||
nextId: state.nextId
|
||||
};
|
||||
|
||||
// Clear canvas for sub-circuit design
|
||||
state.gates = [];
|
||||
state.connections = [];
|
||||
state.nextId = 1;
|
||||
state.componentEditorActive = true;
|
||||
state.placingGate = null;
|
||||
state.connecting = null;
|
||||
|
||||
// Show editor overlay
|
||||
const overlay = document.getElementById('component-editor-overlay');
|
||||
overlay.style.display = 'flex';
|
||||
document.getElementById('component-editor-title').textContent = 'Editing Component: (New)';
|
||||
|
||||
// Resize canvas to account for editor bar
|
||||
if (resizeCallback) resizeCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit component editor mode
|
||||
*/
|
||||
export function exitComponentEditor(name, shouldSave) {
|
||||
const overlay = document.getElementById('component-editor-overlay');
|
||||
overlay.style.display = 'none';
|
||||
|
||||
if (shouldSave && name) {
|
||||
// Save the component
|
||||
saveComponentFromCircuit(name);
|
||||
}
|
||||
|
||||
// Restore main circuit
|
||||
if (state.savedMainCircuit) {
|
||||
state.gates = state.savedMainCircuit.gates;
|
||||
state.connections = state.savedMainCircuit.connections;
|
||||
state.nextId = state.savedMainCircuit.nextId;
|
||||
state.savedMainCircuit = null;
|
||||
}
|
||||
|
||||
state.componentEditorActive = false;
|
||||
state.placingGate = null;
|
||||
|
||||
// Update component buttons to show newly saved component
|
||||
updateComponentButtons();
|
||||
|
||||
// Resize canvas via callback
|
||||
if (resizeCallback) resizeCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update component buttons in toolbar
|
||||
*/
|
||||
export function updateComponentButtons() {
|
||||
const container = document.getElementById('saved-components');
|
||||
container.innerHTML = '';
|
||||
|
||||
const components = getAllComponents();
|
||||
Object.values(components).forEach(comp => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'component-btn';
|
||||
btn.dataset.componentId = comp.id;
|
||||
btn.textContent = comp.name;
|
||||
btn.title = `${comp.inputCount} input(s), ${comp.outputCount} output(s)`;
|
||||
container.appendChild(btn);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user