Fixed manual image stitching and Inspector view for mobiles, other minor fixes/improvements.
This commit is contained in:
parent
55e55edee9
commit
ca9fe52db5
10 changed files with 803 additions and 618 deletions
170
docs/nets.js
170
docs/nets.js
|
|
@ -5,62 +5,71 @@ class NetManager {
|
|||
this.db = db;
|
||||
}
|
||||
|
||||
async render() {
|
||||
const tbody = document.getElementById('nets-body');
|
||||
if(!tbody) return;
|
||||
async render() {
|
||||
const tbody = document.getElementById('nets-body');
|
||||
if(!tbody) return;
|
||||
|
||||
tbody.innerHTML = '<tr><td colspan="3" style="text-align:center; color:#888;">Loading...</td></tr>';
|
||||
|
||||
const nets = await this.db.getNets();
|
||||
tbody.innerHTML = '';
|
||||
|
||||
if(nets.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="3" style="text-align:center; padding:2rem; color:#94a3b8;">No nets defined. Go to "Inspect" to create one.</td></tr>';
|
||||
return;
|
||||
}
|
||||
// Safety check: If no board is loaded, clear the table
|
||||
if (typeof currentBomId === 'undefined' || !currentBomId) {
|
||||
tbody.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
nets.forEach(net => {
|
||||
const tr = document.createElement('tr');
|
||||
|
||||
tr.style.height = 'auto';
|
||||
tr.style.minHeight = '2.2rem';
|
||||
tbody.innerHTML = '<tr><td colspan="3" style="text-align:center; color:#888;">Loading...</td></tr>';
|
||||
|
||||
// Target Icon for Editing
|
||||
const targetIcon = `<span style="cursor:pointer; margin-right:0.5rem;" onclick="netManager.editNet('${net.id}')" title="Edit Net on Board">🎯</span>`;
|
||||
const allNets = await this.db.getNets();
|
||||
|
||||
let nodesHtml = '';
|
||||
net.nodes.forEach((n, idx) => {
|
||||
nodesHtml += `<span class="net-chip" onclick="netManager.editNode('${net.id}', ${idx})" title="Edit Node">${n.label}</span>`;
|
||||
});
|
||||
|
||||
tr.innerHTML = `
|
||||
<td style="display:flex; align-items:center; vertical-align:top; height:auto;">
|
||||
${targetIcon}
|
||||
<input type="text" value="${net.name}" onchange="netManager.rename('${net.id}', this.value)" style="border:none; background:transparent; font-weight:bold; flex:1; min-width:0;">
|
||||
</td>
|
||||
|
||||
<!-- [FIX] Allow cell to expand freely -->
|
||||
<td style="white-space:normal; height:auto; overflow:visible;">
|
||||
<div style="display:flex; flex-wrap:wrap; gap:4px; padding:2px 0;">${nodesHtml}</div>
|
||||
</td>
|
||||
|
||||
<td style="text-align:right; vertical-align:top; height:auto;">
|
||||
<button class="danger sm-btn" onclick="netManager.delete('${net.id}')" title="Delete Net">🗑️</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
}
|
||||
// --- FIX: Filter by Current Board ID ---
|
||||
const nets = allNets.filter(n => n.projectId === currentBomId);
|
||||
|
||||
// Edit Net in Inspector
|
||||
async editNet(id) {
|
||||
const net = await this.db._tx('nets', 'readonly', s => s.get(id));
|
||||
if(net) {
|
||||
switchView('inspect');
|
||||
// We use the global inspector instance
|
||||
if(window.inspector) window.inspector.loadNet(net);
|
||||
}
|
||||
}
|
||||
tbody.innerHTML = '';
|
||||
|
||||
if(nets.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="3" style="text-align:center; padding:2rem; color:#94a3b8;">No nets defined. Go to "Inspect" to create one.</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
nets.forEach(net => {
|
||||
const tr = document.createElement('tr');
|
||||
|
||||
tr.style.height = 'auto';
|
||||
tr.style.minHeight = '2.2rem';
|
||||
|
||||
// Target Icon for Editing
|
||||
const targetIcon = `<span style="cursor:pointer; margin-right:0.5rem;" onclick="netManager.editNet('${net.id}')" title="Edit Net on Board">🎯</span>`;
|
||||
|
||||
let nodesHtml = '';
|
||||
net.nodes.forEach((n, idx) => {
|
||||
nodesHtml += `<span class="net-chip" onclick="netManager.editNode('${net.id}', ${idx})" title="Edit Node">${n.label}</span>`;
|
||||
});
|
||||
|
||||
tr.innerHTML = `
|
||||
<td style="display:flex; align-items:center; vertical-align:top; height:auto;">
|
||||
${targetIcon}
|
||||
<input type="text" value="${net.name}" onchange="netManager.rename('${net.id}', this.value)" style="border:none; background:transparent; font-weight:bold; flex:1; min-width:0;">
|
||||
</td>
|
||||
|
||||
<td style="white-space:normal; height:auto; overflow:visible;">
|
||||
<div style="display:flex; flex-wrap:wrap; gap:4px; padding:2px 0;">${nodesHtml}</div>
|
||||
</td>
|
||||
|
||||
<td style="text-align:right; vertical-align:top; height:auto;">
|
||||
<button class="danger sm-btn" onclick="netManager.delete('${net.id}')" title="Delete Net">🗑️</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
}
|
||||
|
||||
// Edit Net in Inspector
|
||||
async editNet(id) {
|
||||
const net = await this.db._tx('nets', 'readonly', s => s.get(id));
|
||||
if(net) {
|
||||
switchView('inspect');
|
||||
// We use the global inspector instance
|
||||
if(window.inspector) window.inspector.loadNet(net);
|
||||
}
|
||||
}
|
||||
|
||||
// Edit individual node
|
||||
async editNode(netId, nodeIdx) {
|
||||
|
|
@ -68,20 +77,17 @@ class NetManager {
|
|||
if(!net || !net.nodes[nodeIdx]) return;
|
||||
|
||||
const node = net.nodes[nodeIdx];
|
||||
// Simple action menu via Prompt/Confirm
|
||||
// 1. Ask for new name (Empty = Delete)
|
||||
const newName = prompt(`Edit node "${node.label}"\n\nEnter new name to Rename.\nClear text and press OK to Delete.`, node.label);
|
||||
|
||||
if(newName === null) return; // Cancelled
|
||||
|
||||
if(newName.trim() === '') {
|
||||
if(confirm("Delete this node?")) {
|
||||
net.nodes.splice(nodeIdx, 1);
|
||||
await this.db.addNet(net);
|
||||
this.render();
|
||||
}
|
||||
} else {
|
||||
net.nodes[nodeIdx].label = newName.trim();
|
||||
const res = await requestInput("Edit Node", "Node Name", node.label, {
|
||||
extraBtn: { label: 'Delete', value: '__DELETE__', class: 'danger' }
|
||||
});
|
||||
|
||||
if (res === '__DELETE__') {
|
||||
net.nodes.splice(nodeIdx, 1);
|
||||
await this.db.addNet(net);
|
||||
this.render();
|
||||
} else if (res) {
|
||||
net.nodes[nodeIdx].label = res;
|
||||
await this.db.addNet(net);
|
||||
this.render();
|
||||
}
|
||||
|
|
@ -125,10 +131,10 @@ class NetManager {
|
|||
'L': { lib: "Device", part: "L", desc: "Inductor" },
|
||||
'D': { lib: "Device", part: "D", desc: "Diode" },
|
||||
'TP': { lib: "Connector", part: "TestPoint", desc: "Test Point" },
|
||||
|
||||
|
||||
// --- AMBIGUOUS TYPES (Disabled by default) ---
|
||||
// 'Q': { lib: "Device", part: "Q_NPN_BEC", desc: "Transistor NPN" }, // Risk: Could be PNP, MOSFET, IGBT
|
||||
// 'J': { lib: "Connector", part: "Conn_01x02_Male", desc: "Connector" }, // Risk: Pin count unknown
|
||||
// 'Q': { lib: "Device", part: "Q_NPN_BEC", desc: "Transistor NPN" }, // Risk: Could be PNP, MOSFET, IGBT
|
||||
// 'J': { lib: "Connector", part: "Conn_01x02_Male", desc: "Connector" }, // Risk: Pin count unknown
|
||||
// 'CN': { lib: "Connector", part: "Conn_01x02_Male", desc: "Connector" }, // Risk: Pin count unknown
|
||||
};
|
||||
|
||||
|
|
@ -140,44 +146,44 @@ class NetManager {
|
|||
const val = c.value ? c.value : "~";
|
||||
const footprint = c.desc ? c.desc.replace(/"/g, '') : "";
|
||||
const tstamp = c.id ? c.id.substring(0, 8) : Math.floor(Math.random()*10000000).toString(16);
|
||||
|
||||
|
||||
// Detect Type from Prefix
|
||||
const prefix = (c.label.match(/^[A-Z]+/) || [""])[0].toUpperCase();
|
||||
|
||||
|
||||
// Lookup Library definition
|
||||
// Future TODO: Add logic here to check c.desc for keywords like "NPN", "MOSFET", etc.
|
||||
const def = COMPONENT_LIBRARY_MAP[prefix];
|
||||
|
||||
out += ` (comp (ref "${c.label}")\n`;
|
||||
out += ` (value "${val}")\n`;
|
||||
if(footprint) out += ` (footprint "${footprint}")\n`;
|
||||
|
||||
out += ` (comp (ref "${c.label}")\n`;
|
||||
out += ` (value "${val}")\n`;
|
||||
if(footprint) out += ` (footprint "${footprint}")\n`;
|
||||
|
||||
// Inject Library Source if we have a safe definition
|
||||
if(def) {
|
||||
out += ` (libsource (lib "${def.lib}") (part "${def.part}") (description "${def.desc}"))\n`;
|
||||
out += ` (property (name "Sheetname") (value "")) (property (name "Sheetfile") (value "${filename}.kicad_sch"))\n`;
|
||||
out += ` (libsource (lib "${def.lib}") (part "${def.part}") (description "${def.desc}"))\n`;
|
||||
out += ` (property (name "Sheetname") (value "")) (property (name "Sheetfile") (value "${filename}.kicad_sch"))\n`;
|
||||
}
|
||||
|
||||
out += ` (tstamp "${tstamp}")\n`;
|
||||
out += ` )\n`;
|
||||
|
||||
out += ` (tstamp "${tstamp}")\n`;
|
||||
out += ` )\n`;
|
||||
});
|
||||
out += " )\n";
|
||||
|
||||
// 3. Export Nets
|
||||
out += " (nets\n";
|
||||
nets.forEach((net, i) => {
|
||||
out += ` (net (code ${i+1}) (name "${net.name}")\n`;
|
||||
out += ` (net (code ${i+1}) (name "${net.name}")\n`;
|
||||
net.nodes.forEach(node => {
|
||||
const parts = node.label.split('.');
|
||||
if(parts.length === 2) {
|
||||
// Format: R1.2 (Ref R1, Pin 2)
|
||||
out += ` (node (ref "${parts[0]}") (pin "${parts[1]}"))\n`;
|
||||
out += ` (node (ref "${parts[0]}") (pin "${parts[1]}"))\n`;
|
||||
} else {
|
||||
// Fallback: TestPoints or direct names often use Pin 1
|
||||
out += ` (node (ref "${node.label}") (pin "1"))\n`;
|
||||
out += ` (node (ref "${node.label}") (pin "1"))\n`;
|
||||
}
|
||||
});
|
||||
out += " )\n";
|
||||
out += " )\n";
|
||||
});
|
||||
out += " )\n)\n";
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue