← Commit history

Publish 1.1.2

Ray ·9de0c8a58f ·2mo ago ·parent d564e98
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}