feat(collab): presence P1 — awareness transport + who's-here roster (collab-presence 0001)
- provider.ts: expose awareness on YjsProvider (partykit/hocuspocus surface their own; BroadcastChannel gets a sibling-channel relay via awareness-bc.ts) - presence.ts: createPresence — publish local PresenceState, subscribable deduped peers() roster, setCursor/setSelection for P2, pagehide fast removal - PresenceRoster.tsx + WasmTool wiring: facepile chip next to SourceChip; eeschema rebinds per active sheet (sheet-manager ActiveSheet now carries the room's provider); config presenceUser() = slug + colorForUser - new dep y-protocols; unit tests (presence.test.ts) + e2e tests/web/presence-roster.spec.ts (two tabs, verified vs real partykit) - bump pcbjam-shared: presence-wire schema (MIT) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
This commit is contained in:
parent
6fc6a64cd0
commit
22528f450b
12 changed files with 538 additions and 15 deletions
|
|
@ -98,6 +98,7 @@ export const PROJECT_MANIFEST_URL = import.meta.env.VITE_PROJECT_MANIFEST_URL ||
|
|||
export const LOCAL_PROJECTS_ENABLED =
|
||||
import.meta.env.VITE_LOCAL_PROJECTS === "idb";
|
||||
|
||||
import { colorForUser, type PresenceUser } from "@pcbjam/shared";
|
||||
import type { ProviderConfig, ProviderKind } from "@/wasm/collab";
|
||||
import { cdnLibsSource } from "@/wasm/libs/cdn-source";
|
||||
import { cdnModelsSource, type Model3dSource } from "@/wasm/libs/models-source";
|
||||
|
|
@ -169,6 +170,17 @@ export function userSlug(): string {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The local user's presence identity (collab-presence 0001): the pre-auth slug
|
||||
* doubles as id + display name, color is the deterministic palette hash — so
|
||||
* every peer computes the same identity for this user with no coordination.
|
||||
* Real auth/avatars later replace only how this object is built.
|
||||
*/
|
||||
export function presenceUser(): PresenceUser {
|
||||
const slug = userSlug();
|
||||
return { id: slug, name: slug, color: colorForUser(slug) };
|
||||
}
|
||||
|
||||
/**
|
||||
* The active scope (first URL segment) for API calls. Mirrors how `userSlug()`
|
||||
* reads the URL, so the source layer scopes requests without threading scope
|
||||
|
|
|
|||
Loading…
Reference in a new issue