Save contact photos inline, and load cards so avatars show
Stalwart refuses a blobId in a card's media ("blobIds in media is not
supported"), so adding or changing a photo always failed. The editor now
saves the photo as a data: URI, which Stalwart accepts and returns
unchanged, and leaves the card's other media as it was. Checked live on
0.16.22; the mock now refuses a blobId the same way.
Avatars in the mail list come from the address book's cards, and nothing
loaded those at sign-in, so a photo showed only after Contacts had been
opened. The cards now load in the background at start, the avatar uses
whatever cards are held, and a shared card's photo is fetched from the
account it belongs to.
Fixes #376.
This commit is contained in:
+17
-1
@@ -1,4 +1,4 @@
|
||||
import type { ContactCard, EmailAddress, JSContactName } from "@/jmap/types";
|
||||
import type { ContactCard, EmailAddress, JSContactMedia, JSContactName } from "@/jmap/types";
|
||||
import { withBase } from "@/lib/basePath";
|
||||
|
||||
/** Best display name for a card. */
|
||||
@@ -57,6 +57,22 @@ export function contactEmails(c: ContactCard): EmailAddress[] {
|
||||
return Object.values(c.emails ?? {}).map((e) => ({ name: name.includes("@") ? null : name, email: e.address }));
|
||||
}
|
||||
|
||||
/**
|
||||
* A card's `media` with its photo replaced by `photo`, or removed when that is
|
||||
* null, and everything else in it -- a logo, a sound -- left as it was.
|
||||
*
|
||||
* The photo goes in as a `data:` URI. Stalwart (0.16.22, checked live on
|
||||
* 2026-09-16) refuses a `blobId` in `media` outright -- "blobIds in media is
|
||||
* not supported" -- which is RFC 9610's JMAP extension to JSContact, and
|
||||
* accepts the plain RFC 9553 `uri` form, returning it unchanged (#376). The
|
||||
* editor's photo is a 256px JPEG, tens of kilobytes; 134 KB was accepted.
|
||||
*/
|
||||
export function withPhoto(media: Record<string, JSContactMedia> | undefined | null, photo: { dataUrl: string; type: string } | null): Record<string, JSContactMedia> | null {
|
||||
const rest: Record<string, JSContactMedia> = Object.fromEntries(Object.entries(media ?? {}).filter(([, m]) => m.kind !== "photo"));
|
||||
if (photo) rest[newKey("p")] = { "@type": "Media", kind: "photo", uri: photo.dataUrl, mediaType: photo.type };
|
||||
return Object.keys(rest).length ? rest : null;
|
||||
}
|
||||
|
||||
export function contactPhoto(c: ContactCard, accountId: string): string | null {
|
||||
const m = Object.values(c.media ?? {}).find((x) => x.kind === "photo");
|
||||
if (!m) return null;
|
||||
|
||||
Reference in New Issue
Block a user