Files
mc-webui/app/static/css
MarekWoandClaude Opus 5 2acf6f9f3a feat(chat): render shared contacts, channels and positions as cards
MeshCore clients share contacts, channels and positions as plain text in
ordinary chat messages. Until now those arrived as unreadable raw tokens.
They now render as interactive cards in both the channel chat and DMs.

Three wire formats, none of them ours to choose — they are what the
official app emits, so share-tokens.js stays byte-compatible with it:

  contact   <64-hex-pubkey:type:name>   (compact, not a URI)
  channel   meshcore://channel/add?name=&secret=&region_scope=
  location  bare "lat,lon"

The contact URI form is parsed too (QR codes carry it) but never emitted:
with a name like "MarWoj 💡📱 mobile" it costs 153 bytes and cannot fit a
135-byte channel packet, where the compact token needs 91.

Parsing runs BEFORE HTML escaping, leaving private-use-area placeholders
that the later passes cannot match. Tokens do not survive the existing
pipeline otherwise: escaping breaks a URI's '&', processChannelLinks eats
a '#channel' name, processMentions an '@' in a contact name, and the
token's closing '>' collides with quote syntax.

Cards resolve their action before rendering, so the button states what
will actually happen rather than surprising the user afterwards:
  contact  Add / Update name to X / Already in contacts / Push to device
  channel  Add / Already joined / Name used by a different key
The public key is the identity — a known key under a new name is a
rename, never a second contact.

Shared contacts land in the local cache rather than device memory:
they arrive unsolicited and contact slots are limited, so promotion stays
deliberate. The card offers it inline once cached, so it costs one click
rather than a trip to the Contacts panel. New: manual-add accepts
target=cache, which needs no device connection.

Location cards add distance and bearing from our own advertised position,
plus map/copy/external-map actions. A shared channel's region scope is
carried over on join, since transmitting under the firmware default would
not match the sender.

Coordinate detection is deliberately narrow — both numbers need 3+
decimals, ranges are checked, and matches inside URLs are skipped — so
prose like "1,5 osoby" or "wersja 2,10" and Google Maps links are left
alone.

Verified against real payloads received from another device on #mcwebui,
covering all three formats plus a contact URI and emoji names: 65 parser
assertions, 57 render assertions, i18n check clean at pl 100%, and both
themes screenshotted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 10:57:26 +02:00
..