feat(comments): figma-like comment pins + threads (collab-presence 0005)

Hybrid pins: the wasm draws the dot (kicadCollabSetPins rides the presence
VIEW_OVERLAY, author color + white ring, drawn above selections; zero
kicad-fork changes), the DOM owns interaction —
- comments.ts: controller gluing the MIT kdoc_comments helpers to the editor:
  anchor resolution per tool IU (pins track item moves via kdoc_items
  observation), throttled pin snapshots, anchorAt nearest-item snap, jumpTo
  via new kicadCollabSetViewport; rebinds per sheet like presence.
- CommentLayer.tsx: comment mode (click catcher + composer), pin hit targets
  over the GAL dots, thread popover (reply/edit/delete own, resolve/reopen,
  delete thread), panel with resolved filter + jump-to (popover centers when
  the pin is off-screen). Resolved pins drop figma-style.
- WasmTool: controller lifecycle beside presence; live viewport feed;
  window.__pcbjamComments test handle (threads persist in the room ydoc).
- e2e tests/web/comments.spec.ts: two-tab create → reply → resolve → panel
  filter → delete, passing vs real partykit; presence suites + collab units
  stay green; shared pointer bump (0004 model).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
This commit is contained in:
Gergő Törcsvári 2026-07-06 17:50:11 +02:00
commit 635aa2926a
No known key found for this signature in database
GPG key ID: 8E75F2CDE64E5322
8 changed files with 997 additions and 4 deletions

View file

@ -45,9 +45,11 @@ std::string pcbCollabTestMoveFirst( int aDx, int aDy );
std::string pcbCollabGetPos( std::string aId );
bool pcbCollabTestRemoveItem( std::string aId );
bool pcbCollabTestRotateItem( std::string aId, double aDeg );
// Presence (collab-presence 0002) — pcbnew only until 0003 adds the sch side.
// Presence (collab-presence 0002) + comment pins/panning (0005).
void pcbCollabPresenceStart();
void pcbCollabSetRemote( std::string aJson );
void pcbCollabSetPins( std::string aJson );
void pcbCollabSetViewport( double aCx, double aCy );
std::string pcbCollabGetViewport();
std::string pcbCollabGetSelection();
std::string pcbCollabTestSelectFirst();
@ -62,9 +64,11 @@ std::string schCollabTestMoveFirst( int aDx, int aDy );
std::string schCollabGetPos( std::string aId );
bool schCollabTestRemoveItem( std::string aId );
bool schCollabTestRotateItem( std::string aId, double aDeg );
// Presence (collab-presence 0003 — eeschema counterparts of the 0002 set).
// Presence (collab-presence 0003 — eeschema counterparts) + pins (0005).
void schCollabPresenceStart();
void schCollabSetRemote( std::string aJson );
void schCollabSetPins( std::string aJson );
void schCollabSetViewport( double aCx, double aCy );
std::string schCollabGetViewport();
std::string schCollabGetSelection();
std::string schCollabTestSelectFirst();
@ -159,6 +163,16 @@ static void collabSetRemote( std::string aJson )
pcbEditorActive() ? pcbCollabSetRemote( aJson ) : schCollabSetRemote( aJson );
}
static void collabSetPins( std::string aJson )
{
pcbEditorActive() ? pcbCollabSetPins( aJson ) : schCollabSetPins( aJson );
}
static void collabSetViewport( double aCx, double aCy )
{
pcbEditorActive() ? pcbCollabSetViewport( aCx, aCy ) : schCollabSetViewport( aCx, aCy );
}
static std::string collabGetViewport()
{
return pcbEditorActive() ? pcbCollabGetViewport() : schCollabGetViewport();
@ -196,9 +210,11 @@ EMSCRIPTEN_BINDINGS(kicad_editor) {
// endpoint, field text — flow from the per-editor blocks unchanged).
function("kicadCollabTestRemoveItem", &collabTestRemoveItem);
function("kicadCollabTestRotateItem", &collabTestRotateItem);
// Presence (collab-presence 0002).
// Presence (collab-presence 0002/0003) + comment pins/panning (0005).
function("kicadCollabPresenceStart", &collabPresenceStart);
function("kicadCollabSetRemote", &collabSetRemote);
function("kicadCollabSetPins", &collabSetPins);
function("kicadCollabSetViewport", &collabSetViewport);
function("kicadCollabGetViewport", &collabGetViewport);
function("kicadCollabGetSelection", &collabGetSelection);
function("kicadCollabTestSelectFirst", &collabTestSelectFirst);