avatar component

This commit is contained in:
Kyle Spearrin 2018-06-21 11:28:14 -04:00
parent 1fb4f2946a
commit 9633800977
5 changed files with 127 additions and 2 deletions

View File

@ -16,6 +16,8 @@ import { ServicesModule } from './services/services.module';
import { AppComponent } from './app.component';
import { ModalComponent } from './modal.component';
import { AvatarComponent } from './components/avatar.component';
import { FooterComponent } from './layouts/footer.component';
import { FrontendLayoutComponent } from './layouts/frontend-layout.component';
import { NavbarComponent } from './layouts/navbar.component';
@ -87,6 +89,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
AppComponent,
AttachmentsComponent,
AutofocusDirective,
AvatarComponent,
BlurClickDirective,
BoxRowDirective,
BulkDeleteComponent,

View File

@ -0,0 +1,113 @@
import {
Component,
Input,
OnChanges,
OnInit,
} from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'app-avatar',
template: '<img [src]="sanitizer.bypassSecurityTrustResourceUrl(src)" title="{{data}}">',
})
export class AvatarComponent implements OnChanges, OnInit {
@Input() data: string;
@Input() width = 45;
@Input() height = 45;
@Input() charCount = 2;
@Input() textColor = '#ffffff';
@Input() fontSize = 20;
@Input() fontWeight = 300;
@Input() dynamic = false;
src: string;
constructor(public sanitizer: DomSanitizer) { }
ngOnInit() {
if (!this.dynamic) {
this.generate();
}
}
ngOnChanges() {
if (this.dynamic) {
this.generate();
}
}
private generate() {
let chars: string = null;
const upperData = this.data.toUpperCase();
if (this.charCount > 1) {
chars = this.getFirstLetters(upperData, this.charCount);
}
if (chars == null) {
chars = upperData.substr(0, this.charCount);
}
const charObj = this.getCharText(chars);
const color = this.stringToColor(upperData);
const svg = this.getSvg(this.width, this.height, color);
svg.appendChild(charObj);
const html = window.document.createElement('div').appendChild(svg).outerHTML;
const svgHtml = window.btoa(unescape(encodeURIComponent(html)));
this.src = 'data:image/svg+xml;base64,' + svgHtml;
}
private stringToColor(str: string): string {
let hash = 0;
for (let i = 0; i < str.length; i++) {
// tslint:disable-next-line
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
let color = '#';
for (let i = 0; i < 3; i++) {
// tslint:disable-next-line
const value = (hash >> (i * 8)) & 0xFF;
color += ('00' + value.toString(16)).substr(-2);
}
return color;
}
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 += parts[i].substr(0, 1);
}
return text;
}
return null;
}
private getSvg(width: number, height: 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', width.toString());
svgTag.setAttribute('height', height.toString());
svgTag.style.backgroundColor = color;
svgTag.style.width = width + 'px';
svgTag.style.height = height + 'px';
return svgTag;
}
private getCharText(character: 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', this.textColor);
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.fontWeight.toString();
textTag.style.fontSize = this.fontSize + 'px';
return textTag;
}
}

View File

@ -20,6 +20,9 @@
<input id="masterPasswordHint" class="form-control" type="text" name="MasterPasswordHint" [(ngModel)]="profile.masterPasswordHint">
</div>
</div>
<div class="col-6">
<app-avatar data="{{profile.name}}" dynamic="true" width="75" height="75" fontSize="35"></app-avatar>
</div>
</div>
<button type="submit" class="btn btn-primary btn-submit" appBlurClick [disabled]="profileForm.loading">
<i class="fa fa-spinner fa-spin"></i>

View File

@ -47,12 +47,12 @@
<button type="button" class="btn btn-primary" appBlurClick (click)="regenerate()">
{{'regeneratePassword' | i18n}}
</button>
<button type="button" class="btn btn-outline-primary" appBlurClick (click)="copy()">
<button type="button" class="btn btn-outline-secondary" appBlurClick (click)="copy()">
{{'copyPassword' | i18n}}
</button>
</div>
<div class="ml-auto">
<button type="button" class="btn btn-outline-primary" appBlurClick (click)="history()" title="{{'passwordHistory' | i18n}}">
<button type="button" class="btn btn-outline-secondary" appBlurClick (click)="history()" title="{{'passwordHistory' | i18n}}">
<i class="fa fa-clock-o fa-lg"></i>
</button>
</div>

View File

@ -351,6 +351,12 @@ app-password-generator-history {
}
}
app-avatar {
img {
@extend .rounded;
}
}
#duo-frame {
background: url('../images/loading.svg') 0 0 no-repeat;
height: 330px;