app
Component Widgets
Public Made by Adomby adom
Reusable component widgets for pinouts, thermal vias, molecule relationships, reviewed chip outlines and lightweight four-level LOD cache listings.
← Commit history
Publish 1.1.2
3 files changed
+31−9
package.json+1−1@@ -2,7 +2,7 @@ "slug": "component-widgets", "title": "Component Widgets", "type": "app",- "version": "1.1.1",+ "version": "1.1.2", "description": "Reusable, dependency-free web-component widgets to drop into any component or molecule page: <adom-pinout> (datasheet-style pin diagram + synced table), <adom-heatsink-via> (exposed-pad thermal via array, only when the part has an EP), <adom-molecule> (ganged part set + nets), and <adom-chip-thumbnail> (rendered part image). Each is one custom element, self-contained (Shadow DOM, no deps), theme-aware (light + dark), fed by inline JSON or el.data, and all on one lbr-hover cross-highlight bus so a pin hovered in one lights the same pin everywhere. Symbol, footprint, and 3D stay with adom-lbr; the datasheet renders via the native viewer. Installs the widget JS, iframe-embeddable viewers, example data, and an AI skill to ~/.claude/skills/component-widgets. Live reference page renders them all as a readme.html.", "license": "MIT", "dependencies": {},
page.json+2−2@@ -3,8 +3,8 @@ "slug": "component-widgets", "type": "app", "title": "Component Widgets",- "brief": "One home for the reusable, readme-instantiable component/molecule widgets (pinout, heat-sink via, chip thumbnail, molecule) \u2014 self-contained web components on the shared adom-lbr hover bus.",- "version": "1.1.1",+ "brief": "One home for the reusable, readme-instantiable component/molecule widgets (pinout, heat-sink via, chip thumbnail, molecule) — self-contained web components on the shared adom-lbr hover bus.",+ "version": "1.1.2", "visibility": "private", "author": { "name": "Ray",
skills/component-widgets/widgets/moleculize-widget.js+28−6@@ -195,15 +195,36 @@ const input = root.querySelector('[data-file]'); if (!input) return; input.onchange = () => { if (input.files && input.files[0]) this._loadFile(input.files[0]); };- const drop = root.querySelector('[data-drop]');- if (drop) {- drop.onclick = () => input.click();- drop.ondragover = e => { e.preventDefault(); drop.classList.add('over'); };- drop.ondragleave = () => drop.classList.remove('over');- drop.ondrop = e => { e.preventDefault(); drop.classList.remove('over'); const f = e.dataTransfer && e.dataTransfer.files[0]; if (f) this._loadFile(f); };++ // Accept a dropped .kicad_pcb ANYWHERE on the card — in the empty drop-zone+ // AND once a board is loaded. Without this, a drop on the loaded widget falls+ // through to the browser, which just opens the file in a new tab.+ const card = root.querySelector('.card');+ if (card) {+ const over = e => { e.preventDefault(); e.stopPropagation(); if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy'; card.classList.add('over'); };+ card.addEventListener('dragenter', over);+ card.addEventListener('dragover', over);+ card.addEventListener('dragleave', e => { if (!card.contains(e.relatedTarget)) card.classList.remove('over'); });+ card.addEventListener('drop', e => {+ e.preventDefault(); e.stopPropagation(); card.classList.remove('over');+ const f = e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files[0];+ if (f) this._loadFile(f);+ }); }+ // Click affordances: the empty drop zone opens the picker; so does the swap.+ const drop = root.querySelector('[data-drop]');+ if (drop) drop.onclick = () => input.click(); const swap = root.querySelector('[data-swap]'); if (swap) swap.onclick = e => { e.stopPropagation(); input.click(); };++ // Belt-and-braces: stop the browser navigating to a file dropped just OUTSIDE+ // the card (the sandboxed readme otherwise opens it in a new tab). Bound once.+ if (typeof window !== 'undefined' && !window.__adomMoleculizeNoOpen) {+ window.__adomMoleculizeNoOpen = true;+ const prevent = e => { e.preventDefault(); };+ window.addEventListener('dragover', prevent, false);+ window.addEventListener('drop', prevent, false);+ } } _css() {@@ -215,6 +236,7 @@ :host([theme="dark"]){--bg:#0d1420;--panel:#121a26;--line:#26324a;--line2:#33425f;--text:#dbe2ec;--dim:#8b97ac;--dim2:#66738c;--accent:#00e6dc;--wing:rgba(0,214,204,.07);--board:#2b3a52;--boardln:#4c9dff;--mp:#ffb454;--grid:#2a3651} *{box-sizing:border-box} .card{background:var(--bg);border:1px solid var(--line);border-radius:14px;padding:16px;color:var(--text);font:14px/1.5 -apple-system,'Segoe UI',Roboto,Arial,sans-serif}+ .card.over{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)} .hd{display:flex;align-items:baseline;gap:10px;margin-bottom:12px} .hd .t{font:700 16px ui-monospace,'SF Mono',Menlo,monospace} .hd .badge{font:700 10px ui-monospace,monospace;letter-spacing:.06em;color:var(--accent);background:color-mix(in srgb,var(--accent) 12%,transparent);border:1px solid color-mix(in srgb,var(--accent) 30%,transparent);padding:2px 8px;border-radius:6px}