import { TypeScale } from "../typography.slint"; // A single avatar primitive for people, accounts, and sender brands. The // caller owns the image data; this component owns circular clipping, fallback // initials, sizing, and consistent image sampling across the application. export component Avatar inherits Rectangle { in property source; in property has-source: false; in property fallback: "?"; in property size: 40px; in property background-color: #f1f1ef; in property foreground-color: #4b4c49; // Optional stable palette slot for people without stored photos. Callers // derive the slot from an identity key; Avatar owns the theme-aware muted // palette so fallback styling is not duplicated across contact surfaces. in property color-tone: -1; in property dark-mode: false; in property avatar-border-color: transparent; in property avatar-border-width: 0px; in property image-fit: cover; private property tone-background: root.dark-mode ? (root.color-tone == 0 ? #293631 : root.color-tone == 1 ? #332f3b : root.color-tone == 2 ? #382f2b : root.color-tone == 3 ? #29353b : root.color-tone == 4 ? #383529 : #2e372c) : (root.color-tone == 0 ? #dfe8e3 : root.color-tone == 1 ? #e5e1ec : root.color-tone == 2 ? #e9e1dc : root.color-tone == 3 ? #dce6ea : root.color-tone == 4 ? #e9e5d9 : #e0e7dd); private property tone-foreground: root.dark-mode ? (root.color-tone == 0 ? #a8c4b7 : root.color-tone == 1 ? #c0b3d0 : root.color-tone == 2 ? #cdb3a5 : root.color-tone == 3 ? #a9c0ca : root.color-tone == 4 ? #c9c09e : #b0c6aa) : (root.color-tone == 0 ? #455c51 : root.color-tone == 1 ? #594e68 : root.color-tone == 2 ? #675045 : root.color-tone == 3 ? #405a66 : root.color-tone == 4 ? #635b40 : #4a6145); // Initials keep at least the caption size, but shrink to fit the circle // where the platform font makes them wider than a small avatar. private property initials-size: max(TypeScale.caption, root.size * 0.29); width: root.size; height: root.size; border-radius: root.size / 2; // Downloaded rasters carry their own antialiased circular alpha mask. // Keeping the source surface transparent prevents opaque square corners // from showing through on software-rendered views. background: root.has-source ? transparent : root.color-tone >= 0 ? root.tone-background : root.background-color; clip: true; if root.has-source : Image { width: parent.width; height: parent.height; source: root.source; image-fit: root.image-fit; image-rendering: smooth; horizontal-alignment: center; vertical-alignment: center; accessible-role: none; } if !root.has-source : Rectangle { initials-measure := Text { visible: false; text: root.fallback; font-size: root.initials-size; font-weight: 700; } Text { width: parent.width; height: parent.height; text: root.fallback; color: root.color-tone >= 0 ? root.tone-foreground : root.foreground-color; font-size: root.initials-size * min(1, (root.size - 1px) / max(1px, initials-measure.preferred-width)); font-weight: 700; horizontal-alignment: center; vertical-alignment: center; overflow: elide; } } // Draw the outline after the image so full-bleed photos cannot cover it. Rectangle { width: parent.width; height: parent.height; border-radius: root.size / 2; border-width: root.avatar-border-width; border-color: root.avatar-border-color; background: transparent; } }