mirror of
https://github.com/bitwarden/browser
synced 2025-12-20 02:03:39 +00:00
[SM-251] Migrate to new avatar component (#3600)
This commit is contained in:
128
apps/desktop/src/app/components/avatar.component.ts
Normal file
128
apps/desktop/src/app/components/avatar.component.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Component, Input, OnChanges, OnInit } from "@angular/core";
|
||||
import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser";
|
||||
|
||||
import { Utils } from "@bitwarden/common/misc/utils";
|
||||
|
||||
@Component({
|
||||
selector: "app-avatar",
|
||||
template: `<img
|
||||
*ngIf="src"
|
||||
[src]="src"
|
||||
title="{{ data }}"
|
||||
[ngClass]="{ 'rounded-circle': circle }"
|
||||
/>`,
|
||||
})
|
||||
export class AvatarComponent implements OnChanges, OnInit {
|
||||
@Input() size = 45;
|
||||
@Input() charCount = 2;
|
||||
@Input() fontSize = 20;
|
||||
@Input() dynamic = false;
|
||||
@Input() circle = false;
|
||||
|
||||
@Input() color?: string;
|
||||
@Input() id?: number;
|
||||
@Input() text?: string;
|
||||
|
||||
private svgCharCount = 2;
|
||||
private svgFontWeight = 300;
|
||||
src: SafeResourceUrl;
|
||||
|
||||
constructor(public sanitizer: DomSanitizer) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.dynamic) {
|
||||
this.generate();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
if (this.dynamic) {
|
||||
this.generate();
|
||||
}
|
||||
}
|
||||
|
||||
private async generate() {
|
||||
let chars: string = null;
|
||||
const upperCaseText = this.text?.toUpperCase() ?? "";
|
||||
|
||||
chars = this.getFirstLetters(upperCaseText, this.svgCharCount);
|
||||
|
||||
if (chars == null) {
|
||||
chars = this.unicodeSafeSubstring(upperCaseText, this.svgCharCount);
|
||||
}
|
||||
|
||||
// If the chars contain an emoji, only show it.
|
||||
if (chars.match(Utils.regexpEmojiPresentation)) {
|
||||
chars = chars.match(Utils.regexpEmojiPresentation)[0];
|
||||
}
|
||||
|
||||
let svg: HTMLElement;
|
||||
let hexColor = this.color;
|
||||
|
||||
if (this.color != null) {
|
||||
svg = this.createSvgElement(this.size, hexColor);
|
||||
} else if (this.id != null) {
|
||||
hexColor = Utils.stringToColor(this.id.toString());
|
||||
svg = this.createSvgElement(this.size, hexColor);
|
||||
} else {
|
||||
hexColor = Utils.stringToColor(upperCaseText);
|
||||
svg = this.createSvgElement(this.size, hexColor);
|
||||
}
|
||||
|
||||
const charObj = this.createTextElement(chars, hexColor);
|
||||
svg.appendChild(charObj);
|
||||
const html = window.document.createElement("div").appendChild(svg).outerHTML;
|
||||
const svgHtml = window.btoa(unescape(encodeURIComponent(html)));
|
||||
this.src = this.sanitizer.bypassSecurityTrustResourceUrl(
|
||||
"data:image/svg+xml;base64," + svgHtml
|
||||
);
|
||||
}
|
||||
|
||||
private getFirstLetters(data: string, count: number): string {
|
||||
const parts = data.split(" ");
|
||||
if (parts.length > 1) {
|
||||
let text = "";
|
||||
for (let i = 0; i < count; i++) {
|
||||
text += this.unicodeSafeSubstring(parts[i], 1);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private createSvgElement(size: number, color: string): HTMLElement {
|
||||
const svgTag = window.document.createElement("svg");
|
||||
svgTag.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
||||
svgTag.setAttribute("pointer-events", "none");
|
||||
svgTag.setAttribute("width", size.toString());
|
||||
svgTag.setAttribute("height", size.toString());
|
||||
svgTag.style.backgroundColor = color;
|
||||
svgTag.style.width = size + "px";
|
||||
svgTag.style.height = size + "px";
|
||||
return svgTag;
|
||||
}
|
||||
|
||||
private createTextElement(character: string, color: string): HTMLElement {
|
||||
const textTag = window.document.createElement("text");
|
||||
textTag.setAttribute("text-anchor", "middle");
|
||||
textTag.setAttribute("y", "50%");
|
||||
textTag.setAttribute("x", "50%");
|
||||
textTag.setAttribute("dy", "0.35em");
|
||||
textTag.setAttribute("pointer-events", "auto");
|
||||
textTag.setAttribute("fill", Utils.pickTextColorBasedOnBgColor(color, 135, true));
|
||||
textTag.setAttribute(
|
||||
"font-family",
|
||||
'"Open Sans","Helvetica Neue",Helvetica,Arial,' +
|
||||
'sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"'
|
||||
);
|
||||
textTag.textContent = character;
|
||||
textTag.style.fontWeight = this.svgFontWeight.toString();
|
||||
textTag.style.fontSize = this.fontSize + "px";
|
||||
return textTag;
|
||||
}
|
||||
|
||||
private unicodeSafeSubstring(str: string, count: number) {
|
||||
const characters = str.match(/./gu);
|
||||
return characters != null ? characters.slice(0, count).join("") : "";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user