From 5f6f4bad82928822f3cd7184902af93bdfc74d0a Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Thu, 27 Oct 2022 14:38:34 +0200 Subject: [PATCH] [SM-251] Migrate to new avatar component (#3600) --- .../src/app/components/avatar.component.ts | 128 ++++++++++++++++++ .../layout/account-switcher.component.html | 14 +- .../app/layout/account-switcher.component.ts | 59 +++++--- apps/desktop/src/app/shared/shared.module.ts | 3 + .../organization-switcher.component.html | 7 +- .../web/src/app/layouts/navbar.component.html | 8 +- apps/web/src/app/layouts/navbar.component.ts | 2 + .../manage/bulk/bulk-confirm.component.html | 27 +--- .../manage/bulk/bulk-remove.component.html | 18 +-- .../bulk/bulk-restore-revoke.component.html | 18 +-- .../manage/bulk/bulk-status.component.html | 12 +- .../manage/entity-users.component.html | 9 +- .../manage/people.component.html | 9 +- .../settings/account.component.html | 2 +- .../app/providers/providers.component.html | 2 +- .../settings/emergency-access.component.html | 18 +-- .../app/settings/preferences.component.html | 23 ---- .../src/app/settings/preferences.component.ts | 3 - .../src/app/settings/profile.component.html | 9 +- apps/web/src/app/shared/shared.module.ts | 7 +- apps/web/src/locales/en/messages.json | 7 - apps/web/webpack.config.js | 1 - .../clients/add-organization.component.html | 2 +- .../providers/clients/clients.component.html | 7 +- .../providers/manage/people.component.html | 9 +- .../providers/providers-layout.component.html | 2 +- .../providers/settings/account.component.html | 2 +- .../src/components/avatar.component.ts | 127 ----------------- libs/angular/src/jslib.module.ts | 3 - .../logInStrategies/logIn.strategy.spec.ts | 3 + libs/common/src/abstractions/state.service.ts | 2 - .../misc/logInStrategies/logIn.strategy.ts | 1 + libs/common/src/models/domain/account.ts | 2 +- libs/common/src/services/state.service.ts | 21 --- .../src/services/stateMigration.service.ts | 4 - .../components/src/avatar/avatar.component.ts | 12 +- libs/components/src/index.ts | 7 +- 37 files changed, 230 insertions(+), 360 deletions(-) create mode 100644 apps/desktop/src/app/components/avatar.component.ts delete mode 100644 libs/angular/src/components/avatar.component.ts diff --git a/apps/desktop/src/app/components/avatar.component.ts b/apps/desktop/src/app/components/avatar.component.ts new file mode 100644 index 0000000000..b837c541eb --- /dev/null +++ b/apps/desktop/src/app/components/avatar.component.ts @@ -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: ``, +}) +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("") : ""; + } +} diff --git a/apps/desktop/src/app/layout/account-switcher.component.html b/apps/desktop/src/app/layout/account-switcher.component.html index ecf4bba78c..9b77638a6c 100644 --- a/apps/desktop/src/app/layout/account-switcher.component.html +++ b/apps/desktop/src/app/layout/account-switcher.component.html @@ -8,17 +8,18 @@ aria-controls="cdk-overlay-container" [attr.aria-expanded]="isOpen" > - + - {{ activeAccountEmail }} + {{ activeAccount.email }} {{ "switchAccount" | i18n }} @@ -58,7 +59,8 @@ attr.aria-label="{{ 'switchAccount' | i18n }}" > - +