Commit Graph

5 Commits

Author SHA1 Message Date
David Montero Crespo 7dd9b90cf9 fix(ui): a column is a RUN of pads, not two opposite ends of the board
The Arduino Uno came out wrong: 18 pins on the top header, 13 on the bottom,
and SIX x values shared between the two. The column detector accepted any two
pads sharing an x, so those pairs were read as columns and most of the board
was thrown into the side gutters with leader lines fanning across the art.

A column now needs three pads AND small gaps between them (no more than 40%
of the body), which is what a real header looks like; rows get the same guard
on x. The Uno lands as two headers, top and bottom, with no side gutters at
all - covered by a test using its real 31-pin table.
2026-08-04 03:01:21 +02:00
David Montero Crespo 4be8ddd6c3 fix(ui): a pin stack taller than the part was clipped by the preview
The ReSpeaker's left side carries 13 labels: at the minimum spacing that is
208px against a 190px body, so the column ran past both ends and the first
and last labels were cut off by the preview's clip. The gutters now grow to
whatever the labels actually occupy - the box follows the content.
2026-08-03 23:20:49 +02:00
David Montero Crespo cbc74d8409 fix(ui): the inspector dropped labels for inset pin columns, and flickered
Three things the dialog got wrong in use:

1. Missing pins. Classification was nearest-edge with an "interior" bucket,
   and interior pins printed no label - only a dot with a tooltip. The
   ReSpeaker Lite showed it: its XIAO socket is two INSET columns (x=50.5 and
   126.5 on a 178-wide body) plus two breakout columns, so most of its pins
   were called interior and the part looked like it was missing them. The
   classifier now finds the LINES first - pins sharing an x are a column,
   pins sharing a y a row - assigns each line to the side of the body it sits
   on however far inset it is, and joins label to dot with a leader. Only a
   lone pad falls back to nearest-edge. Every pin gets a printed label; that
   is now the contract, covered by a ReSpeaker test with its real table.

2. The panel was cut off on the Datasheet tab until some unrelated event
   re-rendered it. The datasheet loads asynchronously, so the one-shot
   measure placed the dialog while it was still short and it then grew off
   screen. A ResizeObserver repositions on any size change, and the tab body
   caps its own height so long markdown scrolls inside the tab.

3. Flicker when the pointer left and re-entered. The preview effect depended
   on componentProperties and pinInfo by identity - both are rebuilt on every
   parent render (pinInfo is a getter) - so the element was torn down and
   remounted constantly. It now depends on stable digests of them.
2026-08-03 23:04:37 +02:00
David Montero Crespo b02aab9a47 fix(ui): crowded pin headers escaped the inspector - draw those labels vertically
An SSD1306 has 8 pins along a 240px header. Horizontal labels need ~36px
each = 288px, so they overflowed the art box and rendered outside the dialog,
over the header and the canvas. Top/bottom labels are now vertical text - what
printed pinout diagrams do - which needs only the side spacing, and the gutter
grows to fit. The preview also clips, so nothing can escape again.
2026-08-03 22:04:43 +02:00
David Montero Crespo d4a42a4e75 feat(ui): the Part Inspector - right-click dialog merged with the picker card
The right-click dialog was a 250px column: every pin as a text row (an ESP32
means 30 rows of scrolling), a few editors, Rotate/Delete. The picker's info
card (datasheet, brand, Buy) was a separate surface you could only reach by
hovering the catalogue. One dialog now serves both:

- ~560px, two panes: live preview + actions on the left, Properties/Datasheet
  tabs on the right. The Datasheet tab IS the picker card's body -
  ComponentInfoPanel was split into an embeddable ComponentInfoBody (+
  useComponentDoc, and its .cip-* styles moved to their own stylesheet) so
  both surfaces render one implementation.
- "Show pins" (off by default): the preview is the REAL web component,
  mounted and scaled, with pin markers at their true pinInfo positions and
  labels flanking the side each pin lives on. pinInspectorLayout is pure
  geometry - nearest-edge classification, per-side label stacking with a
  minimum spacing and leader lines when nudged, interior pins as
  dot+tooltip - driven only by pinInfo plus the measured element size, so
  every part and board, present or future, works with no per-part data.
  Dots are tinted by the pin's declared signal (i2c/spi/power/...).
- Clicking a pin keeps the old contract (onPinSelect -> handlePinClick), so
  wires start with the same undo, colors and running-state gating.
- The two open gestures finally agree on coordinates: right-click always
  passed viewport coords while touch passed canvas-local ones; the dialog is
  now portaled to body in viewport space and the touch site converts.
- Keybind capture, the SD Card panel, the two-step delete, Escape and
  click-outside all migrate unchanged. Mobile keeps the full-sheet layout.

Geometry covered by pin-inspector-layout.test.ts with coordinate tables
copied verbatim from the shipped parts (ESP32 two-column board, LED, an
interior-pin case).
2026-08-03 21:44:46 +02:00