@gayath1/ng-avatar-creator 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/esm2020/gayath1-ng-avatar-creator.mjs +5 -0
- package/esm2020/lib/avatar-models.mjs +17 -0
- package/esm2020/lib/ng-avatar-creator.component.mjs +192 -0
- package/esm2020/lib/ng-avatar-creator.module.mjs +24 -0
- package/esm2020/lib/ng-avatar-creator.service.mjs +14 -0
- package/esm2020/public-api.mjs +8 -0
- package/fesm2015/gayath1-ng-avatar-creator.mjs +253 -0
- package/fesm2015/gayath1-ng-avatar-creator.mjs.map +1 -0
- package/fesm2020/gayath1-ng-avatar-creator.mjs +252 -0
- package/fesm2020/gayath1-ng-avatar-creator.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/avatar-models.d.ts +13 -0
- package/lib/ng-avatar-creator.component.d.ts +39 -0
- package/lib/ng-avatar-creator.module.d.ts +8 -0
- package/lib/ng-avatar-creator.service.d.ts +6 -0
- package/package.json +31 -0
- package/public-api.d.ts +4 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# NgAvatarCreator
|
|
2
|
+
|
|
3
|
+
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.0.0.
|
|
4
|
+
|
|
5
|
+
## Code scaffolding
|
|
6
|
+
|
|
7
|
+
Run `ng generate component component-name --project ng-avatar-creator` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ng-avatar-creator`.
|
|
8
|
+
> Note: Don't forget to add `--project ng-avatar-creator` or else it will be added to the default project in your `angular.json` file.
|
|
9
|
+
|
|
10
|
+
## Build
|
|
11
|
+
|
|
12
|
+
Run `ng build ng-avatar-creator` to build the project. The build artifacts will be stored in the `dist/` directory.
|
|
13
|
+
|
|
14
|
+
## Publishing
|
|
15
|
+
|
|
16
|
+
After building your library with `ng build ng-avatar-creator`, go to the dist folder `cd dist/ng-avatar-creator` and run `npm publish`.
|
|
17
|
+
|
|
18
|
+
## Running unit tests
|
|
19
|
+
|
|
20
|
+
Run `ng test ng-avatar-creator` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
|
21
|
+
|
|
22
|
+
## Further help
|
|
23
|
+
|
|
24
|
+
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './public-api';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2F5YXRoMS1uZy1hdmF0YXItY3JlYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL25nLWF2YXRhci1jcmVhdG9yL3NyYy9nYXlhdGgxLW5nLWF2YXRhci1jcmVhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxjQUFjLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vcHVibGljLWFwaSc7XG4iXX0=
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const AVATAR_STYLES = [
|
|
2
|
+
{ id: 'initials', name: 'Initials' },
|
|
3
|
+
{ id: 'identicon', name: 'Identicon' },
|
|
4
|
+
{ id: 'rings', name: 'Rings' },
|
|
5
|
+
{ id: 'shapes', name: 'Shapes' },
|
|
6
|
+
{ id: 'thumbs', name: 'Thumbs' },
|
|
7
|
+
{ id: 'avataaars', name: 'Avatars' },
|
|
8
|
+
{ id: 'bottts', name: 'Bots' },
|
|
9
|
+
{ id: 'glass', name: 'Glass' }
|
|
10
|
+
];
|
|
11
|
+
export const PREDEFINED_COLORS = [
|
|
12
|
+
'#ef4444', '#f97316', '#f59e0b', '#84cc16', '#22c55e',
|
|
13
|
+
'#14b8a6', '#06b6d4', '#0ea5e9', '#3b82f6', '#6366f1',
|
|
14
|
+
'#8b5cf6', '#a855f7', '#d946ef', '#ec4899', '#f43f5e',
|
|
15
|
+
'#475569', '#111827', '#7c2d12', '#365314', '#164e63'
|
|
16
|
+
];
|
|
17
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXZhdGFyLW1vZGVscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25nLWF2YXRhci1jcmVhdG9yL3NyYy9saWIvYXZhdGFyLW1vZGVscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFzQkEsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHO0lBQzNCLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFO0lBQ3BDLEVBQUUsRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFO0lBQ3RDLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFO0lBQzlCLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFO0lBQ2hDLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFO0lBQ2hDLEVBQUUsRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFO0lBQ3BDLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFO0lBQzlCLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFO0NBQ1IsQ0FBQztBQUV6QixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRztJQUMvQixTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUztJQUNyRCxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUztJQUNyRCxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUztJQUNyRCxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUztDQUN0RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGludGVyZmFjZSBBdmF0YXJDb25maWcge1xuICBzdHlsZTogQXZhdGFyU3R5bGVJZDtcbiAgc2VlZDogc3RyaW5nO1xuICBiZ0NvbG9yOiBzdHJpbmc7XG4gIHNoYXBlOiAnY2lyY2xlJyB8ICdzcXVhcmUnO1xufVxuXG5leHBvcnQgdHlwZSBBdmF0YXJTdHlsZUlkID1cbiAgfCAnaW5pdGlhbHMnXG4gIHwgJ2lkZW50aWNvbidcbiAgfCAncmluZ3MnXG4gIHwgJ3NoYXBlcydcbiAgfCAndGh1bWJzJ1xuICB8ICdhdmF0YWFhcnMnXG4gIHwgJ2JvdHR0cydcbiAgfCAnZ2xhc3MnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEF2YXRhclN0eWxlT3B0aW9uIHtcbiAgaWQ6IEF2YXRhclN0eWxlSWQ7XG4gIG5hbWU6IHN0cmluZztcbn1cblxuZXhwb3J0IGNvbnN0IEFWQVRBUl9TVFlMRVMgPSBbXG4gIHsgaWQ6ICdpbml0aWFscycsIG5hbWU6ICdJbml0aWFscycgfSxcbiAgeyBpZDogJ2lkZW50aWNvbicsIG5hbWU6ICdJZGVudGljb24nIH0sXG4gIHsgaWQ6ICdyaW5ncycsIG5hbWU6ICdSaW5ncycgfSxcclxuICB7IGlkOiAnc2hhcGVzJywgbmFtZTogJ1NoYXBlcycgfSxcclxuICB7IGlkOiAndGh1bWJzJywgbmFtZTogJ1RodW1icycgfSxcclxuICB7IGlkOiAnYXZhdGFhYXJzJywgbmFtZTogJ0F2YXRhcnMnIH0sXG4gIHsgaWQ6ICdib3R0dHMnLCBuYW1lOiAnQm90cycgfSxcbiAgeyBpZDogJ2dsYXNzJywgbmFtZTogJ0dsYXNzJyB9XG5dIGFzIEF2YXRhclN0eWxlT3B0aW9uW107XG5cbmV4cG9ydCBjb25zdCBQUkVERUZJTkVEX0NPTE9SUyA9IFtcbiAgJyNlZjQ0NDQnLCAnI2Y5NzMxNicsICcjZjU5ZTBiJywgJyM4NGNjMTYnLCAnIzIyYzU1ZScsXG4gICcjMTRiOGE2JywgJyMwNmI2ZDQnLCAnIzBlYTVlOScsICcjM2I4MmY2JywgJyM2MzY2ZjEnLFxuICAnIzhiNWNmNicsICcjYTg1NWY3JywgJyNkOTQ2ZWYnLCAnI2VjNDg5OScsICcjZjQzZjVlJyxcbiAgJyM0NzU1NjknLCAnIzExMTgyNycsICcjN2MyZDEyJywgJyMzNjUzMTQnLCAnIzE2NGU2Mydcbl07XG4iXX0=
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { PREDEFINED_COLORS, AVATAR_STYLES } from './avatar-models';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "@angular/common";
|
|
5
|
+
export class NgAvatarCreatorComponent {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.firstName = '';
|
|
8
|
+
this.lastName = '';
|
|
9
|
+
this.size = 64;
|
|
10
|
+
this.editable = false;
|
|
11
|
+
this.editorTitle = 'Customize Avatar';
|
|
12
|
+
this.avatarConfigChanged = new EventEmitter();
|
|
13
|
+
this.hovering = false;
|
|
14
|
+
this.editorOpen = false;
|
|
15
|
+
this.currentConfig = {
|
|
16
|
+
style: 'initials',
|
|
17
|
+
seed: '',
|
|
18
|
+
bgColor: '#3b82f6',
|
|
19
|
+
shape: 'circle'
|
|
20
|
+
};
|
|
21
|
+
this.colors = PREDEFINED_COLORS;
|
|
22
|
+
this.styles = AVATAR_STYLES;
|
|
23
|
+
}
|
|
24
|
+
ngOnInit() {
|
|
25
|
+
this.syncConfig();
|
|
26
|
+
this.avatarConfigChanged.emit({ ...this.currentConfig });
|
|
27
|
+
}
|
|
28
|
+
ngOnChanges(changes) {
|
|
29
|
+
if (!changes['avatarConfig'] && !changes['firstName'] && !changes['lastName']) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this.syncConfig();
|
|
33
|
+
}
|
|
34
|
+
syncConfig() {
|
|
35
|
+
if (this.avatarConfig) {
|
|
36
|
+
this.currentConfig = { ...this.currentConfig, ...this.avatarConfig };
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const defaultSeed = this.getDefaultSeed();
|
|
40
|
+
const colorIndex = Math.abs(this.hash(defaultSeed)) % this.colors.length;
|
|
41
|
+
this.currentConfig.bgColor = this.colors[colorIndex];
|
|
42
|
+
this.currentConfig.seed = this.getDefaultSeed();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
getDefaultSeed() {
|
|
46
|
+
const parts = [];
|
|
47
|
+
if (this.firstName)
|
|
48
|
+
parts.push(this.firstName);
|
|
49
|
+
if (this.lastName)
|
|
50
|
+
parts.push(this.lastName);
|
|
51
|
+
return parts.join(' ') || 'User';
|
|
52
|
+
}
|
|
53
|
+
getAvatarUrl(config = this.currentConfig) {
|
|
54
|
+
return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(this.getAvatarSvg(config))}`;
|
|
55
|
+
}
|
|
56
|
+
getAvatarSvg(config = this.currentConfig) {
|
|
57
|
+
const seed = this.getEffectiveSeed(config);
|
|
58
|
+
const hash = this.hash(seed);
|
|
59
|
+
const initials = this.getInitials(seed);
|
|
60
|
+
const accent = this.pickAccent(config.bgColor, hash);
|
|
61
|
+
const dark = this.adjustColor(config.bgColor, -34);
|
|
62
|
+
const light = this.adjustColor(config.bgColor, 46);
|
|
63
|
+
const mask = config.shape === 'circle' ? '<clipPath id="clip"><circle cx="50" cy="50" r="50"/></clipPath>' : '<clipPath id="clip"><rect width="100" height="100" rx="12"/></clipPath>';
|
|
64
|
+
const content = this.renderStyle(config.style, hash, initials, config.bgColor, accent, dark, light);
|
|
65
|
+
return [
|
|
66
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" role="img" aria-label="Avatar">',
|
|
67
|
+
'<defs>',
|
|
68
|
+
mask,
|
|
69
|
+
'<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="4" stdDeviation="5" flood-opacity=".18"/></filter>',
|
|
70
|
+
'</defs>',
|
|
71
|
+
'<g clip-path="url(#clip)">',
|
|
72
|
+
`<rect width="100" height="100" fill="${config.bgColor}"/>`,
|
|
73
|
+
content,
|
|
74
|
+
'</g>',
|
|
75
|
+
'</svg>'
|
|
76
|
+
].join('');
|
|
77
|
+
}
|
|
78
|
+
randomizeSeed() {
|
|
79
|
+
const randomString = `avatar-${Math.random().toString(36).substring(2, 8)}`;
|
|
80
|
+
this.updateConfig({ seed: randomString });
|
|
81
|
+
}
|
|
82
|
+
setSeed(value) {
|
|
83
|
+
this.updateConfig({ seed: value || this.getDefaultSeed() });
|
|
84
|
+
}
|
|
85
|
+
toggleEditor() {
|
|
86
|
+
this.editorOpen = !this.editorOpen;
|
|
87
|
+
}
|
|
88
|
+
updateConfig(partial) {
|
|
89
|
+
this.currentConfig = { ...this.currentConfig, ...partial };
|
|
90
|
+
if (partial.style === 'initials') {
|
|
91
|
+
this.currentConfig.seed = this.getDefaultSeed();
|
|
92
|
+
}
|
|
93
|
+
this.avatarConfigChanged.emit({ ...this.currentConfig });
|
|
94
|
+
}
|
|
95
|
+
trackByStyle(_, style) {
|
|
96
|
+
return style.id;
|
|
97
|
+
}
|
|
98
|
+
renderStyle(style, hash, initials, bg, accent, dark, light) {
|
|
99
|
+
switch (style) {
|
|
100
|
+
case 'initials':
|
|
101
|
+
return `<circle cx="76" cy="23" r="24" fill="${light}" opacity=".8"/><circle cx="20" cy="78" r="30" fill="${dark}" opacity=".32"/><text x="50" y="58" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-size="34" font-weight="700" fill="#fff">${initials}</text>`;
|
|
102
|
+
case 'identicon':
|
|
103
|
+
return this.renderIdenticon(hash, accent, dark, light);
|
|
104
|
+
case 'rings':
|
|
105
|
+
return `<circle cx="50" cy="50" r="42" fill="none" stroke="${light}" stroke-width="12" opacity=".9"/><circle cx="50" cy="50" r="27" fill="none" stroke="${accent}" stroke-width="10"/><circle cx="50" cy="50" r="12" fill="${dark}"/><path d="M50 8a42 42 0 0 1 36 21" stroke="#fff" stroke-width="8" stroke-linecap="round" opacity=".65" fill="none"/>`;
|
|
106
|
+
case 'shapes':
|
|
107
|
+
return `<rect x="12" y="14" width="34" height="34" rx="10" fill="${light}" transform="rotate(${hash % 24} 29 31)"/><circle cx="68" cy="34" r="20" fill="${accent}"/><path d="M21 82 47 50l29 32Z" fill="${dark}"/><circle cx="74" cy="76" r="10" fill="#fff" opacity=".7"/>`;
|
|
108
|
+
case 'thumbs':
|
|
109
|
+
return `<circle cx="50" cy="50" r="31" fill="${light}"/><path d="M29 51h11l8-20c2-5 10-3 9 3l-2 12h13c5 0 8 4 7 9l-4 20c-1 5-5 8-10 8H36c-4 0-7-3-7-7V51Z" fill="#fff"/><rect x="21" y="51" width="15" height="32" rx="6" fill="${dark}"/>`;
|
|
110
|
+
case 'avataaars':
|
|
111
|
+
return `<circle cx="50" cy="55" r="28" fill="#ffd7b5"/><path d="M23 48c2-21 17-32 34-29 13 2 21 12 22 28-12-8-25-8-34-3-8 5-15 5-22 4Z" fill="${dark}"/><circle cx="39" cy="57" r="4" fill="#1f2937"/><circle cx="61" cy="57" r="4" fill="#1f2937"/><path d="M40 73c7 5 14 5 21 0" stroke="#9f1239" stroke-width="4" stroke-linecap="round" fill="none"/><path d="M18 100c6-18 21-27 32-27s26 9 32 27Z" fill="${accent}"/>`;
|
|
112
|
+
case 'bottts':
|
|
113
|
+
return `<rect x="22" y="28" width="56" height="48" rx="14" fill="${light}" filter="url(#shadow)"/><rect x="32" y="45" width="13" height="11" rx="4" fill="${dark}"/><rect x="55" y="45" width="13" height="11" rx="4" fill="${dark}"/><path d="M39 66h22" stroke="#fff" stroke-width="5" stroke-linecap="round"/><path d="M50 28V15" stroke="${dark}" stroke-width="5" stroke-linecap="round"/><circle cx="50" cy="13" r="6" fill="${accent}"/>`;
|
|
114
|
+
case 'glass':
|
|
115
|
+
return `<circle cx="32" cy="30" r="24" fill="#fff" opacity=".34"/><circle cx="72" cy="73" r="32" fill="${dark}" opacity=".36"/><rect x="19" y="19" width="62" height="62" rx="18" fill="#fff" opacity=".22" stroke="#fff" stroke-width="2"/><text x="50" y="59" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-size="28" font-weight="700" fill="#fff">${initials}</text>`;
|
|
116
|
+
default:
|
|
117
|
+
return '';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
renderIdenticon(hash, accent, dark, light) {
|
|
121
|
+
const cells = [];
|
|
122
|
+
const colors = [accent, dark, light];
|
|
123
|
+
for (let row = 0; row < 5; row++) {
|
|
124
|
+
for (let col = 0; col < 3; col++) {
|
|
125
|
+
const bit = (hash >> (row * 3 + col)) & 1;
|
|
126
|
+
if (!bit) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const x = 20 + col * 12;
|
|
130
|
+
const mirrorX = 20 + (4 - col) * 12;
|
|
131
|
+
const y = 20 + row * 12;
|
|
132
|
+
const color = colors[(row + col + Math.abs(hash)) % colors.length];
|
|
133
|
+
cells.push(`<rect x="${x}" y="${y}" width="10" height="10" rx="2" fill="${color}"/>`);
|
|
134
|
+
if (col !== 2) {
|
|
135
|
+
cells.push(`<rect x="${mirrorX}" y="${y}" width="10" height="10" rx="2" fill="${color}"/>`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return cells.join('');
|
|
140
|
+
}
|
|
141
|
+
getEffectiveSeed(config) {
|
|
142
|
+
return config.style === 'initials' ? this.getDefaultSeed() : (config.seed || this.getDefaultSeed());
|
|
143
|
+
}
|
|
144
|
+
getInitials(seed) {
|
|
145
|
+
const names = seed.trim().split(/\s+/).filter(Boolean);
|
|
146
|
+
const first = names[0]?.charAt(0) || 'U';
|
|
147
|
+
const second = names.length > 1 ? names[names.length - 1].charAt(0) : names[0]?.charAt(1) || '';
|
|
148
|
+
return `${first}${second}`.toUpperCase();
|
|
149
|
+
}
|
|
150
|
+
hash(value) {
|
|
151
|
+
let hash = 0;
|
|
152
|
+
for (let i = 0; i < value.length; i++) {
|
|
153
|
+
hash = ((hash << 5) - hash) + value.charCodeAt(i);
|
|
154
|
+
hash |= 0;
|
|
155
|
+
}
|
|
156
|
+
return hash || 1;
|
|
157
|
+
}
|
|
158
|
+
pickAccent(color, hash) {
|
|
159
|
+
const index = Math.abs(hash) % this.colors.length;
|
|
160
|
+
const picked = this.colors[index];
|
|
161
|
+
return picked.toLowerCase() === color.toLowerCase() ? this.adjustColor(color, 60) : picked;
|
|
162
|
+
}
|
|
163
|
+
adjustColor(hex, amount) {
|
|
164
|
+
const clean = hex.replace('#', '');
|
|
165
|
+
const num = parseInt(clean, 16);
|
|
166
|
+
const r = Math.max(0, Math.min(255, (num >> 16) + amount));
|
|
167
|
+
const g = Math.max(0, Math.min(255, ((num >> 8) & 0x00ff) + amount));
|
|
168
|
+
const b = Math.max(0, Math.min(255, (num & 0x0000ff) + amount));
|
|
169
|
+
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
NgAvatarCreatorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
173
|
+
NgAvatarCreatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: NgAvatarCreatorComponent, selector: "lib-ng-avatar-creator", inputs: { firstName: "firstName", lastName: "lastName", size: "size", editable: "editable", editorTitle: "editorTitle", avatarConfig: "avatarConfig" }, outputs: { avatarConfigChanged: "avatarConfigChanged" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"avatar-container\" \r\n [style.width.px]=\"size\" \r\n [style.height.px]=\"size\"\r\n [style.borderRadius]=\"currentConfig.shape === 'circle' ? '50%' : '8px'\"\r\n (mouseenter)=\"hovering = true\"\r\n (mouseleave)=\"hovering = false\">\r\n \r\n <div class=\"avatar-content\">\r\n <img [src]=\"getAvatarUrl()\" alt=\"Avatar\" class=\"avatar-image\">\r\n </div>\r\n\r\n <div class=\"edit-overlay\" *ngIf=\"editable && hovering\" (click)=\"toggleEditor()\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"24\" height=\"24\">\r\n <path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\"/>\r\n </svg>\r\n </div>\r\n</div>\r\n\r\n<div class=\"editor-popover\" *ngIf=\"editorOpen\">\r\n <div class=\"editor-header\">\r\n <h3>Customize Avatar</h3>\r\n <button class=\"close-btn\" (click)=\"toggleEditor()\">×</button>\r\n </div>\r\n \r\n <div class=\"editor-body\">\r\n <div class=\"section\">\r\n <label>Shape</label>\r\n <div class=\"shape-options\">\r\n <button [class.active]=\"currentConfig.shape === 'circle'\" (click)=\"updateConfig({shape: 'circle'})\">Circle</button>\r\n <button [class.active]=\"currentConfig.shape === 'square'\" (click)=\"updateConfig({shape: 'square'})\">Square</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <label>Background Color</label>\r\n <div class=\"color-grid\">\r\n <button *ngFor=\"let color of colors\" \r\n class=\"color-swatch\" \r\n [style.backgroundColor]=\"color\"\r\n [class.active]=\"currentConfig.bgColor === color\"\r\n (click)=\"updateConfig({bgColor: color})\">\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title-row\">\r\n <label>Style Category</label>\r\n <button class=\"randomize-btn\" (click)=\"randomizeSeed()\">\uD83C\uDFB2 Randomize</button>\r\n </div>\r\n <div class=\"style-grid\">\r\n <div *ngFor=\"let style of styles\" \r\n class=\"style-card\"\r\n [class.active]=\"currentConfig.style === style.id\"\r\n (click)=\"updateConfig({style: style.id})\">\r\n <img [src]=\"getAvatarUrl({ style: style.id, seed: currentConfig.seed, bgColor: currentConfig.bgColor, shape: currentConfig.shape })\" alt=\"{{style.name}}\">\r\n <span>{{ style.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{display:inline-block;position:relative;font-family:Inter,Roboto,sans-serif}.avatar-container{position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;transition:all .3s ease;-webkit-user-select:none;user-select:none}.avatar-content{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.avatar-image{width:100%;height:100%;object-fit:cover}.edit-overlay{position:absolute;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;color:#fff;cursor:pointer;opacity:0;animation:fadeIn .2s forwards;backdrop-filter:blur(2px)}@keyframes fadeIn{to{opacity:1}}.editor-popover{position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%);width:320px;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;z-index:1000;border:1px solid #e2e8f0;padding:16px;animation:slideUp .3s cubic-bezier(.16,1,.3,1)}@keyframes slideUp{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}.editor-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;border-bottom:1px solid #f1f5f9;padding-bottom:8px}.editor-header h3{margin:0;font-size:14px;font-weight:600;color:#334155}.close-btn{background:none;border:none;font-size:20px;cursor:pointer;color:#94a3b8;padding:0;line-height:1}.close-btn:hover{color:#475569}.section{margin-bottom:16px}.section:last-child{margin-bottom:0}.section-title-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.section label{display:block;font-size:12px;color:#64748b;margin:0;font-weight:500;text-transform:uppercase;letter-spacing:.5px}.randomize-btn{background:#f1f5f9;border:none;border-radius:4px;padding:4px 8px;font-size:11px;color:#475569;cursor:pointer;font-weight:600;transition:background .2s}.randomize-btn:hover{background:#e2e8f0;color:#0f172a}.shape-options{display:flex;gap:8px}.shape-options button{flex:1;padding:8px;border:1px solid #e2e8f0;background:#f8fafc;border-radius:6px;cursor:pointer;font-size:13px;color:#475569;transition:all .2s}.shape-options button:hover{background:#f1f5f9}.shape-options button.active{background:#3b82f6;color:#fff;border-color:#3b82f6}.color-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}.color-swatch{width:100%;aspect-ratio:1;border-radius:50%;border:2px solid transparent;cursor:pointer;transition:transform .2s}.color-swatch:hover{transform:scale(1.1)}.color-swatch.active{border-color:#333;box-shadow:0 0 0 2px #fff inset}.style-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;max-height:200px;overflow-y:auto;padding-right:4px}.style-grid::-webkit-scrollbar{width:4px}.style-grid::-webkit-scrollbar-thumb{background-color:#cbd5e1;border-radius:4px}.style-card{border:1px solid #e2e8f0;background:white;border-radius:8px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:8px 4px;transition:all .2s}.style-card:hover{background:#f8fafc;border-color:#cbd5e1}.style-card.active{border-color:#3b82f6;background:#eff6ff}.style-card img{width:40px;height:40px;margin-bottom:4px;border-radius:50%}.style-card span{font-size:10px;color:#475569;font-weight:500;text-align:center}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
174
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorComponent, decorators: [{
|
|
175
|
+
type: Component,
|
|
176
|
+
args: [{ selector: 'lib-ng-avatar-creator', template: "<div class=\"avatar-container\" \r\n [style.width.px]=\"size\" \r\n [style.height.px]=\"size\"\r\n [style.borderRadius]=\"currentConfig.shape === 'circle' ? '50%' : '8px'\"\r\n (mouseenter)=\"hovering = true\"\r\n (mouseleave)=\"hovering = false\">\r\n \r\n <div class=\"avatar-content\">\r\n <img [src]=\"getAvatarUrl()\" alt=\"Avatar\" class=\"avatar-image\">\r\n </div>\r\n\r\n <div class=\"edit-overlay\" *ngIf=\"editable && hovering\" (click)=\"toggleEditor()\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"24\" height=\"24\">\r\n <path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\"/>\r\n </svg>\r\n </div>\r\n</div>\r\n\r\n<div class=\"editor-popover\" *ngIf=\"editorOpen\">\r\n <div class=\"editor-header\">\r\n <h3>Customize Avatar</h3>\r\n <button class=\"close-btn\" (click)=\"toggleEditor()\">×</button>\r\n </div>\r\n \r\n <div class=\"editor-body\">\r\n <div class=\"section\">\r\n <label>Shape</label>\r\n <div class=\"shape-options\">\r\n <button [class.active]=\"currentConfig.shape === 'circle'\" (click)=\"updateConfig({shape: 'circle'})\">Circle</button>\r\n <button [class.active]=\"currentConfig.shape === 'square'\" (click)=\"updateConfig({shape: 'square'})\">Square</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <label>Background Color</label>\r\n <div class=\"color-grid\">\r\n <button *ngFor=\"let color of colors\" \r\n class=\"color-swatch\" \r\n [style.backgroundColor]=\"color\"\r\n [class.active]=\"currentConfig.bgColor === color\"\r\n (click)=\"updateConfig({bgColor: color})\">\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title-row\">\r\n <label>Style Category</label>\r\n <button class=\"randomize-btn\" (click)=\"randomizeSeed()\">\uD83C\uDFB2 Randomize</button>\r\n </div>\r\n <div class=\"style-grid\">\r\n <div *ngFor=\"let style of styles\" \r\n class=\"style-card\"\r\n [class.active]=\"currentConfig.style === style.id\"\r\n (click)=\"updateConfig({style: style.id})\">\r\n <img [src]=\"getAvatarUrl({ style: style.id, seed: currentConfig.seed, bgColor: currentConfig.bgColor, shape: currentConfig.shape })\" alt=\"{{style.name}}\">\r\n <span>{{ style.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{display:inline-block;position:relative;font-family:Inter,Roboto,sans-serif}.avatar-container{position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;transition:all .3s ease;-webkit-user-select:none;user-select:none}.avatar-content{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.avatar-image{width:100%;height:100%;object-fit:cover}.edit-overlay{position:absolute;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;color:#fff;cursor:pointer;opacity:0;animation:fadeIn .2s forwards;backdrop-filter:blur(2px)}@keyframes fadeIn{to{opacity:1}}.editor-popover{position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%);width:320px;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;z-index:1000;border:1px solid #e2e8f0;padding:16px;animation:slideUp .3s cubic-bezier(.16,1,.3,1)}@keyframes slideUp{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}.editor-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;border-bottom:1px solid #f1f5f9;padding-bottom:8px}.editor-header h3{margin:0;font-size:14px;font-weight:600;color:#334155}.close-btn{background:none;border:none;font-size:20px;cursor:pointer;color:#94a3b8;padding:0;line-height:1}.close-btn:hover{color:#475569}.section{margin-bottom:16px}.section:last-child{margin-bottom:0}.section-title-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.section label{display:block;font-size:12px;color:#64748b;margin:0;font-weight:500;text-transform:uppercase;letter-spacing:.5px}.randomize-btn{background:#f1f5f9;border:none;border-radius:4px;padding:4px 8px;font-size:11px;color:#475569;cursor:pointer;font-weight:600;transition:background .2s}.randomize-btn:hover{background:#e2e8f0;color:#0f172a}.shape-options{display:flex;gap:8px}.shape-options button{flex:1;padding:8px;border:1px solid #e2e8f0;background:#f8fafc;border-radius:6px;cursor:pointer;font-size:13px;color:#475569;transition:all .2s}.shape-options button:hover{background:#f1f5f9}.shape-options button.active{background:#3b82f6;color:#fff;border-color:#3b82f6}.color-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}.color-swatch{width:100%;aspect-ratio:1;border-radius:50%;border:2px solid transparent;cursor:pointer;transition:transform .2s}.color-swatch:hover{transform:scale(1.1)}.color-swatch.active{border-color:#333;box-shadow:0 0 0 2px #fff inset}.style-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;max-height:200px;overflow-y:auto;padding-right:4px}.style-grid::-webkit-scrollbar{width:4px}.style-grid::-webkit-scrollbar-thumb{background-color:#cbd5e1;border-radius:4px}.style-card{border:1px solid #e2e8f0;background:white;border-radius:8px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:8px 4px;transition:all .2s}.style-card:hover{background:#f8fafc;border-color:#cbd5e1}.style-card.active{border-color:#3b82f6;background:#eff6ff}.style-card img{width:40px;height:40px;margin-bottom:4px;border-radius:50%}.style-card span{font-size:10px;color:#475569;font-weight:500;text-align:center}\n"] }]
|
|
177
|
+
}], propDecorators: { firstName: [{
|
|
178
|
+
type: Input
|
|
179
|
+
}], lastName: [{
|
|
180
|
+
type: Input
|
|
181
|
+
}], size: [{
|
|
182
|
+
type: Input
|
|
183
|
+
}], editable: [{
|
|
184
|
+
type: Input
|
|
185
|
+
}], editorTitle: [{
|
|
186
|
+
type: Input
|
|
187
|
+
}], avatarConfig: [{
|
|
188
|
+
type: Input
|
|
189
|
+
}], avatarConfigChanged: [{
|
|
190
|
+
type: Output
|
|
191
|
+
}] } });
|
|
192
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctYXZhdGFyLWNyZWF0b3IuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmctYXZhdGFyLWNyZWF0b3Ivc3JjL2xpYi9uZy1hdmF0YXItY3JlYXRvci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy1hdmF0YXItY3JlYXRvci9zcmMvbGliL25nLWF2YXRhci1jcmVhdG9yLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQW9DLE1BQU0sZUFBZSxDQUFDO0FBQ3pHLE9BQU8sRUFBK0IsaUJBQWlCLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7OztBQU9oRyxNQUFNLE9BQU8sd0JBQXdCO0lBTHJDO1FBTVcsY0FBUyxHQUFXLEVBQUUsQ0FBQztRQUN2QixhQUFRLEdBQVcsRUFBRSxDQUFDO1FBQ3RCLFNBQUksR0FBVyxFQUFFLENBQUM7UUFDbEIsYUFBUSxHQUFZLEtBQUssQ0FBQztRQUMxQixnQkFBVyxHQUFXLGtCQUFrQixDQUFDO1FBR3hDLHdCQUFtQixHQUFHLElBQUksWUFBWSxFQUFnQixDQUFDO1FBRWpFLGFBQVEsR0FBWSxLQUFLLENBQUM7UUFDMUIsZUFBVSxHQUFZLEtBQUssQ0FBQztRQUU1QixrQkFBYSxHQUFpQjtZQUM1QixLQUFLLEVBQUUsVUFBVTtZQUNqQixJQUFJLEVBQUUsRUFBRTtZQUNSLE9BQU8sRUFBRSxTQUFTO1lBQ2xCLEtBQUssRUFBRSxRQUFRO1NBQ2hCLENBQUM7UUFFRixXQUFNLEdBQUcsaUJBQWlCLENBQUM7UUFDM0IsV0FBTSxHQUFHLGFBQWEsQ0FBQztLQTJLeEI7SUF6S0MsUUFBUTtRQUNOLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNsQixJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLEVB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QUFDLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDNUUsQ0FBQzs7c0hBL0xVLHdCQUF3QjswR0FBeEIsd0JBQXdCLG1TQ1JyQyxrbUZBOERBOzRGRHREYSx3QkFBd0I7a0JBTHBDLFNBQVM7K0JBQ0UsdUJBQXVCOzhCQUt4QixTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csSUFBSTtzQkFBWixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFFRyxZQUFZO3NCQUFwQixLQUFLO2dCQUNJLG1CQUFtQjtzQkFBNUIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBPbkNoYW5nZXMsIE9uSW5pdCwgU2ltcGxlQ2hhbmdlcyB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQXZhdGFyQ29uZmlnLCBBdmF0YXJTdHlsZUlkLCBQUkVERUZJTkVEX0NPTE9SUywgQVZBVEFSX1NUWUxFUyB9IGZyb20gJy4vYXZhdGFyLW1vZGVscyc7XG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdsaWItbmctYXZhdGFyLWNyZWF0b3InLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9uZy1hdmF0YXItY3JlYXRvci5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJy4vbmctYXZhdGFyLWNyZWF0b3IuY29tcG9uZW50LmNzcyddXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBOZ0F2YXRhckNyZWF0b3JDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcyB7XG4gIEBJbnB1dCgpIGZpcnN0TmFtZTogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgpIGxhc3ROYW1lOiBzdHJpbmcgPSAnJztcbiAgQElucHV0KCkgc2l6ZTogbnVtYmVyID0gNjQ7XG4gIEBJbnB1dCgpIGVkaXRhYmxlOiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIGVkaXRvclRpdGxlOiBzdHJpbmcgPSAnQ3VzdG9taXplIEF2YXRhcic7XG4gIFxuICBASW5wdXQoKSBhdmF0YXJDb25maWc/OiBBdmF0YXJDb25maWc7XG4gIEBPdXRwdXQoKSBhdmF0YXJDb25maWdDaGFuZ2VkID0gbmV3IEV2ZW50RW1pdHRlcjxBdmF0YXJDb25maWc+KCk7XG5cbiAgaG92ZXJpbmc6IGJvb2xlYW4gPSBmYWxzZTtcbiAgZWRpdG9yT3BlbjogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICBjdXJyZW50Q29uZmlnOiBBdmF0YXJDb25maWcgPSB7XHJcbiAgICBzdHlsZTogJ2luaXRpYWxzJyxcbiAgICBzZWVkOiAnJyxcbiAgICBiZ0NvbG9yOiAnIzNiODJmNicsXG4gICAgc2hhcGU6ICdjaXJjbGUnXG4gIH07XG5cbiAgY29sb3JzID0gUFJFREVGSU5FRF9DT0xPUlM7XG4gIHN0eWxlcyA9IEFWQVRBUl9TVFlMRVM7XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy5zeW5jQ29uZmlnKCk7XG4gICAgdGhpcy5hdmF0YXJDb25maWdDaGFuZ2VkLmVtaXQoeyAuLi50aGlzLmN1cnJlbnRDb25maWcgfSk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG4gICAgaWYgKCFjaGFuZ2VzWydhdmF0YXJDb25maWcnXSAmJiAhY2hhbmdlc1snZmlyc3ROYW1lJ10gJiYgIWNoYW5nZXNbJ2xhc3ROYW1lJ10pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnN5bmNDb25maWcoKTtcbiAgfVxuXG4gIHByaXZhdGUgc3luY0NvbmZpZygpIHtcbiAgICBpZiAodGhpcy5hdmF0YXJDb25maWcpIHtcbiAgICAgIHRoaXMuY3VycmVudENvbmZpZyA9IHsgLi4udGhpcy5jdXJyZW50Q29uZmlnLCAuLi50aGlzLmF2YXRhckNvbmZpZyB9O1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBkZWZhdWx0U2VlZCA9IHRoaXMuZ2V0RGVmYXVsdFNlZWQoKTtcbiAgICAgIGNvbnN0IGNvbG9ySW5kZXggPSBNYXRoLmFicyh0aGlzLmhhc2goZGVmYXVsdFNlZWQpKSAlIHRoaXMuY29sb3JzLmxlbmd0aDtcbiAgICAgIHRoaXMuY3VycmVudENvbmZpZy5iZ0NvbG9yID0gdGhpcy5jb2xvcnNbY29sb3JJbmRleF07XG4gICAgICB0aGlzLmN1cnJlbnRDb25maWcuc2VlZCA9IHRoaXMuZ2V0RGVmYXVsdFNlZWQoKTtcbiAgICB9XG4gIH1cblxyXG4gIGdldERlZmF1bHRTZWVkKCk6IHN0cmluZyB7XG4gICAgY29uc3QgcGFydHMgPSBbXTtcbiAgICBpZiAodGhpcy5maXJzdE5hbWUpIHBhcnRzLnB1c2godGhpcy5maXJzdE5hbWUpO1xuICAgIGlmICh0aGlzLmxhc3ROYW1lKSBwYXJ0cy5wdXNoKHRoaXMubGFzdE5hbWUpO1xuICAgIHJldHVybiBwYXJ0cy5qb2luKCcgJykgfHwgJ1VzZXInO1xuICB9XG5cbiAgZ2V0QXZhdGFyVXJsKGNvbmZpZzogQXZhdGFyQ29uZmlnID0gdGhpcy5jdXJyZW50Q29uZmlnKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYGRhdGE6aW1hZ2Uvc3ZnK3htbDtjaGFyc2V0PVVURi04LCR7ZW5jb2RlVVJJQ29tcG9uZW50KHRoaXMuZ2V0QXZhdGFyU3ZnKGNvbmZpZykpfWA7XG4gIH1cblxuICBnZXRBdmF0YXJTdmcoY29uZmlnOiBBdmF0YXJDb25maWcgPSB0aGlzLmN1cnJlbnRDb25maWcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHNlZWQgPSB0aGlzLmdldEVmZmVjdGl2ZVNlZWQoY29uZmlnKTtcbiAgICBjb25zdCBoYXNoID0gdGhpcy5oYXNoKHNlZWQpO1xuICAgIGNvbnN0IGluaXRpYWxzID0gdGhpcy5nZXRJbml0aWFscyhzZWVkKTtcbiAgICBjb25zdCBhY2NlbnQgPSB0aGlzLnBpY2tBY2NlbnQoY29uZmlnLmJnQ29sb3IsIGhhc2gpO1xuICAgIGNvbnN0IGRhcmsgPSB0aGlzLmFkanVzdENvbG9yKGNvbmZpZy5iZ0NvbG9yLCAtMzQpO1xuICAgIGNvbnN0IGxpZ2h0ID0gdGhpcy5hZGp1c3RDb2xvcihjb25maWcuYmdDb2xvciwgNDYpO1xuICAgIGNvbnN0IG1hc2sgPSBjb25maWcuc2hhcGUgPT09ICdjaXJjbGUnID8gJzxjbGlwUGF0aCBpZD1cImNsaXBcIj48Y2lyY2xlIGN4PVwiNTBcIiBjeT1cIjUwXCIgcj1cIjUwXCIvPjwvY2xpcFBhdGg+JyA6ICc8Y2xpcFBhdGggaWQ9XCJjbGlwXCI+PHJlY3Qgd2lkdGg9XCIxMDBcIiBoZWlnaHQ9XCIxMDBcIiByeD1cIjEyXCIvPjwvY2xpcFBhdGg+JztcbiAgICBjb25zdCBjb250ZW50ID0gdGhpcy5yZW5kZXJTdHlsZShjb25maWcuc3R5bGUsIGhhc2gsIGluaXRpYWxzLCBjb25maWcuYmdDb2xvciwgYWNjZW50LCBkYXJrLCBsaWdodCk7XG5cbiAgICByZXR1cm4gW1xuICAgICAgJzxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHdpZHRoPVwiMTAwXCIgaGVpZ2h0PVwiMTAwXCIgdmlld0JveD1cIjAgMCAxMDAgMTAwXCIgcm9sZT1cImltZ1wiIGFyaWEtbGFiZWw9XCJBdmF0YXJcIj4nLFxuICAgICAgJzxkZWZzPicsXG4gICAgICBtYXNrLFxuICAgICAgJzxmaWx0ZXIgaWQ9XCJzaGFkb3dcIiB4PVwiLTIwJVwiIHk9XCItMjAlXCIgd2lkdGg9XCIxNDAlXCIgaGVpZ2h0PVwiMTQwJVwiPjxmZURyb3BTaGFkb3cgZHg9XCIwXCIgZHk9XCI0XCIgc3RkRGV2aWF0aW9uPVwiNVwiIGZsb29kLW9wYWNpdHk9XCIuMThcIi8+PC9maWx0ZXI+JyxcbiAgICAgICc8L2RlZnM+JyxcbiAgICAgICc8ZyBjbGlwLXBhdGg9XCJ1cmwoI2NsaXApXCI+JyxcbiAgICAgIGA8cmVjdCB3aWR0aD1cIjEwMFwiIGhlaWdodD1cIjEwMFwiIGZpbGw9XCIke2NvbmZpZy5iZ0NvbG9yfVwiLz5gLFxuICAgICAgY29udGVudCxcbiAgICAgICc8L2c+JyxcbiAgICAgICc8L3N2Zz4nXG4gICAgXS5qb2luKCcnKTtcbiAgfVxuXG4gIHJhbmRvbWl6ZVNlZWQoKSB7XG4gICAgY29uc3QgcmFuZG9tU3RyaW5nID0gYGF2YXRhci0ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cmluZygyLCA4KX1gO1xuICAgIHRoaXMudXBkYXRlQ29uZmlnKHsgc2VlZDogcmFuZG9tU3RyaW5nIH0pO1xuICB9XG5cbiAgc2V0U2VlZCh2YWx1ZTogc3RyaW5nKSB7XG4gICAgdGhpcy51cGRhdGVDb25maWcoeyBzZWVkOiB2YWx1ZSB8fCB0aGlzLmdldERlZmF1bHRTZWVkKCkgfSk7XG4gIH1cblxuICB0b2dnbGVFZGl0b3IoKSB7XG4gICAgdGhpcy5lZGl0b3JPcGVuID0gIXRoaXMuZWRpdG9yT3BlbjtcbiAgfVxuXG4gIHVwZGF0ZUNvbmZpZyhwYXJ0aWFsOiBQYXJ0aWFsPEF2YXRhckNvbmZpZz4pIHtcbiAgICB0aGlzLmN1cnJlbnRDb25maWcgPSB7IC4uLnRoaXMuY3VycmVudENvbmZpZywgLi4ucGFydGlhbCB9O1xuXG4gICAgaWYgKHBhcnRpYWwuc3R5bGUgPT09ICdpbml0aWFscycpIHtcbiAgICAgIHRoaXMuY3VycmVudENvbmZpZy5zZWVkID0gdGhpcy5nZXREZWZhdWx0U2VlZCgpO1xuICAgIH1cbiAgICBcbiAgICB0aGlzLmF2YXRhckNvbmZpZ0NoYW5nZWQuZW1pdCh7IC4uLnRoaXMuY3VycmVudENvbmZpZyB9KTtcbiAgfVxuXG4gIHRyYWNrQnlTdHlsZShfOiBudW1iZXIsIHN0eWxlOiB7IGlkOiBBdmF0YXJTdHlsZUlkIH0pIHtcbiAgICByZXR1cm4gc3R5bGUuaWQ7XG4gIH1cblxuICBwcml2YXRlIHJlbmRlclN0eWxlKHN0eWxlOiBBdmF0YXJTdHlsZUlkLCBoYXNoOiBudW1iZXIsIGluaXRpYWxzOiBzdHJpbmcsIGJnOiBzdHJpbmcsIGFjY2VudDogc3RyaW5nLCBkYXJrOiBzdHJpbmcsIGxpZ2h0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHN3aXRjaCAoc3R5bGUpIHtcbiAgICAgIGNhc2UgJ2luaXRpYWxzJzpcbiAgICAgICAgcmV0dXJuIGA8Y2lyY2xlIGN4PVwiNzZcIiBjeT1cIjIzXCIgcj1cIjI0XCIgZmlsbD1cIiR7bGlnaHR9XCIgb3BhY2l0eT1cIi44XCIvPjxjaXJjbGUgY3g9XCIyMFwiIGN5PVwiNzhcIiByPVwiMzBcIiBmaWxsPVwiJHtkYXJrfVwiIG9wYWNpdHk9XCIuMzJcIi8+PHRleHQgeD1cIjUwXCIgeT1cIjU4XCIgdGV4dC1hbmNob3I9XCJtaWRkbGVcIiBmb250LWZhbWlseT1cIkFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWZcIiBmb250LXNpemU9XCIzNFwiIGZvbnQtd2VpZ2h0PVwiNzAwXCIgZmlsbD1cIiNmZmZcIj4ke2luaXRpYWxzfTwvdGV4dD5gO1xuICAgICAgY2FzZSAnaWRlbnRpY29uJzpcbiAgICAgICAgcmV0dXJuIHRoaXMucmVuZGVySWRlbnRpY29uKGhhc2gsIGFjY2VudCwgZGFyaywgbGlnaHQpO1xuICAgICAgY2FzZSAncmluZ3MnOlxuICAgICAgICByZXR1cm4gYDxjaXJjbGUgY3g9XCI1MFwiIGN5PVwiNTBcIiByPVwiNDJcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cIiR7bGlnaHR9XCIgc3Ryb2tlLXdpZHRoPVwiMTJcIiBvcGFjaXR5PVwiLjlcIi8+PGNpcmNsZSBjeD1cIjUwXCIgY3k9XCI1MFwiIHI9XCIyN1wiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiJHthY2NlbnR9XCIgc3Ryb2tlLXdpZHRoPVwiMTBcIi8+PGNpcmNsZSBjeD1cIjUwXCIgY3k9XCI1MFwiIHI9XCIxMlwiIGZpbGw9XCIke2Rhcmt9XCIvPjxwYXRoIGQ9XCJNNTAgOGE0MiA0MiAwIDAgMSAzNiAyMVwiIHN0cm9rZT1cIiNmZmZcIiBzdHJva2Utd2lkdGg9XCI4XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIG9wYWNpdHk9XCIuNjVcIiBmaWxsPVwibm9uZVwiLz5gO1xuICAgICAgY2FzZSAnc2hhcGVzJzpcbiAgICAgICAgcmV0dXJuIGA8cmVjdCB4PVwiMTJcIiB5PVwiMTRcIiB3aWR0aD1cIjM0XCIgaGVpZ2h0PVwiMzRcIiByeD1cIjEwXCIgZmlsbD1cIiR7bGlnaHR9XCIgdHJhbnNmb3JtPVwicm90YXRlKCR7aGFzaCAlIDI0fSAyOSAzMSlcIi8+PGNpcmNsZSBjeD1cIjY4XCIgY3k9XCIzNFwiIHI9XCIyMFwiIGZpbGw9XCIke2FjY2VudH1cIi8+PHBhdGggZD1cIk0yMSA4MiA0NyA1MGwyOSAzMlpcIiBmaWxsPVwiJHtkYXJrfVwiLz48Y2lyY2xlIGN4PVwiNzRcIiBjeT1cIjc2XCIgcj1cIjEwXCIgZmlsbD1cIiNmZmZcIiBvcGFjaXR5PVwiLjdcIi8+YDtcbiAgICAgIGNhc2UgJ3RodW1icyc6XG4gICAgICAgIHJldHVybiBgPGNpcmNsZSBjeD1cIjUwXCIgY3k9XCI1MFwiIHI9XCIzMVwiIGZpbGw9XCIke2xpZ2h0fVwiLz48cGF0aCBkPVwiTTI5IDUxaDExbDgtMjBjMi01IDEwLTMgOSAzbC0yIDEyaDEzYzUgMCA4IDQgNyA5bC00IDIwYy0xIDUtNSA4LTEwIDhIMzZjLTQgMC03LTMtNy03VjUxWlwiIGZpbGw9XCIjZmZmXCIvPjxyZWN0IHg9XCIyMVwiIHk9XCI1MVwiIHdpZHRoPVwiMTVcIiBoZWlnaHQ9XCIzMlwiIHJ4PVwiNlwiIGZpbGw9XCIke2Rhcmt9XCIvPmA7XG4gICAgICBjYXNlICdhdmF0YWFhcnMnOlxuICAgICAgICByZXR1cm4gYDxjaXJjbGUgY3g9XCI1MFwiIGN5PVwiNTVcIiByPVwiMjhcIiBmaWxsPVwiI2ZmZDdiNVwiLz48cGF0aCBkPVwiTTIzIDQ4YzItMjEgMTctMzIgMzQtMjkgMTMgMiAyMSAxMiAyMiAyOC0xMi04LTI1LTgtMzQtMy04IDUtMTUgNS0yMiA0WlwiIGZpbGw9XCIke2Rhcmt9XCIvPjxjaXJjbGUgY3g9XCIzOVwiIGN5PVwiNTdcIiByPVwiNFwiIGZpbGw9XCIjMWYyOTM3XCIvPjxjaXJjbGUgY3g9XCI2MVwiIGN5PVwiNTdcIiByPVwiNFwiIGZpbGw9XCIjMWYyOTM3XCIvPjxwYXRoIGQ9XCJNNDAgNzNjNyA1IDE0IDUgMjEgMFwiIHN0cm9rZT1cIiM5ZjEyMzlcIiBzdHJva2Utd2lkdGg9XCI0XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIGZpbGw9XCJub25lXCIvPjxwYXRoIGQ9XCJNMTggMTAwYzYtMTggMjEtMjcgMzItMjdzMjYgOSAzMiAyN1pcIiBmaWxsPVwiJHthY2NlbnR9XCIvPmA7XG4gICAgICBjYXNlICdib3R0dHMnOlxuICAgICAgICByZXR1cm4gYDxyZWN0IHg9XCIyMlwiIHk9XCIyOFwiIHdpZHRoPVwiNTZcIiBoZWlnaHQ9XCI0OFwiIHJ4PVwiMTRcIiBmaWxsPVwiJHtsaWdodH1cIiBmaWx0ZXI9XCJ1cmwoI3NoYWRvdylcIi8+PHJlY3QgeD1cIjMyXCIgeT1cIjQ1XCIgd2lkdGg9XCIxM1wiIGhlaWdodD1cIjExXCIgcng9XCI0XCIgZmlsbD1cIiR7ZGFya31cIi8+PHJlY3QgeD1cIjU1XCIgeT1cIjQ1XCIgd2lkdGg9XCIxM1wiIGhlaWdodD1cIjExXCIgcng9XCI0XCIgZmlsbD1cIiR7ZGFya31cIi8+PHBhdGggZD1cIk0zOSA2NmgyMlwiIHN0cm9rZT1cIiNmZmZcIiBzdHJva2Utd2lkdGg9XCI1XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiLz48cGF0aCBkPVwiTTUwIDI4VjE1XCIgc3Ryb2tlPVwiJHtkYXJrfVwiIHN0cm9rZS13aWR0aD1cIjVcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIvPjxjaXJjbGUgY3g9XCI1MFwiIGN5PVwiMTNcIiByPVwiNlwiIGZpbGw9XCIke2FjY2VudH1cIi8+YDtcbiAgICAgIGNhc2UgJ2dsYXNzJzpcbiAgICAgICAgcmV0dXJuIGA8Y2lyY2xlIGN4PVwiMzJcIiBjeT1cIjMwXCIgcj1cIjI0XCIgZmlsbD1cIiNmZmZcIiBvcGFjaXR5PVwiLjM0XCIvPjxjaXJjbGUgY3g9XCI3MlwiIGN5PVwiNzNcIiByPVwiMzJcIiBmaWxsPVwiJHtkYXJrfVwiIG9wYWNpdHk9XCIuMzZcIi8+PHJlY3QgeD1cIjE5XCIgeT1cIjE5XCIgd2lkdGg9XCI2MlwiIGhlaWdodD1cIjYyXCIgcng9XCIxOFwiIGZpbGw9XCIjZmZmXCIgb3BhY2l0eT1cIi4yMlwiIHN0cm9rZT1cIiNmZmZcIiBzdHJva2Utd2lkdGg9XCIyXCIvPjx0ZXh0IHg9XCI1MFwiIHk9XCI1OVwiIHRleHQtYW5jaG9yPVwibWlkZGxlXCIgZm9udC1mYW1pbHk9XCJBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmXCIgZm9udC1zaXplPVwiMjhcIiBmb250LXdlaWdodD1cIjcwMFwiIGZpbGw9XCIjZmZmXCI+JHtpbml0aWFsc308L3RleHQ+YDtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJlbmRlcklkZW50aWNvbihoYXNoOiBudW1iZXIsIGFjY2VudDogc3RyaW5nLCBkYXJrOiBzdHJpbmcsIGxpZ2h0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNlbGxzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IGNvbG9ycyA9IFthY2NlbnQsIGRhcmssIGxpZ2h0XTtcblxuICAgIGZvciAobGV0IHJvdyA9IDA7IHJvdyA8IDU7IHJvdysrKSB7XG4gICAgICBmb3IgKGxldCBjb2wgPSAwOyBjb2wgPCAzOyBjb2wrKykge1xuICAgICAgICBjb25zdCBiaXQgPSAoaGFzaCA+PiAocm93ICogMyArIGNvbCkpICYgMTtcbiAgICAgICAgaWYgKCFiaXQpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHggPSAyMCArIGNvbCAqIDEyO1xuICAgICAgICBjb25zdCBtaXJyb3JYID0gMjAgKyAoNCAtIGNvbCkgKiAxMjtcbiAgICAgICAgY29uc3QgeSA9IDIwICsgcm93ICogMTI7XG4gICAgICAgIGNvbnN0IGNvbG9yID0gY29sb3JzWyhyb3cgKyBjb2wgKyBNYXRoLmFicyhoYXNoKSkgJSBjb2xvcnMubGVuZ3RoXTtcbiAgICAgICAgY2VsbHMucHVzaChgPHJlY3QgeD1cIiR7eH1cIiB5PVwiJHt5fVwiIHdpZHRoPVwiMTBcIiBoZWlnaHQ9XCIxMFwiIHJ4PVwiMlwiIGZpbGw9XCIke2NvbG9yfVwiLz5gKTtcblxuICAgICAgICBpZiAoY29sICE9PSAyKSB7XG4gICAgICAgICAgY2VsbHMucHVzaChgPHJlY3QgeD1cIiR7bWlycm9yWH1cIiB5PVwiJHt5fVwiIHdpZHRoPVwiMTBcIiBoZWlnaHQ9XCIxMFwiIHJ4PVwiMlwiIGZpbGw9XCIke2NvbG9yfVwiLz5gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjZWxscy5qb2luKCcnKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0RWZmZWN0aXZlU2VlZChjb25maWc6IEF2YXRhckNvbmZpZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGNvbmZpZy5zdHlsZSA9PT0gJ2luaXRpYWxzJyA/IHRoaXMuZ2V0RGVmYXVsdFNlZWQoKSA6IChjb25maWcuc2VlZCB8fCB0aGlzLmdldERlZmF1bHRTZWVkKCkpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRJbml0aWFscyhzZWVkOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IG5hbWVzID0gc2VlZC50cmltKCkuc3BsaXQoL1xccysvKS5maWx0ZXIoQm9vbGVhbik7XG4gICAgY29uc3QgZmlyc3QgPSBuYW1lc1swXT8uY2hhckF0KDApIHx8ICdVJztcbiAgICBjb25zdCBzZWNvbmQgPSBuYW1lcy5sZW5ndGggPiAxID8gbmFtZXNbbmFtZXMubGVuZ3RoIC0gMV0uY2hhckF0KDApIDogbmFtZXNbMF0/LmNoYXJBdCgxKSB8fCAnJztcbiAgICByZXR1cm4gYCR7Zmlyc3R9JHtzZWNvbmR9YC50b1VwcGVyQ2FzZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBoYXNoKHZhbHVlOiBzdHJpbmcpOiBudW1iZXIge1xuICAgIGxldCBoYXNoID0gMDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHZhbHVlLmxlbmd0aDsgaSsrKSB7XG4gICAgICBoYXNoID0gKChoYXNoIDw8IDUpIC0gaGFzaCkgKyB2YWx1ZS5jaGFyQ29kZUF0KGkpO1xuICAgICAgaGFzaCB8PSAwO1xuICAgIH1cbiAgICByZXR1cm4gaGFzaCB8fCAxO1xuICB9XG5cbiAgcHJpdmF0ZSBwaWNrQWNjZW50KGNvbG9yOiBzdHJpbmcsIGhhc2g6IG51bWJlcik6IHN0cmluZyB7XG4gICAgY29uc3QgaW5kZXggPSBNYXRoLmFicyhoYXNoKSAlIHRoaXMuY29sb3JzLmxlbmd0aDtcbiAgICBjb25zdCBwaWNrZWQgPSB0aGlzLmNvbG9yc1tpbmRleF07XG4gICAgcmV0dXJuIHBpY2tlZC50b0xvd2VyQ2FzZSgpID09PSBjb2xvci50b0xvd2VyQ2FzZSgpID8gdGhpcy5hZGp1c3RDb2xvcihjb2xvciwgNjApIDogcGlja2VkO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGp1c3RDb2xvcihoZXg6IHN0cmluZywgYW1vdW50OiBudW1iZXIpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNsZWFuID0gaGV4LnJlcGxhY2UoJyMnLCAnJyk7XG4gICAgY29uc3QgbnVtID0gcGFyc2VJbnQoY2xlYW4sIDE2KTtcbiAgICBjb25zdCByID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oMjU1LCAobnVtID4+IDE2KSArIGFtb3VudCkpO1xuICAgIGNvbnN0IGcgPSBNYXRoLm1heCgwLCBNYXRoLm1pbigyNTUsICgobnVtID4+IDgpICYgMHgwMGZmKSArIGFtb3VudCkpO1xuICAgIGNvbnN0IGIgPSBNYXRoLm1heCgwLCBNYXRoLm1pbigyNTUsIChudW0gJiAweDAwMDBmZikgKyBhbW91bnQpKTtcbiAgICByZXR1cm4gYCMkeygoMSA8PCAyNCkgKyAociA8PCAxNikgKyAoZyA8PCA4KSArIGIpLnRvU3RyaW5nKDE2KS5zbGljZSgxKX1gO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiYXZhdGFyLWNvbnRhaW5lclwiIFxyXG4gICAgIFtzdHlsZS53aWR0aC5weF09XCJzaXplXCIgXHJcbiAgICAgW3N0eWxlLmhlaWdodC5weF09XCJzaXplXCJcclxuICAgICBbc3R5bGUuYm9yZGVyUmFkaXVzXT1cImN1cnJlbnRDb25maWcuc2hhcGUgPT09ICdjaXJjbGUnID8gJzUwJScgOiAnOHB4J1wiXHJcbiAgICAgKG1vdXNlZW50ZXIpPVwiaG92ZXJpbmcgPSB0cnVlXCJcclxuICAgICAobW91c2VsZWF2ZSk9XCJob3ZlcmluZyA9IGZhbHNlXCI+XHJcbiAgXHJcbiAgPGRpdiBjbGFzcz1cImF2YXRhci1jb250ZW50XCI+XHJcbiAgICA8aW1nIFtzcmNdPVwiZ2V0QXZhdGFyVXJsKClcIiBhbHQ9XCJBdmF0YXJcIiBjbGFzcz1cImF2YXRhci1pbWFnZVwiPlxyXG4gIDwvZGl2PlxyXG5cclxuICA8ZGl2IGNsYXNzPVwiZWRpdC1vdmVybGF5XCIgKm5nSWY9XCJlZGl0YWJsZSAmJiBob3ZlcmluZ1wiIChjbGljayk9XCJ0b2dnbGVFZGl0b3IoKVwiPlxyXG4gICAgPHN2ZyB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cImN1cnJlbnRDb2xvclwiIHdpZHRoPVwiMjRcIiBoZWlnaHQ9XCIyNFwiPlxyXG4gICAgICA8cGF0aCBkPVwiTTMgMTcuMjVWMjFoMy43NUwxNy44MSA5Ljk0bC0zLjc1LTMuNzVMMyAxNy4yNXpNMjAuNzEgNy4wNGMuMzktLjM5LjM5LTEuMDIgMC0xLjQxbC0yLjM0LTIuMzRjLS4zOS0uMzktMS4wMi0uMzktMS40MSAwbC0xLjgzIDEuODMgMy43NSAzLjc1IDEuODMtMS44M3pcIi8+XHJcbiAgICA8L3N2Zz5cclxuICA8L2Rpdj5cclxuPC9kaXY+XHJcblxyXG48ZGl2IGNsYXNzPVwiZWRpdG9yLXBvcG92ZXJcIiAqbmdJZj1cImVkaXRvck9wZW5cIj5cclxuICA8ZGl2IGNsYXNzPVwiZWRpdG9yLWhlYWRlclwiPlxyXG4gICAgPGgzPkN1c3RvbWl6ZSBBdmF0YXI8L2gzPlxyXG4gICAgPGJ1dHRvbiBjbGFzcz1cImNsb3NlLWJ0blwiIChjbGljayk9XCJ0b2dnbGVFZGl0b3IoKVwiPiZ0aW1lczs8L2J1dHRvbj5cclxuICA8L2Rpdj5cclxuICBcclxuICA8ZGl2IGNsYXNzPVwiZWRpdG9yLWJvZHlcIj5cclxuICAgIDxkaXYgY2xhc3M9XCJzZWN0aW9uXCI+XHJcbiAgICAgIDxsYWJlbD5TaGFwZTwvbGFiZWw+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJzaGFwZS1vcHRpb25zXCI+XHJcbiAgICAgICAgPGJ1dHRvbiBbY2xhc3MuYWN0aXZlXT1cImN1cnJlbnRDb25maWcuc2hhcGUgPT09ICdjaXJjbGUnXCIgKGNsaWNrKT1cInVwZGF0ZUNvbmZpZyh7c2hhcGU6ICdjaXJjbGUnfSlcIj5DaXJjbGU8L2J1dHRvbj5cclxuICAgICAgICA8YnV0dG9uIFtjbGFzcy5hY3RpdmVdPVwiY3VycmVudENvbmZpZy5zaGFwZSA9PT0gJ3NxdWFyZSdcIiAoY2xpY2spPVwidXBkYXRlQ29uZmlnKHtzaGFwZTogJ3NxdWFyZSd9KVwiPlNxdWFyZTwvYnV0dG9uPlxyXG4gICAgICA8L2Rpdj5cclxuICAgIDwvZGl2PlxyXG5cclxuICAgIDxkaXYgY2xhc3M9XCJzZWN0aW9uXCI+XHJcbiAgICAgIDxsYWJlbD5CYWNrZ3JvdW5kIENvbG9yPC9sYWJlbD5cclxuICAgICAgPGRpdiBjbGFzcz1cImNvbG9yLWdyaWRcIj5cclxuICAgICAgICA8YnV0dG9uICpuZ0Zvcj1cImxldCBjb2xvciBvZiBjb2xvcnNcIiBcclxuICAgICAgICAgICAgICAgIGNsYXNzPVwiY29sb3Itc3dhdGNoXCIgXHJcbiAgICAgICAgICAgICAgICBbc3R5bGUuYmFja2dyb3VuZENvbG9yXT1cImNvbG9yXCJcclxuICAgICAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwiY3VycmVudENvbmZpZy5iZ0NvbG9yID09PSBjb2xvclwiXHJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwidXBkYXRlQ29uZmlnKHtiZ0NvbG9yOiBjb2xvcn0pXCI+XHJcbiAgICAgICAgPC9idXR0b24+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPGRpdiBjbGFzcz1cInNlY3Rpb25cIj5cclxuICAgICAgPGRpdiBjbGFzcz1cInNlY3Rpb24tdGl0bGUtcm93XCI+XHJcbiAgICAgICAgPGxhYmVsPlN0eWxlIENhdGVnb3J5PC9sYWJlbD5cclxuICAgICAgICA8YnV0dG9uIGNsYXNzPVwicmFuZG9taXplLWJ0blwiIChjbGljayk9XCJyYW5kb21pemVTZWVkKClcIj7wn46yIFJhbmRvbWl6ZTwvYnV0dG9uPlxyXG4gICAgICA8L2Rpdj5cclxuICAgICAgPGRpdiBjbGFzcz1cInN0eWxlLWdyaWRcIj5cclxuICAgICAgICA8ZGl2ICpuZ0Zvcj1cImxldCBzdHlsZSBvZiBzdHlsZXNcIiBcclxuICAgICAgICAgICAgIGNsYXNzPVwic3R5bGUtY2FyZFwiXHJcbiAgICAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cImN1cnJlbnRDb25maWcuc3R5bGUgPT09IHN0eWxlLmlkXCJcclxuICAgICAgICAgICAgIChjbGljayk9XCJ1cGRhdGVDb25maWcoe3N0eWxlOiBzdHlsZS5pZH0pXCI+XHJcbiAgICAgICAgICA8aW1nIFtzcmNdPVwiZ2V0QXZhdGFyVXJsKHsgc3R5bGU6IHN0eWxlLmlkLCBzZWVkOiBjdXJyZW50Q29uZmlnLnNlZWQsIGJnQ29sb3I6IGN1cnJlbnRDb25maWcuYmdDb2xvciwgc2hhcGU6IGN1cnJlbnRDb25maWcuc2hhcGUgfSlcIiBhbHQ9XCJ7e3N0eWxlLm5hbWV9fVwiPlxyXG4gICAgICAgICAgPHNwYW4+e3sgc3R5bGUubmFtZSB9fTwvc3Bhbj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuPC9kaXY+XHJcbiJdfQ==
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { NgAvatarCreatorComponent } from './ng-avatar-creator.component';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export class NgAvatarCreatorModule {
|
|
6
|
+
}
|
|
7
|
+
NgAvatarCreatorModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
8
|
+
NgAvatarCreatorModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, declarations: [NgAvatarCreatorComponent], imports: [CommonModule], exports: [NgAvatarCreatorComponent] });
|
|
9
|
+
NgAvatarCreatorModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, imports: [CommonModule] });
|
|
10
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, decorators: [{
|
|
11
|
+
type: NgModule,
|
|
12
|
+
args: [{
|
|
13
|
+
declarations: [
|
|
14
|
+
NgAvatarCreatorComponent
|
|
15
|
+
],
|
|
16
|
+
imports: [
|
|
17
|
+
CommonModule
|
|
18
|
+
],
|
|
19
|
+
exports: [
|
|
20
|
+
NgAvatarCreatorComponent
|
|
21
|
+
]
|
|
22
|
+
}]
|
|
23
|
+
}] });
|
|
24
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctYXZhdGFyLWNyZWF0b3IubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmctYXZhdGFyLWNyZWF0b3Ivc3JjL2xpYi9uZy1hdmF0YXItY3JlYXRvci5tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sK0JBQStCLENBQUM7O0FBZXpFLE1BQU0sT0FBTyxxQkFBcUI7O21IQUFyQixxQkFBcUI7b0hBQXJCLHFCQUFxQixpQkFUOUIsd0JBQXdCLGFBR3hCLFlBQVksYUFHWix3QkFBd0I7b0hBR2YscUJBQXFCLFlBTjlCLFlBQVk7NEZBTUgscUJBQXFCO2tCQVhqQyxRQUFRO21CQUFDO29CQUNSLFlBQVksRUFBRTt3QkFDWix3QkFBd0I7cUJBQ3pCO29CQUNELE9BQU8sRUFBRTt3QkFDUCxZQUFZO3FCQUNiO29CQUNELE9BQU8sRUFBRTt3QkFDUCx3QkFBd0I7cUJBQ3pCO2lCQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTmdNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgTmdBdmF0YXJDcmVhdG9yQ29tcG9uZW50IH0gZnJvbSAnLi9uZy1hdmF0YXItY3JlYXRvci5jb21wb25lbnQnO1xyXG5cclxuXHJcblxyXG5ATmdNb2R1bGUoe1xyXG4gIGRlY2xhcmF0aW9uczogW1xyXG4gICAgTmdBdmF0YXJDcmVhdG9yQ29tcG9uZW50XHJcbiAgXSxcclxuICBpbXBvcnRzOiBbXHJcbiAgICBDb21tb25Nb2R1bGVcclxuICBdLFxyXG4gIGV4cG9ydHM6IFtcclxuICAgIE5nQXZhdGFyQ3JlYXRvckNvbXBvbmVudFxyXG4gIF1cclxufSlcclxuZXhwb3J0IGNsYXNzIE5nQXZhdGFyQ3JlYXRvck1vZHVsZSB7IH1cclxuIl19
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export class NgAvatarCreatorService {
|
|
4
|
+
constructor() { }
|
|
5
|
+
}
|
|
6
|
+
NgAvatarCreatorService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
7
|
+
NgAvatarCreatorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorService, providedIn: 'root' });
|
|
8
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorService, decorators: [{
|
|
9
|
+
type: Injectable,
|
|
10
|
+
args: [{
|
|
11
|
+
providedIn: 'root'
|
|
12
|
+
}]
|
|
13
|
+
}], ctorParameters: function () { return []; } });
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctYXZhdGFyLWNyZWF0b3Iuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25nLWF2YXRhci1jcmVhdG9yL3NyYy9saWIvbmctYXZhdGFyLWNyZWF0b3Iuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDOztBQUszQyxNQUFNLE9BQU8sc0JBQXNCO0lBRWpDLGdCQUFnQixDQUFDOztvSEFGTixzQkFBc0I7d0hBQXRCLHNCQUFzQixjQUZyQixNQUFNOzRGQUVQLHNCQUFzQjtrQkFIbEMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcblxyXG5ASW5qZWN0YWJsZSh7XHJcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBOZ0F2YXRhckNyZWF0b3JTZXJ2aWNlIHtcclxuXHJcbiAgY29uc3RydWN0b3IoKSB7IH1cclxufVxyXG4iXX0=
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Public API Surface of ng-avatar-creator
|
|
3
|
+
*/
|
|
4
|
+
export * from './lib/ng-avatar-creator.service';
|
|
5
|
+
export * from './lib/ng-avatar-creator.component';
|
|
6
|
+
export * from './lib/ng-avatar-creator.module';
|
|
7
|
+
export * from './lib/avatar-models';
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL25nLWF2YXRhci1jcmVhdG9yL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxpQ0FBaUMsQ0FBQztBQUNoRCxjQUFjLG1DQUFtQyxDQUFDO0FBQ2xELGNBQWMsZ0NBQWdDLENBQUM7QUFDL0MsY0FBYyxxQkFBcUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXHJcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiBuZy1hdmF0YXItY3JlYXRvclxyXG4gKi9cclxuXHJcbmV4cG9ydCAqIGZyb20gJy4vbGliL25nLWF2YXRhci1jcmVhdG9yLnNlcnZpY2UnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9uZy1hdmF0YXItY3JlYXRvci5jb21wb25lbnQnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9uZy1hdmF0YXItY3JlYXRvci5tb2R1bGUnO1xyXG5leHBvcnQgKiBmcm9tICcuL2xpYi9hdmF0YXItbW9kZWxzJztcclxuIl19
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Injectable, EventEmitter, Component, Input, Output, NgModule } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
|
|
6
|
+
class NgAvatarCreatorService {
|
|
7
|
+
constructor() { }
|
|
8
|
+
}
|
|
9
|
+
NgAvatarCreatorService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10
|
+
NgAvatarCreatorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorService, providedIn: 'root' });
|
|
11
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorService, decorators: [{
|
|
12
|
+
type: Injectable,
|
|
13
|
+
args: [{
|
|
14
|
+
providedIn: 'root'
|
|
15
|
+
}]
|
|
16
|
+
}], ctorParameters: function () { return []; } });
|
|
17
|
+
|
|
18
|
+
const AVATAR_STYLES = [
|
|
19
|
+
{ id: 'initials', name: 'Initials' },
|
|
20
|
+
{ id: 'identicon', name: 'Identicon' },
|
|
21
|
+
{ id: 'rings', name: 'Rings' },
|
|
22
|
+
{ id: 'shapes', name: 'Shapes' },
|
|
23
|
+
{ id: 'thumbs', name: 'Thumbs' },
|
|
24
|
+
{ id: 'avataaars', name: 'Avatars' },
|
|
25
|
+
{ id: 'bottts', name: 'Bots' },
|
|
26
|
+
{ id: 'glass', name: 'Glass' }
|
|
27
|
+
];
|
|
28
|
+
const PREDEFINED_COLORS = [
|
|
29
|
+
'#ef4444', '#f97316', '#f59e0b', '#84cc16', '#22c55e',
|
|
30
|
+
'#14b8a6', '#06b6d4', '#0ea5e9', '#3b82f6', '#6366f1',
|
|
31
|
+
'#8b5cf6', '#a855f7', '#d946ef', '#ec4899', '#f43f5e',
|
|
32
|
+
'#475569', '#111827', '#7c2d12', '#365314', '#164e63'
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
class NgAvatarCreatorComponent {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.firstName = '';
|
|
38
|
+
this.lastName = '';
|
|
39
|
+
this.size = 64;
|
|
40
|
+
this.editable = false;
|
|
41
|
+
this.editorTitle = 'Customize Avatar';
|
|
42
|
+
this.avatarConfigChanged = new EventEmitter();
|
|
43
|
+
this.hovering = false;
|
|
44
|
+
this.editorOpen = false;
|
|
45
|
+
this.currentConfig = {
|
|
46
|
+
style: 'initials',
|
|
47
|
+
seed: '',
|
|
48
|
+
bgColor: '#3b82f6',
|
|
49
|
+
shape: 'circle'
|
|
50
|
+
};
|
|
51
|
+
this.colors = PREDEFINED_COLORS;
|
|
52
|
+
this.styles = AVATAR_STYLES;
|
|
53
|
+
}
|
|
54
|
+
ngOnInit() {
|
|
55
|
+
this.syncConfig();
|
|
56
|
+
this.avatarConfigChanged.emit(Object.assign({}, this.currentConfig));
|
|
57
|
+
}
|
|
58
|
+
ngOnChanges(changes) {
|
|
59
|
+
if (!changes['avatarConfig'] && !changes['firstName'] && !changes['lastName']) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.syncConfig();
|
|
63
|
+
}
|
|
64
|
+
syncConfig() {
|
|
65
|
+
if (this.avatarConfig) {
|
|
66
|
+
this.currentConfig = Object.assign(Object.assign({}, this.currentConfig), this.avatarConfig);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const defaultSeed = this.getDefaultSeed();
|
|
70
|
+
const colorIndex = Math.abs(this.hash(defaultSeed)) % this.colors.length;
|
|
71
|
+
this.currentConfig.bgColor = this.colors[colorIndex];
|
|
72
|
+
this.currentConfig.seed = this.getDefaultSeed();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
getDefaultSeed() {
|
|
76
|
+
const parts = [];
|
|
77
|
+
if (this.firstName)
|
|
78
|
+
parts.push(this.firstName);
|
|
79
|
+
if (this.lastName)
|
|
80
|
+
parts.push(this.lastName);
|
|
81
|
+
return parts.join(' ') || 'User';
|
|
82
|
+
}
|
|
83
|
+
getAvatarUrl(config = this.currentConfig) {
|
|
84
|
+
return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(this.getAvatarSvg(config))}`;
|
|
85
|
+
}
|
|
86
|
+
getAvatarSvg(config = this.currentConfig) {
|
|
87
|
+
const seed = this.getEffectiveSeed(config);
|
|
88
|
+
const hash = this.hash(seed);
|
|
89
|
+
const initials = this.getInitials(seed);
|
|
90
|
+
const accent = this.pickAccent(config.bgColor, hash);
|
|
91
|
+
const dark = this.adjustColor(config.bgColor, -34);
|
|
92
|
+
const light = this.adjustColor(config.bgColor, 46);
|
|
93
|
+
const mask = config.shape === 'circle' ? '<clipPath id="clip"><circle cx="50" cy="50" r="50"/></clipPath>' : '<clipPath id="clip"><rect width="100" height="100" rx="12"/></clipPath>';
|
|
94
|
+
const content = this.renderStyle(config.style, hash, initials, config.bgColor, accent, dark, light);
|
|
95
|
+
return [
|
|
96
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" role="img" aria-label="Avatar">',
|
|
97
|
+
'<defs>',
|
|
98
|
+
mask,
|
|
99
|
+
'<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="4" stdDeviation="5" flood-opacity=".18"/></filter>',
|
|
100
|
+
'</defs>',
|
|
101
|
+
'<g clip-path="url(#clip)">',
|
|
102
|
+
`<rect width="100" height="100" fill="${config.bgColor}"/>`,
|
|
103
|
+
content,
|
|
104
|
+
'</g>',
|
|
105
|
+
'</svg>'
|
|
106
|
+
].join('');
|
|
107
|
+
}
|
|
108
|
+
randomizeSeed() {
|
|
109
|
+
const randomString = `avatar-${Math.random().toString(36).substring(2, 8)}`;
|
|
110
|
+
this.updateConfig({ seed: randomString });
|
|
111
|
+
}
|
|
112
|
+
setSeed(value) {
|
|
113
|
+
this.updateConfig({ seed: value || this.getDefaultSeed() });
|
|
114
|
+
}
|
|
115
|
+
toggleEditor() {
|
|
116
|
+
this.editorOpen = !this.editorOpen;
|
|
117
|
+
}
|
|
118
|
+
updateConfig(partial) {
|
|
119
|
+
this.currentConfig = Object.assign(Object.assign({}, this.currentConfig), partial);
|
|
120
|
+
if (partial.style === 'initials') {
|
|
121
|
+
this.currentConfig.seed = this.getDefaultSeed();
|
|
122
|
+
}
|
|
123
|
+
this.avatarConfigChanged.emit(Object.assign({}, this.currentConfig));
|
|
124
|
+
}
|
|
125
|
+
trackByStyle(_, style) {
|
|
126
|
+
return style.id;
|
|
127
|
+
}
|
|
128
|
+
renderStyle(style, hash, initials, bg, accent, dark, light) {
|
|
129
|
+
switch (style) {
|
|
130
|
+
case 'initials':
|
|
131
|
+
return `<circle cx="76" cy="23" r="24" fill="${light}" opacity=".8"/><circle cx="20" cy="78" r="30" fill="${dark}" opacity=".32"/><text x="50" y="58" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-size="34" font-weight="700" fill="#fff">${initials}</text>`;
|
|
132
|
+
case 'identicon':
|
|
133
|
+
return this.renderIdenticon(hash, accent, dark, light);
|
|
134
|
+
case 'rings':
|
|
135
|
+
return `<circle cx="50" cy="50" r="42" fill="none" stroke="${light}" stroke-width="12" opacity=".9"/><circle cx="50" cy="50" r="27" fill="none" stroke="${accent}" stroke-width="10"/><circle cx="50" cy="50" r="12" fill="${dark}"/><path d="M50 8a42 42 0 0 1 36 21" stroke="#fff" stroke-width="8" stroke-linecap="round" opacity=".65" fill="none"/>`;
|
|
136
|
+
case 'shapes':
|
|
137
|
+
return `<rect x="12" y="14" width="34" height="34" rx="10" fill="${light}" transform="rotate(${hash % 24} 29 31)"/><circle cx="68" cy="34" r="20" fill="${accent}"/><path d="M21 82 47 50l29 32Z" fill="${dark}"/><circle cx="74" cy="76" r="10" fill="#fff" opacity=".7"/>`;
|
|
138
|
+
case 'thumbs':
|
|
139
|
+
return `<circle cx="50" cy="50" r="31" fill="${light}"/><path d="M29 51h11l8-20c2-5 10-3 9 3l-2 12h13c5 0 8 4 7 9l-4 20c-1 5-5 8-10 8H36c-4 0-7-3-7-7V51Z" fill="#fff"/><rect x="21" y="51" width="15" height="32" rx="6" fill="${dark}"/>`;
|
|
140
|
+
case 'avataaars':
|
|
141
|
+
return `<circle cx="50" cy="55" r="28" fill="#ffd7b5"/><path d="M23 48c2-21 17-32 34-29 13 2 21 12 22 28-12-8-25-8-34-3-8 5-15 5-22 4Z" fill="${dark}"/><circle cx="39" cy="57" r="4" fill="#1f2937"/><circle cx="61" cy="57" r="4" fill="#1f2937"/><path d="M40 73c7 5 14 5 21 0" stroke="#9f1239" stroke-width="4" stroke-linecap="round" fill="none"/><path d="M18 100c6-18 21-27 32-27s26 9 32 27Z" fill="${accent}"/>`;
|
|
142
|
+
case 'bottts':
|
|
143
|
+
return `<rect x="22" y="28" width="56" height="48" rx="14" fill="${light}" filter="url(#shadow)"/><rect x="32" y="45" width="13" height="11" rx="4" fill="${dark}"/><rect x="55" y="45" width="13" height="11" rx="4" fill="${dark}"/><path d="M39 66h22" stroke="#fff" stroke-width="5" stroke-linecap="round"/><path d="M50 28V15" stroke="${dark}" stroke-width="5" stroke-linecap="round"/><circle cx="50" cy="13" r="6" fill="${accent}"/>`;
|
|
144
|
+
case 'glass':
|
|
145
|
+
return `<circle cx="32" cy="30" r="24" fill="#fff" opacity=".34"/><circle cx="72" cy="73" r="32" fill="${dark}" opacity=".36"/><rect x="19" y="19" width="62" height="62" rx="18" fill="#fff" opacity=".22" stroke="#fff" stroke-width="2"/><text x="50" y="59" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-size="28" font-weight="700" fill="#fff">${initials}</text>`;
|
|
146
|
+
default:
|
|
147
|
+
return '';
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
renderIdenticon(hash, accent, dark, light) {
|
|
151
|
+
const cells = [];
|
|
152
|
+
const colors = [accent, dark, light];
|
|
153
|
+
for (let row = 0; row < 5; row++) {
|
|
154
|
+
for (let col = 0; col < 3; col++) {
|
|
155
|
+
const bit = (hash >> (row * 3 + col)) & 1;
|
|
156
|
+
if (!bit) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const x = 20 + col * 12;
|
|
160
|
+
const mirrorX = 20 + (4 - col) * 12;
|
|
161
|
+
const y = 20 + row * 12;
|
|
162
|
+
const color = colors[(row + col + Math.abs(hash)) % colors.length];
|
|
163
|
+
cells.push(`<rect x="${x}" y="${y}" width="10" height="10" rx="2" fill="${color}"/>`);
|
|
164
|
+
if (col !== 2) {
|
|
165
|
+
cells.push(`<rect x="${mirrorX}" y="${y}" width="10" height="10" rx="2" fill="${color}"/>`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return cells.join('');
|
|
170
|
+
}
|
|
171
|
+
getEffectiveSeed(config) {
|
|
172
|
+
return config.style === 'initials' ? this.getDefaultSeed() : (config.seed || this.getDefaultSeed());
|
|
173
|
+
}
|
|
174
|
+
getInitials(seed) {
|
|
175
|
+
var _a, _b;
|
|
176
|
+
const names = seed.trim().split(/\s+/).filter(Boolean);
|
|
177
|
+
const first = ((_a = names[0]) === null || _a === void 0 ? void 0 : _a.charAt(0)) || 'U';
|
|
178
|
+
const second = names.length > 1 ? names[names.length - 1].charAt(0) : ((_b = names[0]) === null || _b === void 0 ? void 0 : _b.charAt(1)) || '';
|
|
179
|
+
return `${first}${second}`.toUpperCase();
|
|
180
|
+
}
|
|
181
|
+
hash(value) {
|
|
182
|
+
let hash = 0;
|
|
183
|
+
for (let i = 0; i < value.length; i++) {
|
|
184
|
+
hash = ((hash << 5) - hash) + value.charCodeAt(i);
|
|
185
|
+
hash |= 0;
|
|
186
|
+
}
|
|
187
|
+
return hash || 1;
|
|
188
|
+
}
|
|
189
|
+
pickAccent(color, hash) {
|
|
190
|
+
const index = Math.abs(hash) % this.colors.length;
|
|
191
|
+
const picked = this.colors[index];
|
|
192
|
+
return picked.toLowerCase() === color.toLowerCase() ? this.adjustColor(color, 60) : picked;
|
|
193
|
+
}
|
|
194
|
+
adjustColor(hex, amount) {
|
|
195
|
+
const clean = hex.replace('#', '');
|
|
196
|
+
const num = parseInt(clean, 16);
|
|
197
|
+
const r = Math.max(0, Math.min(255, (num >> 16) + amount));
|
|
198
|
+
const g = Math.max(0, Math.min(255, ((num >> 8) & 0x00ff) + amount));
|
|
199
|
+
const b = Math.max(0, Math.min(255, (num & 0x0000ff) + amount));
|
|
200
|
+
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
NgAvatarCreatorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
204
|
+
NgAvatarCreatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: NgAvatarCreatorComponent, selector: "lib-ng-avatar-creator", inputs: { firstName: "firstName", lastName: "lastName", size: "size", editable: "editable", editorTitle: "editorTitle", avatarConfig: "avatarConfig" }, outputs: { avatarConfigChanged: "avatarConfigChanged" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"avatar-container\" \r\n [style.width.px]=\"size\" \r\n [style.height.px]=\"size\"\r\n [style.borderRadius]=\"currentConfig.shape === 'circle' ? '50%' : '8px'\"\r\n (mouseenter)=\"hovering = true\"\r\n (mouseleave)=\"hovering = false\">\r\n \r\n <div class=\"avatar-content\">\r\n <img [src]=\"getAvatarUrl()\" alt=\"Avatar\" class=\"avatar-image\">\r\n </div>\r\n\r\n <div class=\"edit-overlay\" *ngIf=\"editable && hovering\" (click)=\"toggleEditor()\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"24\" height=\"24\">\r\n <path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\"/>\r\n </svg>\r\n </div>\r\n</div>\r\n\r\n<div class=\"editor-popover\" *ngIf=\"editorOpen\">\r\n <div class=\"editor-header\">\r\n <h3>Customize Avatar</h3>\r\n <button class=\"close-btn\" (click)=\"toggleEditor()\">×</button>\r\n </div>\r\n \r\n <div class=\"editor-body\">\r\n <div class=\"section\">\r\n <label>Shape</label>\r\n <div class=\"shape-options\">\r\n <button [class.active]=\"currentConfig.shape === 'circle'\" (click)=\"updateConfig({shape: 'circle'})\">Circle</button>\r\n <button [class.active]=\"currentConfig.shape === 'square'\" (click)=\"updateConfig({shape: 'square'})\">Square</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <label>Background Color</label>\r\n <div class=\"color-grid\">\r\n <button *ngFor=\"let color of colors\" \r\n class=\"color-swatch\" \r\n [style.backgroundColor]=\"color\"\r\n [class.active]=\"currentConfig.bgColor === color\"\r\n (click)=\"updateConfig({bgColor: color})\">\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title-row\">\r\n <label>Style Category</label>\r\n <button class=\"randomize-btn\" (click)=\"randomizeSeed()\">\uD83C\uDFB2 Randomize</button>\r\n </div>\r\n <div class=\"style-grid\">\r\n <div *ngFor=\"let style of styles\" \r\n class=\"style-card\"\r\n [class.active]=\"currentConfig.style === style.id\"\r\n (click)=\"updateConfig({style: style.id})\">\r\n <img [src]=\"getAvatarUrl({ style: style.id, seed: currentConfig.seed, bgColor: currentConfig.bgColor, shape: currentConfig.shape })\" alt=\"{{style.name}}\">\r\n <span>{{ style.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{display:inline-block;position:relative;font-family:Inter,Roboto,sans-serif}.avatar-container{position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;transition:all .3s ease;-webkit-user-select:none;user-select:none}.avatar-content{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.avatar-image{width:100%;height:100%;object-fit:cover}.edit-overlay{position:absolute;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;color:#fff;cursor:pointer;opacity:0;animation:fadeIn .2s forwards;backdrop-filter:blur(2px)}@keyframes fadeIn{to{opacity:1}}.editor-popover{position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%);width:320px;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;z-index:1000;border:1px solid #e2e8f0;padding:16px;animation:slideUp .3s cubic-bezier(.16,1,.3,1)}@keyframes slideUp{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}.editor-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;border-bottom:1px solid #f1f5f9;padding-bottom:8px}.editor-header h3{margin:0;font-size:14px;font-weight:600;color:#334155}.close-btn{background:none;border:none;font-size:20px;cursor:pointer;color:#94a3b8;padding:0;line-height:1}.close-btn:hover{color:#475569}.section{margin-bottom:16px}.section:last-child{margin-bottom:0}.section-title-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.section label{display:block;font-size:12px;color:#64748b;margin:0;font-weight:500;text-transform:uppercase;letter-spacing:.5px}.randomize-btn{background:#f1f5f9;border:none;border-radius:4px;padding:4px 8px;font-size:11px;color:#475569;cursor:pointer;font-weight:600;transition:background .2s}.randomize-btn:hover{background:#e2e8f0;color:#0f172a}.shape-options{display:flex;gap:8px}.shape-options button{flex:1;padding:8px;border:1px solid #e2e8f0;background:#f8fafc;border-radius:6px;cursor:pointer;font-size:13px;color:#475569;transition:all .2s}.shape-options button:hover{background:#f1f5f9}.shape-options button.active{background:#3b82f6;color:#fff;border-color:#3b82f6}.color-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}.color-swatch{width:100%;aspect-ratio:1;border-radius:50%;border:2px solid transparent;cursor:pointer;transition:transform .2s}.color-swatch:hover{transform:scale(1.1)}.color-swatch.active{border-color:#333;box-shadow:0 0 0 2px #fff inset}.style-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;max-height:200px;overflow-y:auto;padding-right:4px}.style-grid::-webkit-scrollbar{width:4px}.style-grid::-webkit-scrollbar-thumb{background-color:#cbd5e1;border-radius:4px}.style-card{border:1px solid #e2e8f0;background:white;border-radius:8px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:8px 4px;transition:all .2s}.style-card:hover{background:#f8fafc;border-color:#cbd5e1}.style-card.active{border-color:#3b82f6;background:#eff6ff}.style-card img{width:40px;height:40px;margin-bottom:4px;border-radius:50%}.style-card span{font-size:10px;color:#475569;font-weight:500;text-align:center}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
205
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorComponent, decorators: [{
|
|
206
|
+
type: Component,
|
|
207
|
+
args: [{ selector: 'lib-ng-avatar-creator', template: "<div class=\"avatar-container\" \r\n [style.width.px]=\"size\" \r\n [style.height.px]=\"size\"\r\n [style.borderRadius]=\"currentConfig.shape === 'circle' ? '50%' : '8px'\"\r\n (mouseenter)=\"hovering = true\"\r\n (mouseleave)=\"hovering = false\">\r\n \r\n <div class=\"avatar-content\">\r\n <img [src]=\"getAvatarUrl()\" alt=\"Avatar\" class=\"avatar-image\">\r\n </div>\r\n\r\n <div class=\"edit-overlay\" *ngIf=\"editable && hovering\" (click)=\"toggleEditor()\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"24\" height=\"24\">\r\n <path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\"/>\r\n </svg>\r\n </div>\r\n</div>\r\n\r\n<div class=\"editor-popover\" *ngIf=\"editorOpen\">\r\n <div class=\"editor-header\">\r\n <h3>Customize Avatar</h3>\r\n <button class=\"close-btn\" (click)=\"toggleEditor()\">×</button>\r\n </div>\r\n \r\n <div class=\"editor-body\">\r\n <div class=\"section\">\r\n <label>Shape</label>\r\n <div class=\"shape-options\">\r\n <button [class.active]=\"currentConfig.shape === 'circle'\" (click)=\"updateConfig({shape: 'circle'})\">Circle</button>\r\n <button [class.active]=\"currentConfig.shape === 'square'\" (click)=\"updateConfig({shape: 'square'})\">Square</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <label>Background Color</label>\r\n <div class=\"color-grid\">\r\n <button *ngFor=\"let color of colors\" \r\n class=\"color-swatch\" \r\n [style.backgroundColor]=\"color\"\r\n [class.active]=\"currentConfig.bgColor === color\"\r\n (click)=\"updateConfig({bgColor: color})\">\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title-row\">\r\n <label>Style Category</label>\r\n <button class=\"randomize-btn\" (click)=\"randomizeSeed()\">\uD83C\uDFB2 Randomize</button>\r\n </div>\r\n <div class=\"style-grid\">\r\n <div *ngFor=\"let style of styles\" \r\n class=\"style-card\"\r\n [class.active]=\"currentConfig.style === style.id\"\r\n (click)=\"updateConfig({style: style.id})\">\r\n <img [src]=\"getAvatarUrl({ style: style.id, seed: currentConfig.seed, bgColor: currentConfig.bgColor, shape: currentConfig.shape })\" alt=\"{{style.name}}\">\r\n <span>{{ style.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{display:inline-block;position:relative;font-family:Inter,Roboto,sans-serif}.avatar-container{position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;transition:all .3s ease;-webkit-user-select:none;user-select:none}.avatar-content{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.avatar-image{width:100%;height:100%;object-fit:cover}.edit-overlay{position:absolute;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;color:#fff;cursor:pointer;opacity:0;animation:fadeIn .2s forwards;backdrop-filter:blur(2px)}@keyframes fadeIn{to{opacity:1}}.editor-popover{position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%);width:320px;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;z-index:1000;border:1px solid #e2e8f0;padding:16px;animation:slideUp .3s cubic-bezier(.16,1,.3,1)}@keyframes slideUp{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}.editor-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;border-bottom:1px solid #f1f5f9;padding-bottom:8px}.editor-header h3{margin:0;font-size:14px;font-weight:600;color:#334155}.close-btn{background:none;border:none;font-size:20px;cursor:pointer;color:#94a3b8;padding:0;line-height:1}.close-btn:hover{color:#475569}.section{margin-bottom:16px}.section:last-child{margin-bottom:0}.section-title-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.section label{display:block;font-size:12px;color:#64748b;margin:0;font-weight:500;text-transform:uppercase;letter-spacing:.5px}.randomize-btn{background:#f1f5f9;border:none;border-radius:4px;padding:4px 8px;font-size:11px;color:#475569;cursor:pointer;font-weight:600;transition:background .2s}.randomize-btn:hover{background:#e2e8f0;color:#0f172a}.shape-options{display:flex;gap:8px}.shape-options button{flex:1;padding:8px;border:1px solid #e2e8f0;background:#f8fafc;border-radius:6px;cursor:pointer;font-size:13px;color:#475569;transition:all .2s}.shape-options button:hover{background:#f1f5f9}.shape-options button.active{background:#3b82f6;color:#fff;border-color:#3b82f6}.color-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}.color-swatch{width:100%;aspect-ratio:1;border-radius:50%;border:2px solid transparent;cursor:pointer;transition:transform .2s}.color-swatch:hover{transform:scale(1.1)}.color-swatch.active{border-color:#333;box-shadow:0 0 0 2px #fff inset}.style-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;max-height:200px;overflow-y:auto;padding-right:4px}.style-grid::-webkit-scrollbar{width:4px}.style-grid::-webkit-scrollbar-thumb{background-color:#cbd5e1;border-radius:4px}.style-card{border:1px solid #e2e8f0;background:white;border-radius:8px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:8px 4px;transition:all .2s}.style-card:hover{background:#f8fafc;border-color:#cbd5e1}.style-card.active{border-color:#3b82f6;background:#eff6ff}.style-card img{width:40px;height:40px;margin-bottom:4px;border-radius:50%}.style-card span{font-size:10px;color:#475569;font-weight:500;text-align:center}\n"] }]
|
|
208
|
+
}], propDecorators: { firstName: [{
|
|
209
|
+
type: Input
|
|
210
|
+
}], lastName: [{
|
|
211
|
+
type: Input
|
|
212
|
+
}], size: [{
|
|
213
|
+
type: Input
|
|
214
|
+
}], editable: [{
|
|
215
|
+
type: Input
|
|
216
|
+
}], editorTitle: [{
|
|
217
|
+
type: Input
|
|
218
|
+
}], avatarConfig: [{
|
|
219
|
+
type: Input
|
|
220
|
+
}], avatarConfigChanged: [{
|
|
221
|
+
type: Output
|
|
222
|
+
}] } });
|
|
223
|
+
|
|
224
|
+
class NgAvatarCreatorModule {
|
|
225
|
+
}
|
|
226
|
+
NgAvatarCreatorModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
227
|
+
NgAvatarCreatorModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, declarations: [NgAvatarCreatorComponent], imports: [CommonModule], exports: [NgAvatarCreatorComponent] });
|
|
228
|
+
NgAvatarCreatorModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, imports: [CommonModule] });
|
|
229
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, decorators: [{
|
|
230
|
+
type: NgModule,
|
|
231
|
+
args: [{
|
|
232
|
+
declarations: [
|
|
233
|
+
NgAvatarCreatorComponent
|
|
234
|
+
],
|
|
235
|
+
imports: [
|
|
236
|
+
CommonModule
|
|
237
|
+
],
|
|
238
|
+
exports: [
|
|
239
|
+
NgAvatarCreatorComponent
|
|
240
|
+
]
|
|
241
|
+
}]
|
|
242
|
+
}] });
|
|
243
|
+
|
|
244
|
+
/*
|
|
245
|
+
* Public API Surface of ng-avatar-creator
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Generated bundle index. Do not edit.
|
|
250
|
+
*/
|
|
251
|
+
|
|
252
|
+
export { AVATAR_STYLES, NgAvatarCreatorComponent, NgAvatarCreatorModule, NgAvatarCreatorService, PREDEFINED_COLORS };
|
|
253
|
+
//# sourceMappingURL=gayath1-ng-avatar-creator.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gayath1-ng-avatar-creator.mjs","sources":["../../../projects/ng-avatar-creator/src/lib/ng-avatar-creator.service.ts","../../../projects/ng-avatar-creator/src/lib/avatar-models.ts","../../../projects/ng-avatar-creator/src/lib/ng-avatar-creator.component.ts","../../../projects/ng-avatar-creator/src/lib/ng-avatar-creator.component.html","../../../projects/ng-avatar-creator/src/lib/ng-avatar-creator.module.ts","../../../projects/ng-avatar-creator/src/public-api.ts","../../../projects/ng-avatar-creator/src/gayath1-ng-avatar-creator.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class NgAvatarCreatorService {\r\n\r\n constructor() { }\r\n}\r\n","export interface AvatarConfig {\n style: AvatarStyleId;\n seed: string;\n bgColor: string;\n shape: 'circle' | 'square';\n}\n\nexport type AvatarStyleId =\n | 'initials'\n | 'identicon'\n | 'rings'\n | 'shapes'\n | 'thumbs'\n | 'avataaars'\n | 'bottts'\n | 'glass';\n\nexport interface AvatarStyleOption {\n id: AvatarStyleId;\n name: string;\n}\n\nexport const AVATAR_STYLES = [\n { id: 'initials', name: 'Initials' },\n { id: 'identicon', name: 'Identicon' },\n { id: 'rings', name: 'Rings' },\r\n { id: 'shapes', name: 'Shapes' },\r\n { id: 'thumbs', name: 'Thumbs' },\r\n { id: 'avataaars', name: 'Avatars' },\n { id: 'bottts', name: 'Bots' },\n { id: 'glass', name: 'Glass' }\n] as AvatarStyleOption[];\n\nexport const PREDEFINED_COLORS = [\n '#ef4444', '#f97316', '#f59e0b', '#84cc16', '#22c55e',\n '#14b8a6', '#06b6d4', '#0ea5e9', '#3b82f6', '#6366f1',\n '#8b5cf6', '#a855f7', '#d946ef', '#ec4899', '#f43f5e',\n '#475569', '#111827', '#7c2d12', '#365314', '#164e63'\n];\n","import { Component, Input, Output, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';\nimport { AvatarConfig, AvatarStyleId, PREDEFINED_COLORS, AVATAR_STYLES } from './avatar-models';\n\r\n@Component({\r\n selector: 'lib-ng-avatar-creator',\r\n templateUrl: './ng-avatar-creator.component.html',\r\n styleUrls: ['./ng-avatar-creator.component.css']\r\n})\r\nexport class NgAvatarCreatorComponent implements OnInit, OnChanges {\n @Input() firstName: string = '';\n @Input() lastName: string = '';\n @Input() size: number = 64;\n @Input() editable: boolean = false;\n @Input() editorTitle: string = 'Customize Avatar';\n \n @Input() avatarConfig?: AvatarConfig;\n @Output() avatarConfigChanged = new EventEmitter<AvatarConfig>();\n\n hovering: boolean = false;\n editorOpen: boolean = false;\r\n\r\n currentConfig: AvatarConfig = {\r\n style: 'initials',\n seed: '',\n bgColor: '#3b82f6',\n shape: 'circle'\n };\n\n colors = PREDEFINED_COLORS;\n styles = AVATAR_STYLES;\n\n ngOnInit() {\n this.syncConfig();\n this.avatarConfigChanged.emit({ ...this.currentConfig });\n }\n\n ngOnChanges(changes: SimpleChanges) {\n if (!changes['avatarConfig'] && !changes['firstName'] && !changes['lastName']) {\n return;\n }\n\n this.syncConfig();\n }\n\n private syncConfig() {\n if (this.avatarConfig) {\n this.currentConfig = { ...this.currentConfig, ...this.avatarConfig };\n } else {\n const defaultSeed = this.getDefaultSeed();\n const colorIndex = Math.abs(this.hash(defaultSeed)) % this.colors.length;\n this.currentConfig.bgColor = this.colors[colorIndex];\n this.currentConfig.seed = this.getDefaultSeed();\n }\n }\n\r\n getDefaultSeed(): string {\n const parts = [];\n if (this.firstName) parts.push(this.firstName);\n if (this.lastName) parts.push(this.lastName);\n return parts.join(' ') || 'User';\n }\n\n getAvatarUrl(config: AvatarConfig = this.currentConfig): string {\n return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(this.getAvatarSvg(config))}`;\n }\n\n getAvatarSvg(config: AvatarConfig = this.currentConfig): string {\n const seed = this.getEffectiveSeed(config);\n const hash = this.hash(seed);\n const initials = this.getInitials(seed);\n const accent = this.pickAccent(config.bgColor, hash);\n const dark = this.adjustColor(config.bgColor, -34);\n const light = this.adjustColor(config.bgColor, 46);\n const mask = config.shape === 'circle' ? '<clipPath id=\"clip\"><circle cx=\"50\" cy=\"50\" r=\"50\"/></clipPath>' : '<clipPath id=\"clip\"><rect width=\"100\" height=\"100\" rx=\"12\"/></clipPath>';\n const content = this.renderStyle(config.style, hash, initials, config.bgColor, accent, dark, light);\n\n return [\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100\" height=\"100\" viewBox=\"0 0 100 100\" role=\"img\" aria-label=\"Avatar\">',\n '<defs>',\n mask,\n '<filter id=\"shadow\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\"><feDropShadow dx=\"0\" dy=\"4\" stdDeviation=\"5\" flood-opacity=\".18\"/></filter>',\n '</defs>',\n '<g clip-path=\"url(#clip)\">',\n `<rect width=\"100\" height=\"100\" fill=\"${config.bgColor}\"/>`,\n content,\n '</g>',\n '</svg>'\n ].join('');\n }\n\n randomizeSeed() {\n const randomString = `avatar-${Math.random().toString(36).substring(2, 8)}`;\n this.updateConfig({ seed: randomString });\n }\n\n setSeed(value: string) {\n this.updateConfig({ seed: value || this.getDefaultSeed() });\n }\n\n toggleEditor() {\n this.editorOpen = !this.editorOpen;\n }\n\n updateConfig(partial: Partial<AvatarConfig>) {\n this.currentConfig = { ...this.currentConfig, ...partial };\n\n if (partial.style === 'initials') {\n this.currentConfig.seed = this.getDefaultSeed();\n }\n \n this.avatarConfigChanged.emit({ ...this.currentConfig });\n }\n\n trackByStyle(_: number, style: { id: AvatarStyleId }) {\n return style.id;\n }\n\n private renderStyle(style: AvatarStyleId, hash: number, initials: string, bg: string, accent: string, dark: string, light: string): string {\n switch (style) {\n case 'initials':\n return `<circle cx=\"76\" cy=\"23\" r=\"24\" fill=\"${light}\" opacity=\".8\"/><circle cx=\"20\" cy=\"78\" r=\"30\" fill=\"${dark}\" opacity=\".32\"/><text x=\"50\" y=\"58\" text-anchor=\"middle\" font-family=\"Arial, Helvetica, sans-serif\" font-size=\"34\" font-weight=\"700\" fill=\"#fff\">${initials}</text>`;\n case 'identicon':\n return this.renderIdenticon(hash, accent, dark, light);\n case 'rings':\n return `<circle cx=\"50\" cy=\"50\" r=\"42\" fill=\"none\" stroke=\"${light}\" stroke-width=\"12\" opacity=\".9\"/><circle cx=\"50\" cy=\"50\" r=\"27\" fill=\"none\" stroke=\"${accent}\" stroke-width=\"10\"/><circle cx=\"50\" cy=\"50\" r=\"12\" fill=\"${dark}\"/><path d=\"M50 8a42 42 0 0 1 36 21\" stroke=\"#fff\" stroke-width=\"8\" stroke-linecap=\"round\" opacity=\".65\" fill=\"none\"/>`;\n case 'shapes':\n return `<rect x=\"12\" y=\"14\" width=\"34\" height=\"34\" rx=\"10\" fill=\"${light}\" transform=\"rotate(${hash % 24} 29 31)\"/><circle cx=\"68\" cy=\"34\" r=\"20\" fill=\"${accent}\"/><path d=\"M21 82 47 50l29 32Z\" fill=\"${dark}\"/><circle cx=\"74\" cy=\"76\" r=\"10\" fill=\"#fff\" opacity=\".7\"/>`;\n case 'thumbs':\n return `<circle cx=\"50\" cy=\"50\" r=\"31\" fill=\"${light}\"/><path d=\"M29 51h11l8-20c2-5 10-3 9 3l-2 12h13c5 0 8 4 7 9l-4 20c-1 5-5 8-10 8H36c-4 0-7-3-7-7V51Z\" fill=\"#fff\"/><rect x=\"21\" y=\"51\" width=\"15\" height=\"32\" rx=\"6\" fill=\"${dark}\"/>`;\n case 'avataaars':\n return `<circle cx=\"50\" cy=\"55\" r=\"28\" fill=\"#ffd7b5\"/><path d=\"M23 48c2-21 17-32 34-29 13 2 21 12 22 28-12-8-25-8-34-3-8 5-15 5-22 4Z\" fill=\"${dark}\"/><circle cx=\"39\" cy=\"57\" r=\"4\" fill=\"#1f2937\"/><circle cx=\"61\" cy=\"57\" r=\"4\" fill=\"#1f2937\"/><path d=\"M40 73c7 5 14 5 21 0\" stroke=\"#9f1239\" stroke-width=\"4\" stroke-linecap=\"round\" fill=\"none\"/><path d=\"M18 100c6-18 21-27 32-27s26 9 32 27Z\" fill=\"${accent}\"/>`;\n case 'bottts':\n return `<rect x=\"22\" y=\"28\" width=\"56\" height=\"48\" rx=\"14\" fill=\"${light}\" filter=\"url(#shadow)\"/><rect x=\"32\" y=\"45\" width=\"13\" height=\"11\" rx=\"4\" fill=\"${dark}\"/><rect x=\"55\" y=\"45\" width=\"13\" height=\"11\" rx=\"4\" fill=\"${dark}\"/><path d=\"M39 66h22\" stroke=\"#fff\" stroke-width=\"5\" stroke-linecap=\"round\"/><path d=\"M50 28V15\" stroke=\"${dark}\" stroke-width=\"5\" stroke-linecap=\"round\"/><circle cx=\"50\" cy=\"13\" r=\"6\" fill=\"${accent}\"/>`;\n case 'glass':\n return `<circle cx=\"32\" cy=\"30\" r=\"24\" fill=\"#fff\" opacity=\".34\"/><circle cx=\"72\" cy=\"73\" r=\"32\" fill=\"${dark}\" opacity=\".36\"/><rect x=\"19\" y=\"19\" width=\"62\" height=\"62\" rx=\"18\" fill=\"#fff\" opacity=\".22\" stroke=\"#fff\" stroke-width=\"2\"/><text x=\"50\" y=\"59\" text-anchor=\"middle\" font-family=\"Arial, Helvetica, sans-serif\" font-size=\"28\" font-weight=\"700\" fill=\"#fff\">${initials}</text>`;\n default:\n return '';\n }\n }\n\n private renderIdenticon(hash: number, accent: string, dark: string, light: string): string {\n const cells: string[] = [];\n const colors = [accent, dark, light];\n\n for (let row = 0; row < 5; row++) {\n for (let col = 0; col < 3; col++) {\n const bit = (hash >> (row * 3 + col)) & 1;\n if (!bit) {\n continue;\n }\n\n const x = 20 + col * 12;\n const mirrorX = 20 + (4 - col) * 12;\n const y = 20 + row * 12;\n const color = colors[(row + col + Math.abs(hash)) % colors.length];\n cells.push(`<rect x=\"${x}\" y=\"${y}\" width=\"10\" height=\"10\" rx=\"2\" fill=\"${color}\"/>`);\n\n if (col !== 2) {\n cells.push(`<rect x=\"${mirrorX}\" y=\"${y}\" width=\"10\" height=\"10\" rx=\"2\" fill=\"${color}\"/>`);\n }\n }\n }\n\n return cells.join('');\n }\n\n private getEffectiveSeed(config: AvatarConfig): string {\n return config.style === 'initials' ? this.getDefaultSeed() : (config.seed || this.getDefaultSeed());\n }\n\n private getInitials(seed: string): string {\n const names = seed.trim().split(/\\s+/).filter(Boolean);\n const first = names[0]?.charAt(0) || 'U';\n const second = names.length > 1 ? names[names.length - 1].charAt(0) : names[0]?.charAt(1) || '';\n return `${first}${second}`.toUpperCase();\n }\n\n private hash(value: string): number {\n let hash = 0;\n for (let i = 0; i < value.length; i++) {\n hash = ((hash << 5) - hash) + value.charCodeAt(i);\n hash |= 0;\n }\n return hash || 1;\n }\n\n private pickAccent(color: string, hash: number): string {\n const index = Math.abs(hash) % this.colors.length;\n const picked = this.colors[index];\n return picked.toLowerCase() === color.toLowerCase() ? this.adjustColor(color, 60) : picked;\n }\n\n private adjustColor(hex: string, amount: number): string {\n const clean = hex.replace('#', '');\n const num = parseInt(clean, 16);\n const r = Math.max(0, Math.min(255, (num >> 16) + amount));\n const g = Math.max(0, Math.min(255, ((num >> 8) & 0x00ff) + amount));\n const b = Math.max(0, Math.min(255, (num & 0x0000ff) + amount));\n return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;\n }\n}\n","<div class=\"avatar-container\" \r\n [style.width.px]=\"size\" \r\n [style.height.px]=\"size\"\r\n [style.borderRadius]=\"currentConfig.shape === 'circle' ? '50%' : '8px'\"\r\n (mouseenter)=\"hovering = true\"\r\n (mouseleave)=\"hovering = false\">\r\n \r\n <div class=\"avatar-content\">\r\n <img [src]=\"getAvatarUrl()\" alt=\"Avatar\" class=\"avatar-image\">\r\n </div>\r\n\r\n <div class=\"edit-overlay\" *ngIf=\"editable && hovering\" (click)=\"toggleEditor()\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"24\" height=\"24\">\r\n <path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\"/>\r\n </svg>\r\n </div>\r\n</div>\r\n\r\n<div class=\"editor-popover\" *ngIf=\"editorOpen\">\r\n <div class=\"editor-header\">\r\n <h3>Customize Avatar</h3>\r\n <button class=\"close-btn\" (click)=\"toggleEditor()\">×</button>\r\n </div>\r\n \r\n <div class=\"editor-body\">\r\n <div class=\"section\">\r\n <label>Shape</label>\r\n <div class=\"shape-options\">\r\n <button [class.active]=\"currentConfig.shape === 'circle'\" (click)=\"updateConfig({shape: 'circle'})\">Circle</button>\r\n <button [class.active]=\"currentConfig.shape === 'square'\" (click)=\"updateConfig({shape: 'square'})\">Square</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <label>Background Color</label>\r\n <div class=\"color-grid\">\r\n <button *ngFor=\"let color of colors\" \r\n class=\"color-swatch\" \r\n [style.backgroundColor]=\"color\"\r\n [class.active]=\"currentConfig.bgColor === color\"\r\n (click)=\"updateConfig({bgColor: color})\">\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title-row\">\r\n <label>Style Category</label>\r\n <button class=\"randomize-btn\" (click)=\"randomizeSeed()\">🎲 Randomize</button>\r\n </div>\r\n <div class=\"style-grid\">\r\n <div *ngFor=\"let style of styles\" \r\n class=\"style-card\"\r\n [class.active]=\"currentConfig.style === style.id\"\r\n (click)=\"updateConfig({style: style.id})\">\r\n <img [src]=\"getAvatarUrl({ style: style.id, seed: currentConfig.seed, bgColor: currentConfig.bgColor, shape: currentConfig.shape })\" alt=\"{{style.name}}\">\r\n <span>{{ style.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n","import { NgModule } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { NgAvatarCreatorComponent } from './ng-avatar-creator.component';\r\n\r\n\r\n\r\n@NgModule({\r\n declarations: [\r\n NgAvatarCreatorComponent\r\n ],\r\n imports: [\r\n CommonModule\r\n ],\r\n exports: [\r\n NgAvatarCreatorComponent\r\n ]\r\n})\r\nexport class NgAvatarCreatorModule { }\r\n","/*\r\n * Public API Surface of ng-avatar-creator\r\n */\r\n\r\nexport * from './lib/ng-avatar-creator.service';\r\nexport * from './lib/ng-avatar-creator.component';\r\nexport * from './lib/ng-avatar-creator.module';\r\nexport * from './lib/avatar-models';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;MAKa,sBAAsB,CAAA;AAEjC,IAAA,WAAA,GAAA,GAAiB;;oHAFN,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAtB,sBAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cAFrB,MAAM,EAAA,CAAA,CAAA;4FAEP,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAHlC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;iBACnB,CAAA;;;ACkBY,MAAA,aAAa,GAAG;AAC3B,IAAA,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE;AACpC,IAAA,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE;AACtC,IAAA,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE;AAC9B,IAAA,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;AAChC,IAAA,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;AAChC,IAAA,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;AACpC,IAAA,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;AAC9B,IAAA,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE;EACP;AAEZ,MAAA,iBAAiB,GAAG;AAC/B,IAAA,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;AACrD,IAAA,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;AACrD,IAAA,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;AACrD,IAAA,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;;;MC7B1C,wBAAwB,CAAA;AALrC,IAAA,WAAA,GAAA;AAMW,QAAA,IAAS,CAAA,SAAA,GAAW,EAAE,CAAC;AACvB,QAAA,IAAQ,CAAA,QAAA,GAAW,EAAE,CAAC;AACtB,QAAA,IAAI,CAAA,IAAA,GAAW,EAAE,CAAC;AAClB,QAAA,IAAQ,CAAA,QAAA,GAAY,KAAK,CAAC;AAC1B,QAAA,IAAW,CAAA,WAAA,GAAW,kBAAkB,CAAC;AAGxC,QAAA,IAAA,CAAA,mBAAmB,GAAG,IAAI,YAAY,EAAgB,CAAC;AAEjE,QAAA,IAAQ,CAAA,QAAA,GAAY,KAAK,CAAC;AAC1B,QAAA,IAAU,CAAA,UAAA,GAAY,KAAK,CAAC;QAE5B,IAAA,CAAA,aAAa,GAAiB;AAC5B,YAAA,KAAK,EAAE,UAAU;AACjB,YAAA,IAAI,EAAE,EAAE;AACR,YAAA,OAAO,EAAE,SAAS;AAClB,YAAA,KAAK,EAAE,QAAQ;SAChB,CAAC;AAEF,QAAA,IAAM,CAAA,MAAA,GAAG,iBAAiB,CAAC;AAC3B,QAAA,IAAM,CAAA,MAAA,GAAG,aAAa,CAAC;KA2KxB;IAzKC,QAAQ,GAAA;QACN,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,mBAAmB,CAAC,IAAI,mBAAM,IAAI,CAAC,aAAa,CAAA,CAAG,CAAC;KAC1D;AAED,IAAA,WAAW,CAAC,OAAsB,EAAA;AAChC,QAAA,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;YAC7E,OAAO;AACR,SAAA;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;KACnB;IAEO,UAAU,GAAA;QAChB,IAAI,IAAI,CAAC,YAAY,EAAE;YACrB,IAAI,CAAC,aAAa,GAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,EAAA,EAAQ,IAAI,CAAC,aAAa,CAAA,EAAK,IAAI,CAAC,YAAY,CAAE,CAAC;AACtE,SAAA;AAAM,aAAA;AACL,YAAA,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;AAC1C,YAAA,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;YACzE,IAAI,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACrD,IAAI,CAAC,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;AACjD,SAAA;KACF;IAED,cAAc,GAAA;QACZ,MAAM,KAAK,GAAG,EAAE,CAAC;QACjB,IAAI,IAAI,CAAC,SAAS;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,IAAI,CAAC,QAAQ;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC;KAClC;AAED,IAAA,YAAY,CAAC,MAAA,GAAuB,IAAI,CAAC,aAAa,EAAA;QACpD,OAAO,CAAA,iCAAA,EAAoC,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAA,CAAE,CAAC;KAC5F;AAED,IAAA,YAAY,CAAC,MAAA,GAAuB,IAAI,CAAC,aAAa,EAAA;QACpD,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;AACxC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACrD,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AACnD,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACnD,QAAA,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,KAAK,QAAQ,GAAG,iEAAiE,GAAG,yEAAyE,CAAC;QACvL,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAEpG,OAAO;YACL,wHAAwH;YACxH,QAAQ;YACR,IAAI;YACJ,8IAA8I;YAC9I,SAAS;YACT,4BAA4B;YAC5B,CAAwC,qCAAA,EAAA,MAAM,CAAC,OAAO,CAAK,GAAA,CAAA;YAC3D,OAAO;YACP,MAAM;YACN,QAAQ;AACT,SAAA,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;KACZ;IAED,aAAa,GAAA;QACX,MAAM,YAAY,GAAG,CAAU,OAAA,EAAA,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC5E,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;KAC3C;AAED,IAAA,OAAO,CAAC,KAAa,EAAA;AACnB,QAAA,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;KAC7D;IAED,YAAY,GAAA;AACV,QAAA,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;KACpC;AAED,IAAA,YAAY,CAAC,OAA8B,EAAA;QACzC,IAAI,CAAC,aAAa,GAAQ,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,EAAA,EAAA,IAAI,CAAC,aAAa,CAAA,EAAK,OAAO,CAAE,CAAC;AAE3D,QAAA,IAAI,OAAO,CAAC,KAAK,KAAK,UAAU,EAAE;YAChC,IAAI,CAAC,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;AACjD,SAAA;QAED,IAAI,CAAC,mBAAmB,CAAC,IAAI,mBAAM,IAAI,CAAC,aAAa,CAAA,CAAG,CAAC;KAC1D;IAED,YAAY,CAAC,CAAS,EAAE,KAA4B,EAAA;QAClD,OAAO,KAAK,CAAC,EAAE,CAAC;KACjB;AAEO,IAAA,WAAW,CAAC,KAAoB,EAAE,IAAY,EAAE,QAAgB,EAAE,EAAU,EAAE,MAAc,EAAE,IAAY,EAAE,KAAa,EAAA;AAC/H,QAAA,QAAQ,KAAK;AACX,YAAA,KAAK,UAAU;AACb,gBAAA,OAAO,wCAAwC,KAAK,CAAA,qDAAA,EAAwD,IAAI,CAAqJ,kJAAA,EAAA,QAAQ,SAAS,CAAC;AACzR,YAAA,KAAK,WAAW;AACd,gBAAA,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AACzD,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,sDAAsD,KAAK,CAAA,qFAAA,EAAwF,MAAM,CAA6D,0DAAA,EAAA,IAAI,wHAAwH,CAAC;AAC5V,YAAA,KAAK,QAAQ;gBACX,OAAO,CAAA,yDAAA,EAA4D,KAAK,CAAA,oBAAA,EAAuB,IAAI,GAAG,EAAE,CAAA,+CAAA,EAAkD,MAAM,CAAA,uCAAA,EAA0C,IAAI,CAAA,4DAAA,CAA8D,CAAC;AAC/Q,YAAA,KAAK,QAAQ;AACX,gBAAA,OAAO,CAAwC,qCAAA,EAAA,KAAK,CAA8K,2KAAA,EAAA,IAAI,KAAK,CAAC;AAC9O,YAAA,KAAK,WAAW;AACd,gBAAA,OAAO,CAAyI,sIAAA,EAAA,IAAI,CAA4P,yPAAA,EAAA,MAAM,KAAK,CAAC;AAC9Z,YAAA,KAAK,QAAQ;gBACX,OAAO,CAAA,yDAAA,EAA4D,KAAK,CAAA,iFAAA,EAAoF,IAAI,CAAA,2DAAA,EAA8D,IAAI,CAAA,0GAAA,EAA6G,IAAI,CAAA,+EAAA,EAAkF,MAAM,CAAA,GAAA,CAAK,CAAC;AACnb,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,CAAkG,+FAAA,EAAA,IAAI,CAAkQ,+PAAA,EAAA,QAAQ,SAAS,CAAC;AACnY,YAAA;AACE,gBAAA,OAAO,EAAE,CAAC;AACb,SAAA;KACF;AAEO,IAAA,eAAe,CAAC,IAAY,EAAE,MAAc,EAAE,IAAY,EAAE,KAAa,EAAA;QAC/E,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAErC,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE;YAChC,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE;AAChC,gBAAA,MAAM,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1C,IAAI,CAAC,GAAG,EAAE;oBACR,SAAS;AACV,iBAAA;AAED,gBAAA,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;gBACxB,MAAM,OAAO,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC;AACpC,gBAAA,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;gBACxB,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;gBACnE,KAAK,CAAC,IAAI,CAAC,CAAY,SAAA,EAAA,CAAC,CAAQ,KAAA,EAAA,CAAC,CAAyC,sCAAA,EAAA,KAAK,CAAK,GAAA,CAAA,CAAC,CAAC;gBAEtF,IAAI,GAAG,KAAK,CAAC,EAAE;oBACb,KAAK,CAAC,IAAI,CAAC,CAAY,SAAA,EAAA,OAAO,CAAQ,KAAA,EAAA,CAAC,CAAyC,sCAAA,EAAA,KAAK,CAAK,GAAA,CAAA,CAAC,CAAC;AAC7F,iBAAA;AACF,aAAA;AACF,SAAA;AAED,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;KACvB;AAEO,IAAA,gBAAgB,CAAC,MAAoB,EAAA;QAC3C,OAAO,MAAM,CAAC,KAAK,KAAK,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,IAAI,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;KACrG;AAEO,IAAA,WAAW,CAAC,IAAY,EAAA;;AAC9B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACvD,QAAA,MAAM,KAAK,GAAG,CAAA,CAAA,EAAA,GAAA,KAAK,CAAC,CAAC,CAAC,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAE,MAAM,CAAC,CAAC,CAAC,KAAI,GAAG,CAAC;AACzC,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAA,MAAA,KAAK,CAAC,CAAC,CAAC,0CAAE,MAAM,CAAC,CAAC,CAAC,KAAI,EAAE,CAAC;QAChG,OAAO,CAAA,EAAG,KAAK,CAAG,EAAA,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC;KAC1C;AAEO,IAAA,IAAI,CAAC,KAAa,EAAA;QACxB,IAAI,IAAI,GAAG,CAAC,CAAC;AACb,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACrC,YAAA,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAClD,IAAI,IAAI,CAAC,CAAC;AACX,SAAA;QACD,OAAO,IAAI,IAAI,CAAC,CAAC;KAClB;IAEO,UAAU,CAAC,KAAa,EAAE,IAAY,EAAA;AAC5C,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClC,OAAO,MAAM,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC;KAC5F;IAEO,WAAW,CAAC,GAAW,EAAE,MAAc,EAAA;QAC7C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAChC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC;QAC3D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC;AAChE,QAAA,OAAO,CAAI,CAAA,EAAA,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3E;;sHA/LU,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAxB,wBAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,wBAAwB,mSCRrC,kmFA8DA,EAAA,MAAA,EAAA,CAAA,uuGAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,cAAA,EAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA;4FDtDa,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBALpC,SAAS;+BACE,uBAAuB,EAAA,QAAA,EAAA,kmFAAA,EAAA,MAAA,EAAA,CAAA,uuGAAA,CAAA,EAAA,CAAA;8BAKxB,SAAS,EAAA,CAAA;sBAAjB,KAAK;gBACG,QAAQ,EAAA,CAAA;sBAAhB,KAAK;gBACG,IAAI,EAAA,CAAA;sBAAZ,KAAK;gBACG,QAAQ,EAAA,CAAA;sBAAhB,KAAK;gBACG,WAAW,EAAA,CAAA;sBAAnB,KAAK;gBAEG,YAAY,EAAA,CAAA;sBAApB,KAAK;gBACI,mBAAmB,EAAA,CAAA;sBAA5B,MAAM;;;MECI,qBAAqB,CAAA;;mHAArB,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;AAArB,qBAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,qBAAqB,EAT9B,YAAA,EAAA,CAAA,wBAAwB,CAGxB,EAAA,OAAA,EAAA,CAAA,YAAY,aAGZ,wBAAwB,CAAA,EAAA,CAAA,CAAA;AAGf,qBAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,qBAAqB,YAN9B,YAAY,CAAA,EAAA,CAAA,CAAA;4FAMH,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBAXjC,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;AACR,oBAAA,YAAY,EAAE;wBACZ,wBAAwB;AACzB,qBAAA;AACD,oBAAA,OAAO,EAAE;wBACP,YAAY;AACb,qBAAA;AACD,oBAAA,OAAO,EAAE;wBACP,wBAAwB;AACzB,qBAAA;iBACF,CAAA;;;AChBD;;AAEG;;ACFH;;AAEG;;;;"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Injectable, EventEmitter, Component, Input, Output, NgModule } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
|
|
6
|
+
class NgAvatarCreatorService {
|
|
7
|
+
constructor() { }
|
|
8
|
+
}
|
|
9
|
+
NgAvatarCreatorService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10
|
+
NgAvatarCreatorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorService, providedIn: 'root' });
|
|
11
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorService, decorators: [{
|
|
12
|
+
type: Injectable,
|
|
13
|
+
args: [{
|
|
14
|
+
providedIn: 'root'
|
|
15
|
+
}]
|
|
16
|
+
}], ctorParameters: function () { return []; } });
|
|
17
|
+
|
|
18
|
+
const AVATAR_STYLES = [
|
|
19
|
+
{ id: 'initials', name: 'Initials' },
|
|
20
|
+
{ id: 'identicon', name: 'Identicon' },
|
|
21
|
+
{ id: 'rings', name: 'Rings' },
|
|
22
|
+
{ id: 'shapes', name: 'Shapes' },
|
|
23
|
+
{ id: 'thumbs', name: 'Thumbs' },
|
|
24
|
+
{ id: 'avataaars', name: 'Avatars' },
|
|
25
|
+
{ id: 'bottts', name: 'Bots' },
|
|
26
|
+
{ id: 'glass', name: 'Glass' }
|
|
27
|
+
];
|
|
28
|
+
const PREDEFINED_COLORS = [
|
|
29
|
+
'#ef4444', '#f97316', '#f59e0b', '#84cc16', '#22c55e',
|
|
30
|
+
'#14b8a6', '#06b6d4', '#0ea5e9', '#3b82f6', '#6366f1',
|
|
31
|
+
'#8b5cf6', '#a855f7', '#d946ef', '#ec4899', '#f43f5e',
|
|
32
|
+
'#475569', '#111827', '#7c2d12', '#365314', '#164e63'
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
class NgAvatarCreatorComponent {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.firstName = '';
|
|
38
|
+
this.lastName = '';
|
|
39
|
+
this.size = 64;
|
|
40
|
+
this.editable = false;
|
|
41
|
+
this.editorTitle = 'Customize Avatar';
|
|
42
|
+
this.avatarConfigChanged = new EventEmitter();
|
|
43
|
+
this.hovering = false;
|
|
44
|
+
this.editorOpen = false;
|
|
45
|
+
this.currentConfig = {
|
|
46
|
+
style: 'initials',
|
|
47
|
+
seed: '',
|
|
48
|
+
bgColor: '#3b82f6',
|
|
49
|
+
shape: 'circle'
|
|
50
|
+
};
|
|
51
|
+
this.colors = PREDEFINED_COLORS;
|
|
52
|
+
this.styles = AVATAR_STYLES;
|
|
53
|
+
}
|
|
54
|
+
ngOnInit() {
|
|
55
|
+
this.syncConfig();
|
|
56
|
+
this.avatarConfigChanged.emit({ ...this.currentConfig });
|
|
57
|
+
}
|
|
58
|
+
ngOnChanges(changes) {
|
|
59
|
+
if (!changes['avatarConfig'] && !changes['firstName'] && !changes['lastName']) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.syncConfig();
|
|
63
|
+
}
|
|
64
|
+
syncConfig() {
|
|
65
|
+
if (this.avatarConfig) {
|
|
66
|
+
this.currentConfig = { ...this.currentConfig, ...this.avatarConfig };
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const defaultSeed = this.getDefaultSeed();
|
|
70
|
+
const colorIndex = Math.abs(this.hash(defaultSeed)) % this.colors.length;
|
|
71
|
+
this.currentConfig.bgColor = this.colors[colorIndex];
|
|
72
|
+
this.currentConfig.seed = this.getDefaultSeed();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
getDefaultSeed() {
|
|
76
|
+
const parts = [];
|
|
77
|
+
if (this.firstName)
|
|
78
|
+
parts.push(this.firstName);
|
|
79
|
+
if (this.lastName)
|
|
80
|
+
parts.push(this.lastName);
|
|
81
|
+
return parts.join(' ') || 'User';
|
|
82
|
+
}
|
|
83
|
+
getAvatarUrl(config = this.currentConfig) {
|
|
84
|
+
return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(this.getAvatarSvg(config))}`;
|
|
85
|
+
}
|
|
86
|
+
getAvatarSvg(config = this.currentConfig) {
|
|
87
|
+
const seed = this.getEffectiveSeed(config);
|
|
88
|
+
const hash = this.hash(seed);
|
|
89
|
+
const initials = this.getInitials(seed);
|
|
90
|
+
const accent = this.pickAccent(config.bgColor, hash);
|
|
91
|
+
const dark = this.adjustColor(config.bgColor, -34);
|
|
92
|
+
const light = this.adjustColor(config.bgColor, 46);
|
|
93
|
+
const mask = config.shape === 'circle' ? '<clipPath id="clip"><circle cx="50" cy="50" r="50"/></clipPath>' : '<clipPath id="clip"><rect width="100" height="100" rx="12"/></clipPath>';
|
|
94
|
+
const content = this.renderStyle(config.style, hash, initials, config.bgColor, accent, dark, light);
|
|
95
|
+
return [
|
|
96
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" role="img" aria-label="Avatar">',
|
|
97
|
+
'<defs>',
|
|
98
|
+
mask,
|
|
99
|
+
'<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="4" stdDeviation="5" flood-opacity=".18"/></filter>',
|
|
100
|
+
'</defs>',
|
|
101
|
+
'<g clip-path="url(#clip)">',
|
|
102
|
+
`<rect width="100" height="100" fill="${config.bgColor}"/>`,
|
|
103
|
+
content,
|
|
104
|
+
'</g>',
|
|
105
|
+
'</svg>'
|
|
106
|
+
].join('');
|
|
107
|
+
}
|
|
108
|
+
randomizeSeed() {
|
|
109
|
+
const randomString = `avatar-${Math.random().toString(36).substring(2, 8)}`;
|
|
110
|
+
this.updateConfig({ seed: randomString });
|
|
111
|
+
}
|
|
112
|
+
setSeed(value) {
|
|
113
|
+
this.updateConfig({ seed: value || this.getDefaultSeed() });
|
|
114
|
+
}
|
|
115
|
+
toggleEditor() {
|
|
116
|
+
this.editorOpen = !this.editorOpen;
|
|
117
|
+
}
|
|
118
|
+
updateConfig(partial) {
|
|
119
|
+
this.currentConfig = { ...this.currentConfig, ...partial };
|
|
120
|
+
if (partial.style === 'initials') {
|
|
121
|
+
this.currentConfig.seed = this.getDefaultSeed();
|
|
122
|
+
}
|
|
123
|
+
this.avatarConfigChanged.emit({ ...this.currentConfig });
|
|
124
|
+
}
|
|
125
|
+
trackByStyle(_, style) {
|
|
126
|
+
return style.id;
|
|
127
|
+
}
|
|
128
|
+
renderStyle(style, hash, initials, bg, accent, dark, light) {
|
|
129
|
+
switch (style) {
|
|
130
|
+
case 'initials':
|
|
131
|
+
return `<circle cx="76" cy="23" r="24" fill="${light}" opacity=".8"/><circle cx="20" cy="78" r="30" fill="${dark}" opacity=".32"/><text x="50" y="58" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-size="34" font-weight="700" fill="#fff">${initials}</text>`;
|
|
132
|
+
case 'identicon':
|
|
133
|
+
return this.renderIdenticon(hash, accent, dark, light);
|
|
134
|
+
case 'rings':
|
|
135
|
+
return `<circle cx="50" cy="50" r="42" fill="none" stroke="${light}" stroke-width="12" opacity=".9"/><circle cx="50" cy="50" r="27" fill="none" stroke="${accent}" stroke-width="10"/><circle cx="50" cy="50" r="12" fill="${dark}"/><path d="M50 8a42 42 0 0 1 36 21" stroke="#fff" stroke-width="8" stroke-linecap="round" opacity=".65" fill="none"/>`;
|
|
136
|
+
case 'shapes':
|
|
137
|
+
return `<rect x="12" y="14" width="34" height="34" rx="10" fill="${light}" transform="rotate(${hash % 24} 29 31)"/><circle cx="68" cy="34" r="20" fill="${accent}"/><path d="M21 82 47 50l29 32Z" fill="${dark}"/><circle cx="74" cy="76" r="10" fill="#fff" opacity=".7"/>`;
|
|
138
|
+
case 'thumbs':
|
|
139
|
+
return `<circle cx="50" cy="50" r="31" fill="${light}"/><path d="M29 51h11l8-20c2-5 10-3 9 3l-2 12h13c5 0 8 4 7 9l-4 20c-1 5-5 8-10 8H36c-4 0-7-3-7-7V51Z" fill="#fff"/><rect x="21" y="51" width="15" height="32" rx="6" fill="${dark}"/>`;
|
|
140
|
+
case 'avataaars':
|
|
141
|
+
return `<circle cx="50" cy="55" r="28" fill="#ffd7b5"/><path d="M23 48c2-21 17-32 34-29 13 2 21 12 22 28-12-8-25-8-34-3-8 5-15 5-22 4Z" fill="${dark}"/><circle cx="39" cy="57" r="4" fill="#1f2937"/><circle cx="61" cy="57" r="4" fill="#1f2937"/><path d="M40 73c7 5 14 5 21 0" stroke="#9f1239" stroke-width="4" stroke-linecap="round" fill="none"/><path d="M18 100c6-18 21-27 32-27s26 9 32 27Z" fill="${accent}"/>`;
|
|
142
|
+
case 'bottts':
|
|
143
|
+
return `<rect x="22" y="28" width="56" height="48" rx="14" fill="${light}" filter="url(#shadow)"/><rect x="32" y="45" width="13" height="11" rx="4" fill="${dark}"/><rect x="55" y="45" width="13" height="11" rx="4" fill="${dark}"/><path d="M39 66h22" stroke="#fff" stroke-width="5" stroke-linecap="round"/><path d="M50 28V15" stroke="${dark}" stroke-width="5" stroke-linecap="round"/><circle cx="50" cy="13" r="6" fill="${accent}"/>`;
|
|
144
|
+
case 'glass':
|
|
145
|
+
return `<circle cx="32" cy="30" r="24" fill="#fff" opacity=".34"/><circle cx="72" cy="73" r="32" fill="${dark}" opacity=".36"/><rect x="19" y="19" width="62" height="62" rx="18" fill="#fff" opacity=".22" stroke="#fff" stroke-width="2"/><text x="50" y="59" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-size="28" font-weight="700" fill="#fff">${initials}</text>`;
|
|
146
|
+
default:
|
|
147
|
+
return '';
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
renderIdenticon(hash, accent, dark, light) {
|
|
151
|
+
const cells = [];
|
|
152
|
+
const colors = [accent, dark, light];
|
|
153
|
+
for (let row = 0; row < 5; row++) {
|
|
154
|
+
for (let col = 0; col < 3; col++) {
|
|
155
|
+
const bit = (hash >> (row * 3 + col)) & 1;
|
|
156
|
+
if (!bit) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const x = 20 + col * 12;
|
|
160
|
+
const mirrorX = 20 + (4 - col) * 12;
|
|
161
|
+
const y = 20 + row * 12;
|
|
162
|
+
const color = colors[(row + col + Math.abs(hash)) % colors.length];
|
|
163
|
+
cells.push(`<rect x="${x}" y="${y}" width="10" height="10" rx="2" fill="${color}"/>`);
|
|
164
|
+
if (col !== 2) {
|
|
165
|
+
cells.push(`<rect x="${mirrorX}" y="${y}" width="10" height="10" rx="2" fill="${color}"/>`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return cells.join('');
|
|
170
|
+
}
|
|
171
|
+
getEffectiveSeed(config) {
|
|
172
|
+
return config.style === 'initials' ? this.getDefaultSeed() : (config.seed || this.getDefaultSeed());
|
|
173
|
+
}
|
|
174
|
+
getInitials(seed) {
|
|
175
|
+
const names = seed.trim().split(/\s+/).filter(Boolean);
|
|
176
|
+
const first = names[0]?.charAt(0) || 'U';
|
|
177
|
+
const second = names.length > 1 ? names[names.length - 1].charAt(0) : names[0]?.charAt(1) || '';
|
|
178
|
+
return `${first}${second}`.toUpperCase();
|
|
179
|
+
}
|
|
180
|
+
hash(value) {
|
|
181
|
+
let hash = 0;
|
|
182
|
+
for (let i = 0; i < value.length; i++) {
|
|
183
|
+
hash = ((hash << 5) - hash) + value.charCodeAt(i);
|
|
184
|
+
hash |= 0;
|
|
185
|
+
}
|
|
186
|
+
return hash || 1;
|
|
187
|
+
}
|
|
188
|
+
pickAccent(color, hash) {
|
|
189
|
+
const index = Math.abs(hash) % this.colors.length;
|
|
190
|
+
const picked = this.colors[index];
|
|
191
|
+
return picked.toLowerCase() === color.toLowerCase() ? this.adjustColor(color, 60) : picked;
|
|
192
|
+
}
|
|
193
|
+
adjustColor(hex, amount) {
|
|
194
|
+
const clean = hex.replace('#', '');
|
|
195
|
+
const num = parseInt(clean, 16);
|
|
196
|
+
const r = Math.max(0, Math.min(255, (num >> 16) + amount));
|
|
197
|
+
const g = Math.max(0, Math.min(255, ((num >> 8) & 0x00ff) + amount));
|
|
198
|
+
const b = Math.max(0, Math.min(255, (num & 0x0000ff) + amount));
|
|
199
|
+
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
NgAvatarCreatorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
203
|
+
NgAvatarCreatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: NgAvatarCreatorComponent, selector: "lib-ng-avatar-creator", inputs: { firstName: "firstName", lastName: "lastName", size: "size", editable: "editable", editorTitle: "editorTitle", avatarConfig: "avatarConfig" }, outputs: { avatarConfigChanged: "avatarConfigChanged" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"avatar-container\" \r\n [style.width.px]=\"size\" \r\n [style.height.px]=\"size\"\r\n [style.borderRadius]=\"currentConfig.shape === 'circle' ? '50%' : '8px'\"\r\n (mouseenter)=\"hovering = true\"\r\n (mouseleave)=\"hovering = false\">\r\n \r\n <div class=\"avatar-content\">\r\n <img [src]=\"getAvatarUrl()\" alt=\"Avatar\" class=\"avatar-image\">\r\n </div>\r\n\r\n <div class=\"edit-overlay\" *ngIf=\"editable && hovering\" (click)=\"toggleEditor()\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"24\" height=\"24\">\r\n <path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\"/>\r\n </svg>\r\n </div>\r\n</div>\r\n\r\n<div class=\"editor-popover\" *ngIf=\"editorOpen\">\r\n <div class=\"editor-header\">\r\n <h3>Customize Avatar</h3>\r\n <button class=\"close-btn\" (click)=\"toggleEditor()\">×</button>\r\n </div>\r\n \r\n <div class=\"editor-body\">\r\n <div class=\"section\">\r\n <label>Shape</label>\r\n <div class=\"shape-options\">\r\n <button [class.active]=\"currentConfig.shape === 'circle'\" (click)=\"updateConfig({shape: 'circle'})\">Circle</button>\r\n <button [class.active]=\"currentConfig.shape === 'square'\" (click)=\"updateConfig({shape: 'square'})\">Square</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <label>Background Color</label>\r\n <div class=\"color-grid\">\r\n <button *ngFor=\"let color of colors\" \r\n class=\"color-swatch\" \r\n [style.backgroundColor]=\"color\"\r\n [class.active]=\"currentConfig.bgColor === color\"\r\n (click)=\"updateConfig({bgColor: color})\">\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title-row\">\r\n <label>Style Category</label>\r\n <button class=\"randomize-btn\" (click)=\"randomizeSeed()\">\uD83C\uDFB2 Randomize</button>\r\n </div>\r\n <div class=\"style-grid\">\r\n <div *ngFor=\"let style of styles\" \r\n class=\"style-card\"\r\n [class.active]=\"currentConfig.style === style.id\"\r\n (click)=\"updateConfig({style: style.id})\">\r\n <img [src]=\"getAvatarUrl({ style: style.id, seed: currentConfig.seed, bgColor: currentConfig.bgColor, shape: currentConfig.shape })\" alt=\"{{style.name}}\">\r\n <span>{{ style.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{display:inline-block;position:relative;font-family:Inter,Roboto,sans-serif}.avatar-container{position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;transition:all .3s ease;-webkit-user-select:none;user-select:none}.avatar-content{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.avatar-image{width:100%;height:100%;object-fit:cover}.edit-overlay{position:absolute;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;color:#fff;cursor:pointer;opacity:0;animation:fadeIn .2s forwards;backdrop-filter:blur(2px)}@keyframes fadeIn{to{opacity:1}}.editor-popover{position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%);width:320px;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;z-index:1000;border:1px solid #e2e8f0;padding:16px;animation:slideUp .3s cubic-bezier(.16,1,.3,1)}@keyframes slideUp{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}.editor-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;border-bottom:1px solid #f1f5f9;padding-bottom:8px}.editor-header h3{margin:0;font-size:14px;font-weight:600;color:#334155}.close-btn{background:none;border:none;font-size:20px;cursor:pointer;color:#94a3b8;padding:0;line-height:1}.close-btn:hover{color:#475569}.section{margin-bottom:16px}.section:last-child{margin-bottom:0}.section-title-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.section label{display:block;font-size:12px;color:#64748b;margin:0;font-weight:500;text-transform:uppercase;letter-spacing:.5px}.randomize-btn{background:#f1f5f9;border:none;border-radius:4px;padding:4px 8px;font-size:11px;color:#475569;cursor:pointer;font-weight:600;transition:background .2s}.randomize-btn:hover{background:#e2e8f0;color:#0f172a}.shape-options{display:flex;gap:8px}.shape-options button{flex:1;padding:8px;border:1px solid #e2e8f0;background:#f8fafc;border-radius:6px;cursor:pointer;font-size:13px;color:#475569;transition:all .2s}.shape-options button:hover{background:#f1f5f9}.shape-options button.active{background:#3b82f6;color:#fff;border-color:#3b82f6}.color-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}.color-swatch{width:100%;aspect-ratio:1;border-radius:50%;border:2px solid transparent;cursor:pointer;transition:transform .2s}.color-swatch:hover{transform:scale(1.1)}.color-swatch.active{border-color:#333;box-shadow:0 0 0 2px #fff inset}.style-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;max-height:200px;overflow-y:auto;padding-right:4px}.style-grid::-webkit-scrollbar{width:4px}.style-grid::-webkit-scrollbar-thumb{background-color:#cbd5e1;border-radius:4px}.style-card{border:1px solid #e2e8f0;background:white;border-radius:8px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:8px 4px;transition:all .2s}.style-card:hover{background:#f8fafc;border-color:#cbd5e1}.style-card.active{border-color:#3b82f6;background:#eff6ff}.style-card img{width:40px;height:40px;margin-bottom:4px;border-radius:50%}.style-card span{font-size:10px;color:#475569;font-weight:500;text-align:center}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
204
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorComponent, decorators: [{
|
|
205
|
+
type: Component,
|
|
206
|
+
args: [{ selector: 'lib-ng-avatar-creator', template: "<div class=\"avatar-container\" \r\n [style.width.px]=\"size\" \r\n [style.height.px]=\"size\"\r\n [style.borderRadius]=\"currentConfig.shape === 'circle' ? '50%' : '8px'\"\r\n (mouseenter)=\"hovering = true\"\r\n (mouseleave)=\"hovering = false\">\r\n \r\n <div class=\"avatar-content\">\r\n <img [src]=\"getAvatarUrl()\" alt=\"Avatar\" class=\"avatar-image\">\r\n </div>\r\n\r\n <div class=\"edit-overlay\" *ngIf=\"editable && hovering\" (click)=\"toggleEditor()\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"24\" height=\"24\">\r\n <path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\"/>\r\n </svg>\r\n </div>\r\n</div>\r\n\r\n<div class=\"editor-popover\" *ngIf=\"editorOpen\">\r\n <div class=\"editor-header\">\r\n <h3>Customize Avatar</h3>\r\n <button class=\"close-btn\" (click)=\"toggleEditor()\">×</button>\r\n </div>\r\n \r\n <div class=\"editor-body\">\r\n <div class=\"section\">\r\n <label>Shape</label>\r\n <div class=\"shape-options\">\r\n <button [class.active]=\"currentConfig.shape === 'circle'\" (click)=\"updateConfig({shape: 'circle'})\">Circle</button>\r\n <button [class.active]=\"currentConfig.shape === 'square'\" (click)=\"updateConfig({shape: 'square'})\">Square</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <label>Background Color</label>\r\n <div class=\"color-grid\">\r\n <button *ngFor=\"let color of colors\" \r\n class=\"color-swatch\" \r\n [style.backgroundColor]=\"color\"\r\n [class.active]=\"currentConfig.bgColor === color\"\r\n (click)=\"updateConfig({bgColor: color})\">\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title-row\">\r\n <label>Style Category</label>\r\n <button class=\"randomize-btn\" (click)=\"randomizeSeed()\">\uD83C\uDFB2 Randomize</button>\r\n </div>\r\n <div class=\"style-grid\">\r\n <div *ngFor=\"let style of styles\" \r\n class=\"style-card\"\r\n [class.active]=\"currentConfig.style === style.id\"\r\n (click)=\"updateConfig({style: style.id})\">\r\n <img [src]=\"getAvatarUrl({ style: style.id, seed: currentConfig.seed, bgColor: currentConfig.bgColor, shape: currentConfig.shape })\" alt=\"{{style.name}}\">\r\n <span>{{ style.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{display:inline-block;position:relative;font-family:Inter,Roboto,sans-serif}.avatar-container{position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;transition:all .3s ease;-webkit-user-select:none;user-select:none}.avatar-content{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.avatar-image{width:100%;height:100%;object-fit:cover}.edit-overlay{position:absolute;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;color:#fff;cursor:pointer;opacity:0;animation:fadeIn .2s forwards;backdrop-filter:blur(2px)}@keyframes fadeIn{to{opacity:1}}.editor-popover{position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%);width:320px;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;z-index:1000;border:1px solid #e2e8f0;padding:16px;animation:slideUp .3s cubic-bezier(.16,1,.3,1)}@keyframes slideUp{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}.editor-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;border-bottom:1px solid #f1f5f9;padding-bottom:8px}.editor-header h3{margin:0;font-size:14px;font-weight:600;color:#334155}.close-btn{background:none;border:none;font-size:20px;cursor:pointer;color:#94a3b8;padding:0;line-height:1}.close-btn:hover{color:#475569}.section{margin-bottom:16px}.section:last-child{margin-bottom:0}.section-title-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.section label{display:block;font-size:12px;color:#64748b;margin:0;font-weight:500;text-transform:uppercase;letter-spacing:.5px}.randomize-btn{background:#f1f5f9;border:none;border-radius:4px;padding:4px 8px;font-size:11px;color:#475569;cursor:pointer;font-weight:600;transition:background .2s}.randomize-btn:hover{background:#e2e8f0;color:#0f172a}.shape-options{display:flex;gap:8px}.shape-options button{flex:1;padding:8px;border:1px solid #e2e8f0;background:#f8fafc;border-radius:6px;cursor:pointer;font-size:13px;color:#475569;transition:all .2s}.shape-options button:hover{background:#f1f5f9}.shape-options button.active{background:#3b82f6;color:#fff;border-color:#3b82f6}.color-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}.color-swatch{width:100%;aspect-ratio:1;border-radius:50%;border:2px solid transparent;cursor:pointer;transition:transform .2s}.color-swatch:hover{transform:scale(1.1)}.color-swatch.active{border-color:#333;box-shadow:0 0 0 2px #fff inset}.style-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;max-height:200px;overflow-y:auto;padding-right:4px}.style-grid::-webkit-scrollbar{width:4px}.style-grid::-webkit-scrollbar-thumb{background-color:#cbd5e1;border-radius:4px}.style-card{border:1px solid #e2e8f0;background:white;border-radius:8px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:8px 4px;transition:all .2s}.style-card:hover{background:#f8fafc;border-color:#cbd5e1}.style-card.active{border-color:#3b82f6;background:#eff6ff}.style-card img{width:40px;height:40px;margin-bottom:4px;border-radius:50%}.style-card span{font-size:10px;color:#475569;font-weight:500;text-align:center}\n"] }]
|
|
207
|
+
}], propDecorators: { firstName: [{
|
|
208
|
+
type: Input
|
|
209
|
+
}], lastName: [{
|
|
210
|
+
type: Input
|
|
211
|
+
}], size: [{
|
|
212
|
+
type: Input
|
|
213
|
+
}], editable: [{
|
|
214
|
+
type: Input
|
|
215
|
+
}], editorTitle: [{
|
|
216
|
+
type: Input
|
|
217
|
+
}], avatarConfig: [{
|
|
218
|
+
type: Input
|
|
219
|
+
}], avatarConfigChanged: [{
|
|
220
|
+
type: Output
|
|
221
|
+
}] } });
|
|
222
|
+
|
|
223
|
+
class NgAvatarCreatorModule {
|
|
224
|
+
}
|
|
225
|
+
NgAvatarCreatorModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
226
|
+
NgAvatarCreatorModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, declarations: [NgAvatarCreatorComponent], imports: [CommonModule], exports: [NgAvatarCreatorComponent] });
|
|
227
|
+
NgAvatarCreatorModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, imports: [CommonModule] });
|
|
228
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgAvatarCreatorModule, decorators: [{
|
|
229
|
+
type: NgModule,
|
|
230
|
+
args: [{
|
|
231
|
+
declarations: [
|
|
232
|
+
NgAvatarCreatorComponent
|
|
233
|
+
],
|
|
234
|
+
imports: [
|
|
235
|
+
CommonModule
|
|
236
|
+
],
|
|
237
|
+
exports: [
|
|
238
|
+
NgAvatarCreatorComponent
|
|
239
|
+
]
|
|
240
|
+
}]
|
|
241
|
+
}] });
|
|
242
|
+
|
|
243
|
+
/*
|
|
244
|
+
* Public API Surface of ng-avatar-creator
|
|
245
|
+
*/
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Generated bundle index. Do not edit.
|
|
249
|
+
*/
|
|
250
|
+
|
|
251
|
+
export { AVATAR_STYLES, NgAvatarCreatorComponent, NgAvatarCreatorModule, NgAvatarCreatorService, PREDEFINED_COLORS };
|
|
252
|
+
//# sourceMappingURL=gayath1-ng-avatar-creator.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gayath1-ng-avatar-creator.mjs","sources":["../../../projects/ng-avatar-creator/src/lib/ng-avatar-creator.service.ts","../../../projects/ng-avatar-creator/src/lib/avatar-models.ts","../../../projects/ng-avatar-creator/src/lib/ng-avatar-creator.component.ts","../../../projects/ng-avatar-creator/src/lib/ng-avatar-creator.component.html","../../../projects/ng-avatar-creator/src/lib/ng-avatar-creator.module.ts","../../../projects/ng-avatar-creator/src/public-api.ts","../../../projects/ng-avatar-creator/src/gayath1-ng-avatar-creator.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class NgAvatarCreatorService {\r\n\r\n constructor() { }\r\n}\r\n","export interface AvatarConfig {\n style: AvatarStyleId;\n seed: string;\n bgColor: string;\n shape: 'circle' | 'square';\n}\n\nexport type AvatarStyleId =\n | 'initials'\n | 'identicon'\n | 'rings'\n | 'shapes'\n | 'thumbs'\n | 'avataaars'\n | 'bottts'\n | 'glass';\n\nexport interface AvatarStyleOption {\n id: AvatarStyleId;\n name: string;\n}\n\nexport const AVATAR_STYLES = [\n { id: 'initials', name: 'Initials' },\n { id: 'identicon', name: 'Identicon' },\n { id: 'rings', name: 'Rings' },\r\n { id: 'shapes', name: 'Shapes' },\r\n { id: 'thumbs', name: 'Thumbs' },\r\n { id: 'avataaars', name: 'Avatars' },\n { id: 'bottts', name: 'Bots' },\n { id: 'glass', name: 'Glass' }\n] as AvatarStyleOption[];\n\nexport const PREDEFINED_COLORS = [\n '#ef4444', '#f97316', '#f59e0b', '#84cc16', '#22c55e',\n '#14b8a6', '#06b6d4', '#0ea5e9', '#3b82f6', '#6366f1',\n '#8b5cf6', '#a855f7', '#d946ef', '#ec4899', '#f43f5e',\n '#475569', '#111827', '#7c2d12', '#365314', '#164e63'\n];\n","import { Component, Input, Output, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';\nimport { AvatarConfig, AvatarStyleId, PREDEFINED_COLORS, AVATAR_STYLES } from './avatar-models';\n\r\n@Component({\r\n selector: 'lib-ng-avatar-creator',\r\n templateUrl: './ng-avatar-creator.component.html',\r\n styleUrls: ['./ng-avatar-creator.component.css']\r\n})\r\nexport class NgAvatarCreatorComponent implements OnInit, OnChanges {\n @Input() firstName: string = '';\n @Input() lastName: string = '';\n @Input() size: number = 64;\n @Input() editable: boolean = false;\n @Input() editorTitle: string = 'Customize Avatar';\n \n @Input() avatarConfig?: AvatarConfig;\n @Output() avatarConfigChanged = new EventEmitter<AvatarConfig>();\n\n hovering: boolean = false;\n editorOpen: boolean = false;\r\n\r\n currentConfig: AvatarConfig = {\r\n style: 'initials',\n seed: '',\n bgColor: '#3b82f6',\n shape: 'circle'\n };\n\n colors = PREDEFINED_COLORS;\n styles = AVATAR_STYLES;\n\n ngOnInit() {\n this.syncConfig();\n this.avatarConfigChanged.emit({ ...this.currentConfig });\n }\n\n ngOnChanges(changes: SimpleChanges) {\n if (!changes['avatarConfig'] && !changes['firstName'] && !changes['lastName']) {\n return;\n }\n\n this.syncConfig();\n }\n\n private syncConfig() {\n if (this.avatarConfig) {\n this.currentConfig = { ...this.currentConfig, ...this.avatarConfig };\n } else {\n const defaultSeed = this.getDefaultSeed();\n const colorIndex = Math.abs(this.hash(defaultSeed)) % this.colors.length;\n this.currentConfig.bgColor = this.colors[colorIndex];\n this.currentConfig.seed = this.getDefaultSeed();\n }\n }\n\r\n getDefaultSeed(): string {\n const parts = [];\n if (this.firstName) parts.push(this.firstName);\n if (this.lastName) parts.push(this.lastName);\n return parts.join(' ') || 'User';\n }\n\n getAvatarUrl(config: AvatarConfig = this.currentConfig): string {\n return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(this.getAvatarSvg(config))}`;\n }\n\n getAvatarSvg(config: AvatarConfig = this.currentConfig): string {\n const seed = this.getEffectiveSeed(config);\n const hash = this.hash(seed);\n const initials = this.getInitials(seed);\n const accent = this.pickAccent(config.bgColor, hash);\n const dark = this.adjustColor(config.bgColor, -34);\n const light = this.adjustColor(config.bgColor, 46);\n const mask = config.shape === 'circle' ? '<clipPath id=\"clip\"><circle cx=\"50\" cy=\"50\" r=\"50\"/></clipPath>' : '<clipPath id=\"clip\"><rect width=\"100\" height=\"100\" rx=\"12\"/></clipPath>';\n const content = this.renderStyle(config.style, hash, initials, config.bgColor, accent, dark, light);\n\n return [\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100\" height=\"100\" viewBox=\"0 0 100 100\" role=\"img\" aria-label=\"Avatar\">',\n '<defs>',\n mask,\n '<filter id=\"shadow\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\"><feDropShadow dx=\"0\" dy=\"4\" stdDeviation=\"5\" flood-opacity=\".18\"/></filter>',\n '</defs>',\n '<g clip-path=\"url(#clip)\">',\n `<rect width=\"100\" height=\"100\" fill=\"${config.bgColor}\"/>`,\n content,\n '</g>',\n '</svg>'\n ].join('');\n }\n\n randomizeSeed() {\n const randomString = `avatar-${Math.random().toString(36).substring(2, 8)}`;\n this.updateConfig({ seed: randomString });\n }\n\n setSeed(value: string) {\n this.updateConfig({ seed: value || this.getDefaultSeed() });\n }\n\n toggleEditor() {\n this.editorOpen = !this.editorOpen;\n }\n\n updateConfig(partial: Partial<AvatarConfig>) {\n this.currentConfig = { ...this.currentConfig, ...partial };\n\n if (partial.style === 'initials') {\n this.currentConfig.seed = this.getDefaultSeed();\n }\n \n this.avatarConfigChanged.emit({ ...this.currentConfig });\n }\n\n trackByStyle(_: number, style: { id: AvatarStyleId }) {\n return style.id;\n }\n\n private renderStyle(style: AvatarStyleId, hash: number, initials: string, bg: string, accent: string, dark: string, light: string): string {\n switch (style) {\n case 'initials':\n return `<circle cx=\"76\" cy=\"23\" r=\"24\" fill=\"${light}\" opacity=\".8\"/><circle cx=\"20\" cy=\"78\" r=\"30\" fill=\"${dark}\" opacity=\".32\"/><text x=\"50\" y=\"58\" text-anchor=\"middle\" font-family=\"Arial, Helvetica, sans-serif\" font-size=\"34\" font-weight=\"700\" fill=\"#fff\">${initials}</text>`;\n case 'identicon':\n return this.renderIdenticon(hash, accent, dark, light);\n case 'rings':\n return `<circle cx=\"50\" cy=\"50\" r=\"42\" fill=\"none\" stroke=\"${light}\" stroke-width=\"12\" opacity=\".9\"/><circle cx=\"50\" cy=\"50\" r=\"27\" fill=\"none\" stroke=\"${accent}\" stroke-width=\"10\"/><circle cx=\"50\" cy=\"50\" r=\"12\" fill=\"${dark}\"/><path d=\"M50 8a42 42 0 0 1 36 21\" stroke=\"#fff\" stroke-width=\"8\" stroke-linecap=\"round\" opacity=\".65\" fill=\"none\"/>`;\n case 'shapes':\n return `<rect x=\"12\" y=\"14\" width=\"34\" height=\"34\" rx=\"10\" fill=\"${light}\" transform=\"rotate(${hash % 24} 29 31)\"/><circle cx=\"68\" cy=\"34\" r=\"20\" fill=\"${accent}\"/><path d=\"M21 82 47 50l29 32Z\" fill=\"${dark}\"/><circle cx=\"74\" cy=\"76\" r=\"10\" fill=\"#fff\" opacity=\".7\"/>`;\n case 'thumbs':\n return `<circle cx=\"50\" cy=\"50\" r=\"31\" fill=\"${light}\"/><path d=\"M29 51h11l8-20c2-5 10-3 9 3l-2 12h13c5 0 8 4 7 9l-4 20c-1 5-5 8-10 8H36c-4 0-7-3-7-7V51Z\" fill=\"#fff\"/><rect x=\"21\" y=\"51\" width=\"15\" height=\"32\" rx=\"6\" fill=\"${dark}\"/>`;\n case 'avataaars':\n return `<circle cx=\"50\" cy=\"55\" r=\"28\" fill=\"#ffd7b5\"/><path d=\"M23 48c2-21 17-32 34-29 13 2 21 12 22 28-12-8-25-8-34-3-8 5-15 5-22 4Z\" fill=\"${dark}\"/><circle cx=\"39\" cy=\"57\" r=\"4\" fill=\"#1f2937\"/><circle cx=\"61\" cy=\"57\" r=\"4\" fill=\"#1f2937\"/><path d=\"M40 73c7 5 14 5 21 0\" stroke=\"#9f1239\" stroke-width=\"4\" stroke-linecap=\"round\" fill=\"none\"/><path d=\"M18 100c6-18 21-27 32-27s26 9 32 27Z\" fill=\"${accent}\"/>`;\n case 'bottts':\n return `<rect x=\"22\" y=\"28\" width=\"56\" height=\"48\" rx=\"14\" fill=\"${light}\" filter=\"url(#shadow)\"/><rect x=\"32\" y=\"45\" width=\"13\" height=\"11\" rx=\"4\" fill=\"${dark}\"/><rect x=\"55\" y=\"45\" width=\"13\" height=\"11\" rx=\"4\" fill=\"${dark}\"/><path d=\"M39 66h22\" stroke=\"#fff\" stroke-width=\"5\" stroke-linecap=\"round\"/><path d=\"M50 28V15\" stroke=\"${dark}\" stroke-width=\"5\" stroke-linecap=\"round\"/><circle cx=\"50\" cy=\"13\" r=\"6\" fill=\"${accent}\"/>`;\n case 'glass':\n return `<circle cx=\"32\" cy=\"30\" r=\"24\" fill=\"#fff\" opacity=\".34\"/><circle cx=\"72\" cy=\"73\" r=\"32\" fill=\"${dark}\" opacity=\".36\"/><rect x=\"19\" y=\"19\" width=\"62\" height=\"62\" rx=\"18\" fill=\"#fff\" opacity=\".22\" stroke=\"#fff\" stroke-width=\"2\"/><text x=\"50\" y=\"59\" text-anchor=\"middle\" font-family=\"Arial, Helvetica, sans-serif\" font-size=\"28\" font-weight=\"700\" fill=\"#fff\">${initials}</text>`;\n default:\n return '';\n }\n }\n\n private renderIdenticon(hash: number, accent: string, dark: string, light: string): string {\n const cells: string[] = [];\n const colors = [accent, dark, light];\n\n for (let row = 0; row < 5; row++) {\n for (let col = 0; col < 3; col++) {\n const bit = (hash >> (row * 3 + col)) & 1;\n if (!bit) {\n continue;\n }\n\n const x = 20 + col * 12;\n const mirrorX = 20 + (4 - col) * 12;\n const y = 20 + row * 12;\n const color = colors[(row + col + Math.abs(hash)) % colors.length];\n cells.push(`<rect x=\"${x}\" y=\"${y}\" width=\"10\" height=\"10\" rx=\"2\" fill=\"${color}\"/>`);\n\n if (col !== 2) {\n cells.push(`<rect x=\"${mirrorX}\" y=\"${y}\" width=\"10\" height=\"10\" rx=\"2\" fill=\"${color}\"/>`);\n }\n }\n }\n\n return cells.join('');\n }\n\n private getEffectiveSeed(config: AvatarConfig): string {\n return config.style === 'initials' ? this.getDefaultSeed() : (config.seed || this.getDefaultSeed());\n }\n\n private getInitials(seed: string): string {\n const names = seed.trim().split(/\\s+/).filter(Boolean);\n const first = names[0]?.charAt(0) || 'U';\n const second = names.length > 1 ? names[names.length - 1].charAt(0) : names[0]?.charAt(1) || '';\n return `${first}${second}`.toUpperCase();\n }\n\n private hash(value: string): number {\n let hash = 0;\n for (let i = 0; i < value.length; i++) {\n hash = ((hash << 5) - hash) + value.charCodeAt(i);\n hash |= 0;\n }\n return hash || 1;\n }\n\n private pickAccent(color: string, hash: number): string {\n const index = Math.abs(hash) % this.colors.length;\n const picked = this.colors[index];\n return picked.toLowerCase() === color.toLowerCase() ? this.adjustColor(color, 60) : picked;\n }\n\n private adjustColor(hex: string, amount: number): string {\n const clean = hex.replace('#', '');\n const num = parseInt(clean, 16);\n const r = Math.max(0, Math.min(255, (num >> 16) + amount));\n const g = Math.max(0, Math.min(255, ((num >> 8) & 0x00ff) + amount));\n const b = Math.max(0, Math.min(255, (num & 0x0000ff) + amount));\n return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;\n }\n}\n","<div class=\"avatar-container\" \r\n [style.width.px]=\"size\" \r\n [style.height.px]=\"size\"\r\n [style.borderRadius]=\"currentConfig.shape === 'circle' ? '50%' : '8px'\"\r\n (mouseenter)=\"hovering = true\"\r\n (mouseleave)=\"hovering = false\">\r\n \r\n <div class=\"avatar-content\">\r\n <img [src]=\"getAvatarUrl()\" alt=\"Avatar\" class=\"avatar-image\">\r\n </div>\r\n\r\n <div class=\"edit-overlay\" *ngIf=\"editable && hovering\" (click)=\"toggleEditor()\">\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"24\" height=\"24\">\r\n <path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\"/>\r\n </svg>\r\n </div>\r\n</div>\r\n\r\n<div class=\"editor-popover\" *ngIf=\"editorOpen\">\r\n <div class=\"editor-header\">\r\n <h3>Customize Avatar</h3>\r\n <button class=\"close-btn\" (click)=\"toggleEditor()\">×</button>\r\n </div>\r\n \r\n <div class=\"editor-body\">\r\n <div class=\"section\">\r\n <label>Shape</label>\r\n <div class=\"shape-options\">\r\n <button [class.active]=\"currentConfig.shape === 'circle'\" (click)=\"updateConfig({shape: 'circle'})\">Circle</button>\r\n <button [class.active]=\"currentConfig.shape === 'square'\" (click)=\"updateConfig({shape: 'square'})\">Square</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <label>Background Color</label>\r\n <div class=\"color-grid\">\r\n <button *ngFor=\"let color of colors\" \r\n class=\"color-swatch\" \r\n [style.backgroundColor]=\"color\"\r\n [class.active]=\"currentConfig.bgColor === color\"\r\n (click)=\"updateConfig({bgColor: color})\">\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title-row\">\r\n <label>Style Category</label>\r\n <button class=\"randomize-btn\" (click)=\"randomizeSeed()\">🎲 Randomize</button>\r\n </div>\r\n <div class=\"style-grid\">\r\n <div *ngFor=\"let style of styles\" \r\n class=\"style-card\"\r\n [class.active]=\"currentConfig.style === style.id\"\r\n (click)=\"updateConfig({style: style.id})\">\r\n <img [src]=\"getAvatarUrl({ style: style.id, seed: currentConfig.seed, bgColor: currentConfig.bgColor, shape: currentConfig.shape })\" alt=\"{{style.name}}\">\r\n <span>{{ style.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n","import { NgModule } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { NgAvatarCreatorComponent } from './ng-avatar-creator.component';\r\n\r\n\r\n\r\n@NgModule({\r\n declarations: [\r\n NgAvatarCreatorComponent\r\n ],\r\n imports: [\r\n CommonModule\r\n ],\r\n exports: [\r\n NgAvatarCreatorComponent\r\n ]\r\n})\r\nexport class NgAvatarCreatorModule { }\r\n","/*\r\n * Public API Surface of ng-avatar-creator\r\n */\r\n\r\nexport * from './lib/ng-avatar-creator.service';\r\nexport * from './lib/ng-avatar-creator.component';\r\nexport * from './lib/ng-avatar-creator.module';\r\nexport * from './lib/avatar-models';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface AvatarConfig {
|
|
2
|
+
style: AvatarStyleId;
|
|
3
|
+
seed: string;
|
|
4
|
+
bgColor: string;
|
|
5
|
+
shape: 'circle' | 'square';
|
|
6
|
+
}
|
|
7
|
+
export declare type AvatarStyleId = 'initials' | 'identicon' | 'rings' | 'shapes' | 'thumbs' | 'avataaars' | 'bottts' | 'glass';
|
|
8
|
+
export interface AvatarStyleOption {
|
|
9
|
+
id: AvatarStyleId;
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const AVATAR_STYLES: AvatarStyleOption[];
|
|
13
|
+
export declare const PREDEFINED_COLORS: string[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { AvatarConfig, AvatarStyleId } from './avatar-models';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class NgAvatarCreatorComponent implements OnInit, OnChanges {
|
|
5
|
+
firstName: string;
|
|
6
|
+
lastName: string;
|
|
7
|
+
size: number;
|
|
8
|
+
editable: boolean;
|
|
9
|
+
editorTitle: string;
|
|
10
|
+
avatarConfig?: AvatarConfig;
|
|
11
|
+
avatarConfigChanged: EventEmitter<AvatarConfig>;
|
|
12
|
+
hovering: boolean;
|
|
13
|
+
editorOpen: boolean;
|
|
14
|
+
currentConfig: AvatarConfig;
|
|
15
|
+
colors: string[];
|
|
16
|
+
styles: import("./avatar-models").AvatarStyleOption[];
|
|
17
|
+
ngOnInit(): void;
|
|
18
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
19
|
+
private syncConfig;
|
|
20
|
+
getDefaultSeed(): string;
|
|
21
|
+
getAvatarUrl(config?: AvatarConfig): string;
|
|
22
|
+
getAvatarSvg(config?: AvatarConfig): string;
|
|
23
|
+
randomizeSeed(): void;
|
|
24
|
+
setSeed(value: string): void;
|
|
25
|
+
toggleEditor(): void;
|
|
26
|
+
updateConfig(partial: Partial<AvatarConfig>): void;
|
|
27
|
+
trackByStyle(_: number, style: {
|
|
28
|
+
id: AvatarStyleId;
|
|
29
|
+
}): AvatarStyleId;
|
|
30
|
+
private renderStyle;
|
|
31
|
+
private renderIdenticon;
|
|
32
|
+
private getEffectiveSeed;
|
|
33
|
+
private getInitials;
|
|
34
|
+
private hash;
|
|
35
|
+
private pickAccent;
|
|
36
|
+
private adjustColor;
|
|
37
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NgAvatarCreatorComponent, never>;
|
|
38
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<NgAvatarCreatorComponent, "lib-ng-avatar-creator", never, { "firstName": "firstName"; "lastName": "lastName"; "size": "size"; "editable": "editable"; "editorTitle": "editorTitle"; "avatarConfig": "avatarConfig"; }, { "avatarConfigChanged": "avatarConfigChanged"; }, never, never, false, never>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import * as i1 from "./ng-avatar-creator.component";
|
|
3
|
+
import * as i2 from "@angular/common";
|
|
4
|
+
export declare class NgAvatarCreatorModule {
|
|
5
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NgAvatarCreatorModule, never>;
|
|
6
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<NgAvatarCreatorModule, [typeof i1.NgAvatarCreatorComponent], [typeof i2.CommonModule], [typeof i1.NgAvatarCreatorComponent]>;
|
|
7
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<NgAvatarCreatorModule>;
|
|
8
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gayath1/ng-avatar-creator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"peerDependencies": {
|
|
5
|
+
"@angular/common": "^15.0.0",
|
|
6
|
+
"@angular/core": "^15.0.0"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"tslib": "^2.3.0"
|
|
10
|
+
},
|
|
11
|
+
"module": "fesm2015/gayath1-ng-avatar-creator.mjs",
|
|
12
|
+
"es2020": "fesm2020/gayath1-ng-avatar-creator.mjs",
|
|
13
|
+
"esm2020": "esm2020/gayath1-ng-avatar-creator.mjs",
|
|
14
|
+
"fesm2020": "fesm2020/gayath1-ng-avatar-creator.mjs",
|
|
15
|
+
"fesm2015": "fesm2015/gayath1-ng-avatar-creator.mjs",
|
|
16
|
+
"typings": "index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
"./package.json": {
|
|
19
|
+
"default": "./package.json"
|
|
20
|
+
},
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./index.d.ts",
|
|
23
|
+
"esm2020": "./esm2020/gayath1-ng-avatar-creator.mjs",
|
|
24
|
+
"es2020": "./fesm2020/gayath1-ng-avatar-creator.mjs",
|
|
25
|
+
"es2015": "./fesm2015/gayath1-ng-avatar-creator.mjs",
|
|
26
|
+
"node": "./fesm2015/gayath1-ng-avatar-creator.mjs",
|
|
27
|
+
"default": "./fesm2020/gayath1-ng-avatar-creator.mjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"sideEffects": false
|
|
31
|
+
}
|
package/public-api.d.ts
ADDED