valtech-components 2.0.677 → 2.0.679
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/esm2022/lib/components/molecules/image-crop/image-crop.component.mjs +174 -0
- package/esm2022/lib/components/molecules/image-crop/index.mjs +2 -0
- package/esm2022/lib/components/organisms/avatar-upload/avatar-upload.component.mjs +345 -0
- package/esm2022/lib/components/organisms/avatar-upload/types.mjs +15 -0
- package/esm2022/lib/components/organisms/bottom-nav/bottom-nav.component.mjs +3 -3
- package/esm2022/lib/services/auth/auth.service.mjs +10 -1
- package/esm2022/lib/services/auth/types.mjs +1 -1
- package/esm2022/lib/services/image/image.service.mjs +244 -0
- package/esm2022/lib/services/image/index.mjs +3 -0
- package/esm2022/lib/services/image/types.mjs +13 -0
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +7 -1
- package/fesm2022/valtech-components.mjs +784 -5
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +1 -1
- package/lib/components/atoms/text/text.component.d.ts +1 -1
- package/lib/components/molecules/features-list/features-list.component.d.ts +1 -1
- package/lib/components/molecules/image-crop/image-crop.component.d.ts +59 -0
- package/lib/components/molecules/image-crop/index.d.ts +1 -0
- package/lib/components/organisms/article/article.component.d.ts +4 -4
- package/lib/components/organisms/avatar-upload/avatar-upload.component.d.ts +82 -0
- package/lib/components/organisms/avatar-upload/types.d.ts +62 -0
- package/lib/components/organisms/bottom-nav/bottom-nav.component.d.ts +1 -1
- package/lib/components/organisms/toolbar/toolbar.component.d.ts +1 -1
- package/lib/services/auth/auth.service.d.ts +6 -1
- package/lib/services/auth/types.d.ts +18 -0
- package/lib/services/image/image.service.d.ts +76 -0
- package/lib/services/image/index.d.ts +2 -0
- package/lib/services/image/types.d.ts +74 -0
- package/lib/version.d.ts +1 -1
- package/package.json +6 -2
- package/public-api.d.ts +4 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component, computed, EventEmitter, inject, input, Output, signal, } from '@angular/core';
|
|
3
|
+
import { IonButton, IonButtons, IonContent, IonHeader, IonTitle, IonToolbar, } from '@ionic/angular/standalone';
|
|
4
|
+
import { ImageCropperComponent } from 'ngx-image-cropper';
|
|
5
|
+
import { I18nService } from '../../../services/i18n';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
/**
|
|
8
|
+
* ImageCropComponent
|
|
9
|
+
*
|
|
10
|
+
* A modal-ready component for cropping images with a specified aspect ratio.
|
|
11
|
+
* Uses ngx-image-cropper internally and provides a simple interface.
|
|
12
|
+
*
|
|
13
|
+
* @example Inside an ion-modal
|
|
14
|
+
* ```html
|
|
15
|
+
* <ion-modal [isOpen]="showCropModal">
|
|
16
|
+
* <ng-template>
|
|
17
|
+
* <val-image-crop
|
|
18
|
+
* [image]="selectedFile"
|
|
19
|
+
* [aspectRatio]="1"
|
|
20
|
+
* [roundCropper]="true"
|
|
21
|
+
* (cropComplete)="onCropComplete($event)"
|
|
22
|
+
* (cancel)="showCropModal = false"
|
|
23
|
+
* />
|
|
24
|
+
* </ng-template>
|
|
25
|
+
* </ion-modal>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class ImageCropComponent {
|
|
29
|
+
constructor() {
|
|
30
|
+
this.i18n = inject(I18nService);
|
|
31
|
+
/** Image file to crop */
|
|
32
|
+
this.image = input.required();
|
|
33
|
+
/** Aspect ratio (1 for square, 16/9 for widescreen, etc.) */
|
|
34
|
+
this.aspectRatio = input(1);
|
|
35
|
+
/** Use round cropper (for avatars) */
|
|
36
|
+
this.roundCropper = input(true);
|
|
37
|
+
/** Resize output to specific width (0 = no resize) */
|
|
38
|
+
this.resizeToWidth = input(0);
|
|
39
|
+
/** i18n namespace for labels */
|
|
40
|
+
this.i18nNamespace = input('ImageCrop');
|
|
41
|
+
/** Emitted when crop is confirmed with the cropped blob */
|
|
42
|
+
this.cropComplete = new EventEmitter();
|
|
43
|
+
/** Emitted when user cancels the crop */
|
|
44
|
+
this.cancel = new EventEmitter();
|
|
45
|
+
/** Emitted when image fails to load */
|
|
46
|
+
this.loadFailed = new EventEmitter();
|
|
47
|
+
/** Internal signal for cropped blob */
|
|
48
|
+
this.croppedBlob = signal(null);
|
|
49
|
+
/** Computed text for cancel button */
|
|
50
|
+
this.cancelText = computed(() => {
|
|
51
|
+
this.i18n.lang(); // Track language changes
|
|
52
|
+
return this.i18n.t('cancel', 'Common') || 'Cancelar';
|
|
53
|
+
});
|
|
54
|
+
/** Computed text for confirm button */
|
|
55
|
+
this.confirmText = computed(() => {
|
|
56
|
+
this.i18n.lang();
|
|
57
|
+
return this.i18n.t('confirm', 'Common') || 'Confirmar';
|
|
58
|
+
});
|
|
59
|
+
/** Computed text for title */
|
|
60
|
+
this.titleText = computed(() => {
|
|
61
|
+
this.i18n.lang();
|
|
62
|
+
return this.i18n.t('cropImage', this.i18nNamespace()) || 'Recortar imagen';
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/** Handle crop event from ngx-image-cropper */
|
|
66
|
+
onImageCropped(event) {
|
|
67
|
+
if (event.blob) {
|
|
68
|
+
this.croppedBlob.set(event.blob);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Confirm and emit the cropped blob */
|
|
72
|
+
confirmCrop() {
|
|
73
|
+
const blob = this.croppedBlob();
|
|
74
|
+
if (blob) {
|
|
75
|
+
this.cropComplete.emit(blob);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** Handle load failure */
|
|
79
|
+
onLoadFailed() {
|
|
80
|
+
this.loadFailed.emit();
|
|
81
|
+
}
|
|
82
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageCropComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
83
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.14", type: ImageCropComponent, isStandalone: true, selector: "val-image-crop", inputs: { image: { classPropertyName: "image", publicName: "image", isSignal: true, isRequired: true, transformFunction: null }, aspectRatio: { classPropertyName: "aspectRatio", publicName: "aspectRatio", isSignal: true, isRequired: false, transformFunction: null }, roundCropper: { classPropertyName: "roundCropper", publicName: "roundCropper", isSignal: true, isRequired: false, transformFunction: null }, resizeToWidth: { classPropertyName: "resizeToWidth", publicName: "resizeToWidth", isSignal: true, isRequired: false, transformFunction: null }, i18nNamespace: { classPropertyName: "i18nNamespace", publicName: "i18nNamespace", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cropComplete: "cropComplete", cancel: "cancel", loadFailed: "loadFailed" }, ngImport: i0, template: `
|
|
84
|
+
<ion-header>
|
|
85
|
+
<ion-toolbar>
|
|
86
|
+
<ion-buttons slot="start">
|
|
87
|
+
<ion-button (click)="cancel.emit()" color="medium">
|
|
88
|
+
{{ cancelText() }}
|
|
89
|
+
</ion-button>
|
|
90
|
+
</ion-buttons>
|
|
91
|
+
<ion-title>{{ titleText() }}</ion-title>
|
|
92
|
+
<ion-buttons slot="end">
|
|
93
|
+
<ion-button
|
|
94
|
+
(click)="confirmCrop()"
|
|
95
|
+
color="primary"
|
|
96
|
+
[strong]="true"
|
|
97
|
+
[disabled]="!croppedBlob()"
|
|
98
|
+
>
|
|
99
|
+
{{ confirmText() }}
|
|
100
|
+
</ion-button>
|
|
101
|
+
</ion-buttons>
|
|
102
|
+
</ion-toolbar>
|
|
103
|
+
</ion-header>
|
|
104
|
+
|
|
105
|
+
<ion-content class="image-crop-content">
|
|
106
|
+
<image-cropper
|
|
107
|
+
[imageFile]="image()"
|
|
108
|
+
[aspectRatio]="aspectRatio()"
|
|
109
|
+
[maintainAspectRatio]="true"
|
|
110
|
+
[roundCropper]="roundCropper()"
|
|
111
|
+
[resizeToWidth]="resizeToWidth()"
|
|
112
|
+
format="jpeg"
|
|
113
|
+
outputType="blob"
|
|
114
|
+
(imageCropped)="onImageCropped($event)"
|
|
115
|
+
(loadImageFailed)="onLoadFailed()"
|
|
116
|
+
/>
|
|
117
|
+
</ion-content>
|
|
118
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}.image-crop-content{--background: var(--ion-color-dark)}.image-crop-content::part(scroll){display:flex;flex-direction:column}image-cropper{--cropper-outline-color: rgba(255, 255, 255, .3);--cropper-background-color: var(--ion-color-dark);flex:1;height:100%;max-height:calc(100vh - 56px)}::ng-deep .ngx-ic-component{height:100%!important}::ng-deep .ngx-ic-source-image{max-height:100%!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: ImageCropperComponent, selector: "image-cropper", inputs: ["imageChangedEvent", "imageURL", "imageBase64", "imageFile", "imageAltText", "options", "cropperFrameAriaLabel", "output", "format", "autoCrop", "cropper", "transform", "maintainAspectRatio", "aspectRatio", "resetCropOnAspectRatioChange", "resizeToWidth", "resizeToHeight", "cropperMinWidth", "cropperMinHeight", "cropperMaxHeight", "cropperMaxWidth", "cropperStaticWidth", "cropperStaticHeight", "canvasRotation", "initialStepSize", "roundCropper", "onlyScaleDown", "imageQuality", "backgroundColor", "containWithinAspectRatio", "hideResizeSquares", "allowMoveImage", "checkImageType", "alignImage", "disabled", "hidden"], outputs: ["imageCropped", "startCropImage", "imageLoaded", "cropperReady", "loadImageFailed", "transformChange", "cropperChange"] }] }); }
|
|
119
|
+
}
|
|
120
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageCropComponent, decorators: [{
|
|
121
|
+
type: Component,
|
|
122
|
+
args: [{ selector: 'val-image-crop', standalone: true, imports: [
|
|
123
|
+
CommonModule,
|
|
124
|
+
IonHeader,
|
|
125
|
+
IonToolbar,
|
|
126
|
+
IonTitle,
|
|
127
|
+
IonButtons,
|
|
128
|
+
IonButton,
|
|
129
|
+
IonContent,
|
|
130
|
+
ImageCropperComponent,
|
|
131
|
+
], template: `
|
|
132
|
+
<ion-header>
|
|
133
|
+
<ion-toolbar>
|
|
134
|
+
<ion-buttons slot="start">
|
|
135
|
+
<ion-button (click)="cancel.emit()" color="medium">
|
|
136
|
+
{{ cancelText() }}
|
|
137
|
+
</ion-button>
|
|
138
|
+
</ion-buttons>
|
|
139
|
+
<ion-title>{{ titleText() }}</ion-title>
|
|
140
|
+
<ion-buttons slot="end">
|
|
141
|
+
<ion-button
|
|
142
|
+
(click)="confirmCrop()"
|
|
143
|
+
color="primary"
|
|
144
|
+
[strong]="true"
|
|
145
|
+
[disabled]="!croppedBlob()"
|
|
146
|
+
>
|
|
147
|
+
{{ confirmText() }}
|
|
148
|
+
</ion-button>
|
|
149
|
+
</ion-buttons>
|
|
150
|
+
</ion-toolbar>
|
|
151
|
+
</ion-header>
|
|
152
|
+
|
|
153
|
+
<ion-content class="image-crop-content">
|
|
154
|
+
<image-cropper
|
|
155
|
+
[imageFile]="image()"
|
|
156
|
+
[aspectRatio]="aspectRatio()"
|
|
157
|
+
[maintainAspectRatio]="true"
|
|
158
|
+
[roundCropper]="roundCropper()"
|
|
159
|
+
[resizeToWidth]="resizeToWidth()"
|
|
160
|
+
format="jpeg"
|
|
161
|
+
outputType="blob"
|
|
162
|
+
(imageCropped)="onImageCropped($event)"
|
|
163
|
+
(loadImageFailed)="onLoadFailed()"
|
|
164
|
+
/>
|
|
165
|
+
</ion-content>
|
|
166
|
+
`, styles: [":host{display:flex;flex-direction:column;height:100%}.image-crop-content{--background: var(--ion-color-dark)}.image-crop-content::part(scroll){display:flex;flex-direction:column}image-cropper{--cropper-outline-color: rgba(255, 255, 255, .3);--cropper-background-color: var(--ion-color-dark);flex:1;height:100%;max-height:calc(100vh - 56px)}::ng-deep .ngx-ic-component{height:100%!important}::ng-deep .ngx-ic-source-image{max-height:100%!important}\n"] }]
|
|
167
|
+
}], propDecorators: { cropComplete: [{
|
|
168
|
+
type: Output
|
|
169
|
+
}], cancel: [{
|
|
170
|
+
type: Output
|
|
171
|
+
}], loadFailed: [{
|
|
172
|
+
type: Output
|
|
173
|
+
}] } });
|
|
174
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtY3JvcC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvbW9sZWN1bGVzL2ltYWdlLWNyb3AvaW1hZ2UtY3JvcC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFDTCxTQUFTLEVBQ1QsUUFBUSxFQUNSLFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUNMLE1BQU0sRUFDTixNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUNMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsVUFBVSxFQUNWLFNBQVMsRUFDVCxRQUFRLEVBQ1IsVUFBVSxHQUNYLE1BQU0sMkJBQTJCLENBQUM7QUFDbkMsT0FBTyxFQUFxQixxQkFBcUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzdFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQzs7QUFFckQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBc0ZILE1BQU0sT0FBTyxrQkFBa0I7SUFyRi9CO1FBc0ZVLFNBQUksR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7UUFFbkMseUJBQXlCO1FBQ2hCLFVBQUssR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFRLENBQUM7UUFFeEMsNkRBQTZEO1FBQ3BELGdCQUFXLEdBQUcsS0FBSyxDQUFTLENBQUMsQ0FBQyxDQUFDO1FBRXhDLHNDQUFzQztRQUM3QixpQkFBWSxHQUFHLEtBQUssQ0FBVSxJQUFJLENBQUMsQ0FBQztRQUU3QyxzREFBc0Q7UUFDN0Msa0JBQWEsR0FBRyxLQUFLLENBQVMsQ0FBQyxDQUFDLENBQUM7UUFFMUMsZ0NBQWdDO1FBQ3ZCLGtCQUFhLEdBQUcsS0FBSyxDQUFTLFdBQVcsQ0FBQyxDQUFDO1FBRXBELDJEQUEyRDtRQUNqRCxpQkFBWSxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7UUFFbEQseUNBQXlDO1FBQy9CLFdBQU0sR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO1FBRTVDLHVDQUF1QztRQUM3QixlQUFVLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUVoRCx1Q0FBdUM7UUFDN0IsZ0JBQVcsR0FBRyxNQUFNLENBQWMsSUFBSSxDQUFDLENBQUM7UUFFbEQsc0NBQXNDO1FBQzVCLGVBQVUsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1lBQ25DLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyx5QkFBeUI7WUFDM0MsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLElBQUksVUFBVSxDQUFDO1FBQ3ZELENBQUMsQ0FBQyxDQUFDO1FBRUgsdUNBQXVDO1FBQzdCLGdCQUFXLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtZQUNwQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2pCLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxJQUFJLFdBQVcsQ0FBQztRQUN6RCxDQUFDLENBQUMsQ0FBQztRQUVILDhCQUE4QjtRQUNwQixjQUFTLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtZQUNsQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2pCLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxJQUFJLGlCQUFpQixDQUFDO1FBQzdFLENBQUMsQ0FBQyxDQUFDO0tBcUJKO0lBbkJDLCtDQUErQztJQUMvQyxjQUFjLENBQUMsS0FBd0I7UUFDckMsSUFBSSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDbkMsQ0FBQztJQUNILENBQUM7SUFFRCx3Q0FBd0M7SUFDeEMsV0FBVztRQUNULE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNoQyxJQUFJLElBQUksRUFBRSxDQUFDO1lBQ1QsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDL0IsQ0FBQztJQUNILENBQUM7SUFFRCwwQkFBMEI7SUFDMUIsWUFBWTtRQUNWLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDekIsQ0FBQzsrR0FsRVUsa0JBQWtCO21HQUFsQixrQkFBa0IsMjFCQXhFbkI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUNULDBnQkE1Q0MsWUFBWSwrQkFDWixTQUFTLG9HQUNULFVBQVUsbUZBQ1YsUUFBUSxpRkFDUixVQUFVLDhFQUNWLFNBQVMsb1BBQ1QsVUFBVSx3S0FDVixxQkFBcUI7OzRGQTBFWixrQkFBa0I7a0JBckY5QixTQUFTOytCQUNFLGdCQUFnQixjQUNkLElBQUksV0FDUDt3QkFDUCxZQUFZO3dCQUNaLFNBQVM7d0JBQ1QsVUFBVTt3QkFDVixRQUFRO3dCQUNSLFVBQVU7d0JBQ1YsU0FBUzt3QkFDVCxVQUFVO3dCQUNWLHFCQUFxQjtxQkFDdEIsWUFDUzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQ1Q7OEJBd0RTLFlBQVk7c0JBQXJCLE1BQU07Z0JBR0csTUFBTTtzQkFBZixNQUFNO2dCQUdHLFVBQVU7c0JBQW5CLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBjb21wdXRlZCxcbiAgRXZlbnRFbWl0dGVyLFxuICBpbmplY3QsXG4gIGlucHV0LFxuICBPdXRwdXQsXG4gIHNpZ25hbCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBJb25CdXR0b24sXG4gIElvbkJ1dHRvbnMsXG4gIElvbkNvbnRlbnQsXG4gIElvbkhlYWRlcixcbiAgSW9uVGl0bGUsXG4gIElvblRvb2xiYXIsXG59IGZyb20gJ0Bpb25pYy9hbmd1bGFyL3N0YW5kYWxvbmUnO1xuaW1wb3J0IHsgSW1hZ2VDcm9wcGVkRXZlbnQsIEltYWdlQ3JvcHBlckNvbXBvbmVudCB9IGZyb20gJ25neC1pbWFnZS1jcm9wcGVyJztcbmltcG9ydCB7IEkxOG5TZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvaTE4bic7XG5cbi8qKlxuICogSW1hZ2VDcm9wQ29tcG9uZW50XG4gKlxuICogQSBtb2RhbC1yZWFkeSBjb21wb25lbnQgZm9yIGNyb3BwaW5nIGltYWdlcyB3aXRoIGEgc3BlY2lmaWVkIGFzcGVjdCByYXRpby5cbiAqIFVzZXMgbmd4LWltYWdlLWNyb3BwZXIgaW50ZXJuYWxseSBhbmQgcHJvdmlkZXMgYSBzaW1wbGUgaW50ZXJmYWNlLlxuICpcbiAqIEBleGFtcGxlIEluc2lkZSBhbiBpb24tbW9kYWxcbiAqIGBgYGh0bWxcbiAqIDxpb24tbW9kYWwgW2lzT3Blbl09XCJzaG93Q3JvcE1vZGFsXCI+XG4gKiAgIDxuZy10ZW1wbGF0ZT5cbiAqICAgICA8dmFsLWltYWdlLWNyb3BcbiAqICAgICAgIFtpbWFnZV09XCJzZWxlY3RlZEZpbGVcIlxuICogICAgICAgW2FzcGVjdFJhdGlvXT1cIjFcIlxuICogICAgICAgW3JvdW5kQ3JvcHBlcl09XCJ0cnVlXCJcbiAqICAgICAgIChjcm9wQ29tcGxldGUpPVwib25Dcm9wQ29tcGxldGUoJGV2ZW50KVwiXG4gKiAgICAgICAoY2FuY2VsKT1cInNob3dDcm9wTW9kYWwgPSBmYWxzZVwiXG4gKiAgICAgLz5cbiAqICAgPC9uZy10ZW1wbGF0ZT5cbiAqIDwvaW9uLW1vZGFsPlxuICogYGBgXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3ZhbC1pbWFnZS1jcm9wJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIENvbW1vbk1vZHVsZSxcbiAgICBJb25IZWFkZXIsXG4gICAgSW9uVG9vbGJhcixcbiAgICBJb25UaXRsZSxcbiAgICBJb25CdXR0b25zLFxuICAgIElvbkJ1dHRvbixcbiAgICBJb25Db250ZW50LFxuICAgIEltYWdlQ3JvcHBlckNvbXBvbmVudCxcbiAgXSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8aW9uLWhlYWRlcj5cbiAgICAgIDxpb24tdG9vbGJhcj5cbiAgICAgICAgPGlvbi1idXR0b25zIHNsb3Q9XCJzdGFydFwiPlxuICAgICAgICAgIDxpb24tYnV0dG9uIChjbGljayk9XCJjYW5jZWwuZW1pdCgpXCIgY29sb3I9XCJtZWRpdW1cIj5cbiAgICAgICAgICAgIHt7IGNhbmNlbFRleHQoKSB9fVxuICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgICAgPC9pb24tYnV0dG9ucz5cbiAgICAgICAgPGlvbi10aXRsZT57eyB0aXRsZVRleHQoKSB9fTwvaW9uLXRpdGxlPlxuICAgICAgICA8aW9uLWJ1dHRvbnMgc2xvdD1cImVuZFwiPlxuICAgICAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgICAgICAoY2xpY2spPVwiY29uZmlybUNyb3AoKVwiXG4gICAgICAgICAgICBjb2xvcj1cInByaW1hcnlcIlxuICAgICAgICAgICAgW3N0cm9uZ109XCJ0cnVlXCJcbiAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhY3JvcHBlZEJsb2IoKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAge3sgY29uZmlybVRleHQoKSB9fVxuICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgICAgPC9pb24tYnV0dG9ucz5cbiAgICAgIDwvaW9uLXRvb2xiYXI+XG4gICAgPC9pb24taGVhZGVyPlxuXG4gICAgPGlvbi1jb250ZW50IGNsYXNzPVwiaW1hZ2UtY3JvcC1jb250ZW50XCI+XG4gICAgICA8aW1hZ2UtY3JvcHBlclxuICAgICAgICBbaW1hZ2VGaWxlXT1cImltYWdlKClcIlxuICAgICAgICBbYXNwZWN0UmF0aW9dPVwiYXNwZWN0UmF0aW8oKVwiXG4gICAgICAgIFttYWludGFpbkFzcGVjdFJhdGlvXT1cInRydWVcIlxuICAgICAgICBbcm91bmRDcm9wcGVyXT1cInJvdW5kQ3JvcHBlcigpXCJcbiAgICAgICAgW3Jlc2l6ZVRvV2lkdGhdPVwicmVzaXplVG9XaWR0aCgpXCJcbiAgICAgICAgZm9ybWF0PVwianBlZ1wiXG4gICAgICAgIG91dHB1dFR5cGU9XCJibG9iXCJcbiAgICAgICAgKGltYWdlQ3JvcHBlZCk9XCJvbkltYWdlQ3JvcHBlZCgkZXZlbnQpXCJcbiAgICAgICAgKGxvYWRJbWFnZUZhaWxlZCk9XCJvbkxvYWRGYWlsZWQoKVwiXG4gICAgICAvPlxuICAgIDwvaW9uLWNvbnRlbnQ+XG4gIGAsXG4gIHN0eWxlczogW1xuICAgIGBcbiAgICAgIDpob3N0IHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgICAgICAgaGVpZ2h0OiAxMDAlO1xuICAgICAgfVxuXG4gICAgICAuaW1hZ2UtY3JvcC1jb250ZW50IHtcbiAgICAgICAgLS1iYWNrZ3JvdW5kOiB2YXIoLS1pb24tY29sb3ItZGFyayk7XG4gICAgICB9XG5cbiAgICAgIC5pbWFnZS1jcm9wLWNvbnRlbnQ6OnBhcnQoc2Nyb2xsKSB7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICAgICB9XG5cbiAgICAgIGltYWdlLWNyb3BwZXIge1xuICAgICAgICAtLWNyb3BwZXItb3V0bGluZS1jb2xvcjogcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjMpO1xuICAgICAgICAtLWNyb3BwZXItYmFja2dyb3VuZC1jb2xvcjogdmFyKC0taW9uLWNvbG9yLWRhcmspO1xuICAgICAgICBmbGV4OiAxO1xuICAgICAgICBoZWlnaHQ6IDEwMCU7XG4gICAgICAgIG1heC1oZWlnaHQ6IGNhbGMoMTAwdmggLSA1NnB4KTtcbiAgICAgIH1cblxuICAgICAgLyogRW5zdXJlIHRoZSBjcm9wcGVyIHdyYXBwZXIgdGFrZXMgZnVsbCBoZWlnaHQgKi9cbiAgICAgIDo6bmctZGVlcCAubmd4LWljLWNvbXBvbmVudCB7XG4gICAgICAgIGhlaWdodDogMTAwJSAhaW1wb3J0YW50O1xuICAgICAgfVxuXG4gICAgICA6Om5nLWRlZXAgLm5neC1pYy1zb3VyY2UtaW1hZ2Uge1xuICAgICAgICBtYXgtaGVpZ2h0OiAxMDAlICFpbXBvcnRhbnQ7XG4gICAgICB9XG4gICAgYCxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgSW1hZ2VDcm9wQ29tcG9uZW50IHtcbiAgcHJpdmF0ZSBpMThuID0gaW5qZWN0KEkxOG5TZXJ2aWNlKTtcblxuICAvKiogSW1hZ2UgZmlsZSB0byBjcm9wICovXG4gIHJlYWRvbmx5IGltYWdlID0gaW5wdXQucmVxdWlyZWQ8RmlsZT4oKTtcblxuICAvKiogQXNwZWN0IHJhdGlvICgxIGZvciBzcXVhcmUsIDE2LzkgZm9yIHdpZGVzY3JlZW4sIGV0Yy4pICovXG4gIHJlYWRvbmx5IGFzcGVjdFJhdGlvID0gaW5wdXQ8bnVtYmVyPigxKTtcblxuICAvKiogVXNlIHJvdW5kIGNyb3BwZXIgKGZvciBhdmF0YXJzKSAqL1xuICByZWFkb25seSByb3VuZENyb3BwZXIgPSBpbnB1dDxib29sZWFuPih0cnVlKTtcblxuICAvKiogUmVzaXplIG91dHB1dCB0byBzcGVjaWZpYyB3aWR0aCAoMCA9IG5vIHJlc2l6ZSkgKi9cbiAgcmVhZG9ubHkgcmVzaXplVG9XaWR0aCA9IGlucHV0PG51bWJlcj4oMCk7XG5cbiAgLyoqIGkxOG4gbmFtZXNwYWNlIGZvciBsYWJlbHMgKi9cbiAgcmVhZG9ubHkgaTE4bk5hbWVzcGFjZSA9IGlucHV0PHN0cmluZz4oJ0ltYWdlQ3JvcCcpO1xuXG4gIC8qKiBFbWl0dGVkIHdoZW4gY3JvcCBpcyBjb25maXJtZWQgd2l0aCB0aGUgY3JvcHBlZCBibG9iICovXG4gIEBPdXRwdXQoKSBjcm9wQ29tcGxldGUgPSBuZXcgRXZlbnRFbWl0dGVyPEJsb2I+KCk7XG5cbiAgLyoqIEVtaXR0ZWQgd2hlbiB1c2VyIGNhbmNlbHMgdGhlIGNyb3AgKi9cbiAgQE91dHB1dCgpIGNhbmNlbCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICAvKiogRW1pdHRlZCB3aGVuIGltYWdlIGZhaWxzIHRvIGxvYWQgKi9cbiAgQE91dHB1dCgpIGxvYWRGYWlsZWQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgLyoqIEludGVybmFsIHNpZ25hbCBmb3IgY3JvcHBlZCBibG9iICovXG4gIHByb3RlY3RlZCBjcm9wcGVkQmxvYiA9IHNpZ25hbDxCbG9iIHwgbnVsbD4obnVsbCk7XG5cbiAgLyoqIENvbXB1dGVkIHRleHQgZm9yIGNhbmNlbCBidXR0b24gKi9cbiAgcHJvdGVjdGVkIGNhbmNlbFRleHQgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgdGhpcy5pMThuLmxhbmcoKTsgLy8gVHJhY2sgbGFuZ3VhZ2UgY2hhbmdlc1xuICAgIHJldHVybiB0aGlzLmkxOG4udCgnY2FuY2VsJywgJ0NvbW1vbicpIHx8ICdDYW5jZWxhcic7XG4gIH0pO1xuXG4gIC8qKiBDb21wdXRlZCB0ZXh0IGZvciBjb25maXJtIGJ1dHRvbiAqL1xuICBwcm90ZWN0ZWQgY29uZmlybVRleHQgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgdGhpcy5pMThuLmxhbmcoKTtcbiAgICByZXR1cm4gdGhpcy5pMThuLnQoJ2NvbmZpcm0nLCAnQ29tbW9uJykgfHwgJ0NvbmZpcm1hcic7XG4gIH0pO1xuXG4gIC8qKiBDb21wdXRlZCB0ZXh0IGZvciB0aXRsZSAqL1xuICBwcm90ZWN0ZWQgdGl0bGVUZXh0ID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIHRoaXMuaTE4bi5sYW5nKCk7XG4gICAgcmV0dXJuIHRoaXMuaTE4bi50KCdjcm9wSW1hZ2UnLCB0aGlzLmkxOG5OYW1lc3BhY2UoKSkgfHwgJ1JlY29ydGFyIGltYWdlbic7XG4gIH0pO1xuXG4gIC8qKiBIYW5kbGUgY3JvcCBldmVudCBmcm9tIG5neC1pbWFnZS1jcm9wcGVyICovXG4gIG9uSW1hZ2VDcm9wcGVkKGV2ZW50OiBJbWFnZUNyb3BwZWRFdmVudCk6IHZvaWQge1xuICAgIGlmIChldmVudC5ibG9iKSB7XG4gICAgICB0aGlzLmNyb3BwZWRCbG9iLnNldChldmVudC5ibG9iKTtcbiAgICB9XG4gIH1cblxuICAvKiogQ29uZmlybSBhbmQgZW1pdCB0aGUgY3JvcHBlZCBibG9iICovXG4gIGNvbmZpcm1Dcm9wKCk6IHZvaWQge1xuICAgIGNvbnN0IGJsb2IgPSB0aGlzLmNyb3BwZWRCbG9iKCk7XG4gICAgaWYgKGJsb2IpIHtcbiAgICAgIHRoaXMuY3JvcENvbXBsZXRlLmVtaXQoYmxvYik7XG4gICAgfVxuICB9XG5cbiAgLyoqIEhhbmRsZSBsb2FkIGZhaWx1cmUgKi9cbiAgb25Mb2FkRmFpbGVkKCk6IHZvaWQge1xuICAgIHRoaXMubG9hZEZhaWxlZC5lbWl0KCk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from './image-crop.component';
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvbW9sZWN1bGVzL2ltYWdlLWNyb3AvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyx3QkFBd0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vaW1hZ2UtY3JvcC5jb21wb25lbnQnO1xuIl19
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component, computed, EventEmitter, inject, input, Output, signal, ViewChild, } from '@angular/core';
|
|
3
|
+
import { IonIcon, IonModal, IonSpinner } from '@ionic/angular/standalone';
|
|
4
|
+
import { addIcons } from 'ionicons';
|
|
5
|
+
import { cameraOutline } from 'ionicons/icons';
|
|
6
|
+
import { firstValueFrom } from 'rxjs';
|
|
7
|
+
import { AuthService } from '../../../services/auth';
|
|
8
|
+
import { StorageService } from '../../../services/firebase';
|
|
9
|
+
import { I18nService } from '../../../services/i18n';
|
|
10
|
+
import { ImageService } from '../../../services/image';
|
|
11
|
+
import { ImageCropComponent } from '../../molecules/image-crop';
|
|
12
|
+
import { AVATAR_UPLOAD_DEFAULTS, } from './types';
|
|
13
|
+
import * as i0 from "@angular/core";
|
|
14
|
+
addIcons({ cameraOutline });
|
|
15
|
+
/**
|
|
16
|
+
* AvatarUploadComponent
|
|
17
|
+
*
|
|
18
|
+
* A complete avatar upload solution with:
|
|
19
|
+
* - Image selection from device
|
|
20
|
+
* - Crop modal with round preview
|
|
21
|
+
* - Automatic compression and thumbnail generation
|
|
22
|
+
* - Upload to Firebase Storage
|
|
23
|
+
* - Backend sync via AuthService
|
|
24
|
+
*
|
|
25
|
+
* @example Basic usage
|
|
26
|
+
* ```html
|
|
27
|
+
* <val-avatar-upload
|
|
28
|
+
* [props]="{
|
|
29
|
+
* currentUrl: user()?.avatarUrl,
|
|
30
|
+
* initials: 'JD',
|
|
31
|
+
* size: 120
|
|
32
|
+
* }"
|
|
33
|
+
* (uploaded)="onAvatarUploaded($event)"
|
|
34
|
+
* (error)="onError($event)"
|
|
35
|
+
* />
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export class AvatarUploadComponent {
|
|
39
|
+
constructor() {
|
|
40
|
+
this.imageService = inject(ImageService);
|
|
41
|
+
this.storageService = inject(StorageService);
|
|
42
|
+
this.authService = inject(AuthService);
|
|
43
|
+
this.i18n = inject(I18nService);
|
|
44
|
+
/** Component configuration */
|
|
45
|
+
this.props = input({});
|
|
46
|
+
/** Emitted after successful upload and backend sync */
|
|
47
|
+
this.uploaded = new EventEmitter();
|
|
48
|
+
/** Emitted on any error during the process */
|
|
49
|
+
this.error = new EventEmitter();
|
|
50
|
+
/** Emitted when upload starts */
|
|
51
|
+
this.uploadStart = new EventEmitter();
|
|
52
|
+
// Internal state
|
|
53
|
+
this.loading = signal(false);
|
|
54
|
+
this.showCropModal = signal(false);
|
|
55
|
+
this.selectedFile = signal(null);
|
|
56
|
+
this.previewUrl = signal(null);
|
|
57
|
+
this.imageLoadError = signal(false);
|
|
58
|
+
/** Merged config with defaults */
|
|
59
|
+
this.config = computed(() => ({
|
|
60
|
+
...AVATAR_UPLOAD_DEFAULTS,
|
|
61
|
+
...this.props(),
|
|
62
|
+
}));
|
|
63
|
+
/** URL to display (preview takes priority over current) */
|
|
64
|
+
this.displayUrl = computed(() => {
|
|
65
|
+
if (this.imageLoadError())
|
|
66
|
+
return null;
|
|
67
|
+
return this.previewUrl() || this.config().currentUrl || null;
|
|
68
|
+
});
|
|
69
|
+
/** Aria label for edit button */
|
|
70
|
+
this.editButtonLabel = computed(() => {
|
|
71
|
+
this.i18n.lang();
|
|
72
|
+
return this.i18n.t('changePhoto', this.config().i18nNamespace) || 'Cambiar foto';
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Open file picker dialog */
|
|
76
|
+
openFilePicker() {
|
|
77
|
+
this.fileInput.nativeElement.click();
|
|
78
|
+
}
|
|
79
|
+
/** Handle file selection */
|
|
80
|
+
onFileSelected(event) {
|
|
81
|
+
const input = event.target;
|
|
82
|
+
const file = input.files?.[0];
|
|
83
|
+
if (!file)
|
|
84
|
+
return;
|
|
85
|
+
// Reset input for same file selection
|
|
86
|
+
input.value = '';
|
|
87
|
+
// Validate file
|
|
88
|
+
const validation = this.imageService.validate(file, {
|
|
89
|
+
maxSize: this.config().maxFileSize,
|
|
90
|
+
allowedTypes: ['image/jpeg', 'image/png', 'image/webp'],
|
|
91
|
+
});
|
|
92
|
+
if (!validation.valid) {
|
|
93
|
+
this.emitError(validation.error, validation.message);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Open crop modal
|
|
97
|
+
this.selectedFile.set(file);
|
|
98
|
+
this.showCropModal.set(true);
|
|
99
|
+
}
|
|
100
|
+
/** Handle crop completion */
|
|
101
|
+
async onCropComplete(croppedBlob) {
|
|
102
|
+
this.showCropModal.set(false);
|
|
103
|
+
this.selectedFile.set(null);
|
|
104
|
+
await this.processAndUpload(croppedBlob);
|
|
105
|
+
}
|
|
106
|
+
/** Handle crop cancel */
|
|
107
|
+
onCropCancel() {
|
|
108
|
+
this.showCropModal.set(false);
|
|
109
|
+
this.selectedFile.set(null);
|
|
110
|
+
}
|
|
111
|
+
/** Handle crop load failure */
|
|
112
|
+
onCropLoadFailed() {
|
|
113
|
+
this.showCropModal.set(false);
|
|
114
|
+
this.selectedFile.set(null);
|
|
115
|
+
this.emitError('invalidType', this.i18n.t('loadFailed', this.config().i18nNamespace) || 'No se pudo cargar la imagen');
|
|
116
|
+
}
|
|
117
|
+
/** Handle image load error */
|
|
118
|
+
onImageError() {
|
|
119
|
+
this.imageLoadError.set(true);
|
|
120
|
+
}
|
|
121
|
+
/** Process cropped image and upload */
|
|
122
|
+
async processAndUpload(croppedBlob) {
|
|
123
|
+
this.loading.set(true);
|
|
124
|
+
this.uploadStart.emit();
|
|
125
|
+
try {
|
|
126
|
+
const config = this.config();
|
|
127
|
+
// 1. Compress image
|
|
128
|
+
const compressed = await this.imageService.compress(croppedBlob, {
|
|
129
|
+
maxWidth: config.maxWidth,
|
|
130
|
+
maxHeight: config.maxWidth,
|
|
131
|
+
quality: config.compressQuality,
|
|
132
|
+
});
|
|
133
|
+
// 2. Generate thumbnail
|
|
134
|
+
const thumbnail = await this.imageService.thumbnail(compressed.blob, config.thumbnailSize);
|
|
135
|
+
// 3. Set preview immediately
|
|
136
|
+
this.previewUrl.set(compressed.dataUrl);
|
|
137
|
+
this.imageLoadError.set(false);
|
|
138
|
+
// 4. Get user ID for storage path
|
|
139
|
+
const userId = this.authService.user()?.userId;
|
|
140
|
+
if (!userId) {
|
|
141
|
+
throw new Error('User not authenticated');
|
|
142
|
+
}
|
|
143
|
+
// 5. Upload to Firebase Storage
|
|
144
|
+
const timestamp = Date.now();
|
|
145
|
+
const avatarPath = `${config.storagePath}/${userId}/avatar_${timestamp}.jpg`;
|
|
146
|
+
const thumbPath = `${config.storagePath}/${userId}/thumb_${timestamp}.jpg`;
|
|
147
|
+
const [avatarResult, thumbResult] = await Promise.all([
|
|
148
|
+
this.storageService.uploadAndGetUrl(avatarPath, compressed.blob),
|
|
149
|
+
this.storageService.uploadAndGetUrl(thumbPath, thumbnail.blob),
|
|
150
|
+
]);
|
|
151
|
+
// 6. Update backend
|
|
152
|
+
await firstValueFrom(this.authService.updateAvatar({
|
|
153
|
+
avatarUrl: avatarResult.downloadUrl,
|
|
154
|
+
avatarThumbnail: thumbResult.downloadUrl,
|
|
155
|
+
}));
|
|
156
|
+
// 7. Emit success
|
|
157
|
+
const result = {
|
|
158
|
+
avatarUrl: avatarResult.downloadUrl,
|
|
159
|
+
thumbnailUrl: thumbResult.downloadUrl,
|
|
160
|
+
};
|
|
161
|
+
this.uploaded.emit(result);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
// Revert preview on error
|
|
165
|
+
this.previewUrl.set(null);
|
|
166
|
+
const message = err instanceof Error
|
|
167
|
+
? err.message
|
|
168
|
+
: this.i18n.t('uploadError', this.config().i18nNamespace) || 'Error al subir la imagen';
|
|
169
|
+
this.emitError('uploadFailed', message, err);
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
this.loading.set(false);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** Emit error event */
|
|
176
|
+
emitError(type, message, originalError) {
|
|
177
|
+
this.error.emit({ type, message, originalError });
|
|
178
|
+
}
|
|
179
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
180
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AvatarUploadComponent, isStandalone: true, selector: "val-avatar-upload", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { uploaded: "uploaded", error: "error", uploadStart: "uploadStart" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: `
|
|
181
|
+
<div
|
|
182
|
+
class="avatar-upload"
|
|
183
|
+
[style.--avatar-size.px]="config().size"
|
|
184
|
+
[class.avatar-upload--loading]="loading()"
|
|
185
|
+
>
|
|
186
|
+
<div class="avatar-container">
|
|
187
|
+
<!-- Avatar Image or Initials -->
|
|
188
|
+
@if (displayUrl()) {
|
|
189
|
+
<img
|
|
190
|
+
class="avatar-image"
|
|
191
|
+
[src]="displayUrl()"
|
|
192
|
+
alt="Avatar"
|
|
193
|
+
(error)="onImageError()"
|
|
194
|
+
/>
|
|
195
|
+
} @else {
|
|
196
|
+
<div
|
|
197
|
+
class="avatar-initials"
|
|
198
|
+
[style.background-color]="config().backgroundColor"
|
|
199
|
+
>
|
|
200
|
+
{{ config().initials || '?' }}
|
|
201
|
+
</div>
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
<!-- Edit Button -->
|
|
205
|
+
@if (config().editable && !loading()) {
|
|
206
|
+
<button
|
|
207
|
+
class="edit-button"
|
|
208
|
+
type="button"
|
|
209
|
+
(click)="openFilePicker()"
|
|
210
|
+
[attr.aria-label]="editButtonLabel()"
|
|
211
|
+
>
|
|
212
|
+
<ion-icon name="camera-outline"></ion-icon>
|
|
213
|
+
</button>
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
<!-- Loading Overlay -->
|
|
217
|
+
@if (loading()) {
|
|
218
|
+
<div class="loading-overlay">
|
|
219
|
+
<ion-spinner name="crescent"></ion-spinner>
|
|
220
|
+
</div>
|
|
221
|
+
}
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
<!-- Hidden File Input -->
|
|
225
|
+
<input
|
|
226
|
+
#fileInput
|
|
227
|
+
type="file"
|
|
228
|
+
accept="image/jpeg,image/png,image/webp"
|
|
229
|
+
(change)="onFileSelected($event)"
|
|
230
|
+
hidden
|
|
231
|
+
/>
|
|
232
|
+
|
|
233
|
+
<!-- Crop Modal -->
|
|
234
|
+
<ion-modal
|
|
235
|
+
[isOpen]="showCropModal()"
|
|
236
|
+
(didDismiss)="onCropCancel()"
|
|
237
|
+
[breakpoints]="[0, 1]"
|
|
238
|
+
[initialBreakpoint]="1"
|
|
239
|
+
>
|
|
240
|
+
<ng-template>
|
|
241
|
+
@if (selectedFile()) {
|
|
242
|
+
<val-image-crop
|
|
243
|
+
[image]="selectedFile()!"
|
|
244
|
+
[aspectRatio]="1"
|
|
245
|
+
[roundCropper]="true"
|
|
246
|
+
[i18nNamespace]="config().i18nNamespace"
|
|
247
|
+
(cropComplete)="onCropComplete($event)"
|
|
248
|
+
(cancel)="onCropCancel()"
|
|
249
|
+
(loadFailed)="onCropLoadFailed()"
|
|
250
|
+
/>
|
|
251
|
+
}
|
|
252
|
+
</ng-template>
|
|
253
|
+
</ion-modal>
|
|
254
|
+
</div>
|
|
255
|
+
`, isInline: true, styles: [".avatar-upload{--avatar-size: 100px;--edit-button-size: 32px;--edit-button-offset: 4px;display:inline-block}.avatar-container{position:relative;width:var(--avatar-size);height:var(--avatar-size);border-radius:50%;overflow:visible}.avatar-image{width:100%;height:100%;border-radius:50%;object-fit:cover;background-color:var(--ion-color-light)}.avatar-initials{width:100%;height:100%;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:calc(var(--avatar-size) * .4);font-weight:600;color:#fff;text-transform:uppercase;-webkit-user-select:none;user-select:none}.edit-button{position:absolute;bottom:var(--edit-button-offset);right:var(--edit-button-offset);width:var(--edit-button-size);height:var(--edit-button-size);border-radius:50%;border:2px solid white;background:var(--ion-color-primary);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:transform .2s ease,background-color .2s ease;box-shadow:0 2px 8px #00000026}.edit-button ion-icon{font-size:calc(var(--edit-button-size) * .5)}.edit-button:hover{transform:scale(1.1);background:var(--ion-color-primary-shade)}.edit-button:active{transform:scale(.95)}.edit-button:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%;background:#00000080;display:flex;align-items:center;justify-content:center}.loading-overlay ion-spinner{--color: white;width:calc(var(--avatar-size) * .4);height:calc(var(--avatar-size) * .4)}.avatar-upload--loading .edit-button{display:none}.avatar-upload--loading .avatar-image,.avatar-upload--loading .avatar-initials{filter:brightness(.7)}@container (max-width: 60px){.edit-button{--edit-button-size: 24px;--edit-button-offset: 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: ImageCropComponent, selector: "val-image-crop", inputs: ["image", "aspectRatio", "roundCropper", "resizeToWidth", "i18nNamespace"], outputs: ["cropComplete", "cancel", "loadFailed"] }] }); }
|
|
256
|
+
}
|
|
257
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarUploadComponent, decorators: [{
|
|
258
|
+
type: Component,
|
|
259
|
+
args: [{ selector: 'val-avatar-upload', standalone: true, imports: [CommonModule, IonIcon, IonSpinner, IonModal, ImageCropComponent], template: `
|
|
260
|
+
<div
|
|
261
|
+
class="avatar-upload"
|
|
262
|
+
[style.--avatar-size.px]="config().size"
|
|
263
|
+
[class.avatar-upload--loading]="loading()"
|
|
264
|
+
>
|
|
265
|
+
<div class="avatar-container">
|
|
266
|
+
<!-- Avatar Image or Initials -->
|
|
267
|
+
@if (displayUrl()) {
|
|
268
|
+
<img
|
|
269
|
+
class="avatar-image"
|
|
270
|
+
[src]="displayUrl()"
|
|
271
|
+
alt="Avatar"
|
|
272
|
+
(error)="onImageError()"
|
|
273
|
+
/>
|
|
274
|
+
} @else {
|
|
275
|
+
<div
|
|
276
|
+
class="avatar-initials"
|
|
277
|
+
[style.background-color]="config().backgroundColor"
|
|
278
|
+
>
|
|
279
|
+
{{ config().initials || '?' }}
|
|
280
|
+
</div>
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
<!-- Edit Button -->
|
|
284
|
+
@if (config().editable && !loading()) {
|
|
285
|
+
<button
|
|
286
|
+
class="edit-button"
|
|
287
|
+
type="button"
|
|
288
|
+
(click)="openFilePicker()"
|
|
289
|
+
[attr.aria-label]="editButtonLabel()"
|
|
290
|
+
>
|
|
291
|
+
<ion-icon name="camera-outline"></ion-icon>
|
|
292
|
+
</button>
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
<!-- Loading Overlay -->
|
|
296
|
+
@if (loading()) {
|
|
297
|
+
<div class="loading-overlay">
|
|
298
|
+
<ion-spinner name="crescent"></ion-spinner>
|
|
299
|
+
</div>
|
|
300
|
+
}
|
|
301
|
+
</div>
|
|
302
|
+
|
|
303
|
+
<!-- Hidden File Input -->
|
|
304
|
+
<input
|
|
305
|
+
#fileInput
|
|
306
|
+
type="file"
|
|
307
|
+
accept="image/jpeg,image/png,image/webp"
|
|
308
|
+
(change)="onFileSelected($event)"
|
|
309
|
+
hidden
|
|
310
|
+
/>
|
|
311
|
+
|
|
312
|
+
<!-- Crop Modal -->
|
|
313
|
+
<ion-modal
|
|
314
|
+
[isOpen]="showCropModal()"
|
|
315
|
+
(didDismiss)="onCropCancel()"
|
|
316
|
+
[breakpoints]="[0, 1]"
|
|
317
|
+
[initialBreakpoint]="1"
|
|
318
|
+
>
|
|
319
|
+
<ng-template>
|
|
320
|
+
@if (selectedFile()) {
|
|
321
|
+
<val-image-crop
|
|
322
|
+
[image]="selectedFile()!"
|
|
323
|
+
[aspectRatio]="1"
|
|
324
|
+
[roundCropper]="true"
|
|
325
|
+
[i18nNamespace]="config().i18nNamespace"
|
|
326
|
+
(cropComplete)="onCropComplete($event)"
|
|
327
|
+
(cancel)="onCropCancel()"
|
|
328
|
+
(loadFailed)="onCropLoadFailed()"
|
|
329
|
+
/>
|
|
330
|
+
}
|
|
331
|
+
</ng-template>
|
|
332
|
+
</ion-modal>
|
|
333
|
+
</div>
|
|
334
|
+
`, styles: [".avatar-upload{--avatar-size: 100px;--edit-button-size: 32px;--edit-button-offset: 4px;display:inline-block}.avatar-container{position:relative;width:var(--avatar-size);height:var(--avatar-size);border-radius:50%;overflow:visible}.avatar-image{width:100%;height:100%;border-radius:50%;object-fit:cover;background-color:var(--ion-color-light)}.avatar-initials{width:100%;height:100%;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:calc(var(--avatar-size) * .4);font-weight:600;color:#fff;text-transform:uppercase;-webkit-user-select:none;user-select:none}.edit-button{position:absolute;bottom:var(--edit-button-offset);right:var(--edit-button-offset);width:var(--edit-button-size);height:var(--edit-button-size);border-radius:50%;border:2px solid white;background:var(--ion-color-primary);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:transform .2s ease,background-color .2s ease;box-shadow:0 2px 8px #00000026}.edit-button ion-icon{font-size:calc(var(--edit-button-size) * .5)}.edit-button:hover{transform:scale(1.1);background:var(--ion-color-primary-shade)}.edit-button:active{transform:scale(.95)}.edit-button:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%;background:#00000080;display:flex;align-items:center;justify-content:center}.loading-overlay ion-spinner{--color: white;width:calc(var(--avatar-size) * .4);height:calc(var(--avatar-size) * .4)}.avatar-upload--loading .edit-button{display:none}.avatar-upload--loading .avatar-image,.avatar-upload--loading .avatar-initials{filter:brightness(.7)}@container (max-width: 60px){.edit-button{--edit-button-size: 24px;--edit-button-offset: 0}}\n"] }]
|
|
335
|
+
}], propDecorators: { fileInput: [{
|
|
336
|
+
type: ViewChild,
|
|
337
|
+
args: ['fileInput']
|
|
338
|
+
}], uploaded: [{
|
|
339
|
+
type: Output
|
|
340
|
+
}], error: [{
|
|
341
|
+
type: Output
|
|
342
|
+
}], uploadStart: [{
|
|
343
|
+
type: Output
|
|
344
|
+
}] } });
|
|
345
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXZhdGFyLXVwbG9hZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvb3JnYW5pc21zL2F2YXRhci11cGxvYWQvYXZhdGFyLXVwbG9hZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFDTCxTQUFTLEVBQ1QsUUFBUSxFQUVSLFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUNMLE1BQU0sRUFDTixNQUFNLEVBQ04sU0FBUyxHQUNWLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDcEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdEMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDckQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFDTCxzQkFBc0IsR0FJdkIsTUFBTSxTQUFTLENBQUM7O0FBRWpCLFFBQVEsQ0FBQyxFQUFFLGFBQWEsRUFBRSxDQUFDLENBQUM7QUFFNUI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzQkc7QUFtRkgsTUFBTSxPQUFPLHFCQUFxQjtJQWxGbEM7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QyxDQUFDO1FBQzFCLENBQUM7SUFDSCxDQUFDO0lBRUQsdUJBQXVCO0lBQ2YsU0FBUyxDQUNmLElBQStCLEVBQy9CLE9BQWUsRUFDZixhQUF1QjtRQUV2QixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsYUFBYSxFQUFFLENBQUMsQ0FBQztJQUNwRCxDQUFDOytHQXBMVSxxQkFBcUI7bUdBQXJCLHFCQUFxQix3WUE5RXRCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyRVQsODBEQTVFUyxZQUFZLCtCQUFFLE9BQU8sMkpBQUUsVUFBVSx5R0FBRSxRQUFRLHNEQUFFLGtCQUFrQjs7NEZBK0U5RCxxQkFBcUI7a0JBbEZqQyxTQUFTOytCQUNFLG1CQUFtQixjQUNqQixJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsa0JBQWtCLENBQUMsWUFDaEU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJFVDs4QkFTdUIsU0FBUztzQkFBaEMsU0FBUzt1QkFBQyxXQUFXO2dCQU1aLFFBQVE7c0JBQWpCLE1BQU07Z0JBR0csS0FBSztzQkFBZCxNQUFNO2dCQUdHLFdBQVc7c0JBQXBCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBjb21wdXRlZCxcbiAgRWxlbWVudFJlZixcbiAgRXZlbnRFbWl0dGVyLFxuICBpbmplY3QsXG4gIGlucHV0LFxuICBPdXRwdXQsXG4gIHNpZ25hbCxcbiAgVmlld0NoaWxkLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElvbkljb24sIElvbk1vZGFsLCBJb25TcGlubmVyIH0gZnJvbSAnQGlvbmljL2FuZ3VsYXIvc3RhbmRhbG9uZSc7XG5pbXBvcnQgeyBhZGRJY29ucyB9IGZyb20gJ2lvbmljb25zJztcbmltcG9ydCB7IGNhbWVyYU91dGxpbmUgfSBmcm9tICdpb25pY29ucy9pY29ucyc7XG5pbXBvcnQgeyBmaXJzdFZhbHVlRnJvbSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9zZXJ2aWNlcy9hdXRoJztcbmltcG9ydCB7IFN0b3JhZ2VTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvZmlyZWJhc2UnO1xuaW1wb3J0IHsgSTE4blNlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9zZXJ2aWNlcy9pMThuJztcbmltcG9ydCB7IEltYWdlU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2ltYWdlJztcbmltcG9ydCB7IEltYWdlQ3JvcENvbXBvbmVudCB9IGZyb20gJy4uLy4uL21vbGVjdWxlcy9pbWFnZS1jcm9wJztcbmltcG9ydCB7XG4gIEFWQVRBUl9VUExPQURfREVGQVVMVFMsXG4gIEF2YXRhclVwbG9hZEVycm9yLFxuICBBdmF0YXJVcGxvYWRNZXRhZGF0YSxcbiAgQXZhdGFyVXBsb2FkUmVzdWx0LFxufSBmcm9tICcuL3R5cGVzJztcblxuYWRkSWNvbnMoeyBjYW1lcmFPdXRsaW5lIH0pO1xuXG4vKipcbiAqIEF2YXRhclVwbG9hZENvbXBvbmVudFxuICpcbiAqIEEgY29tcGxldGUgYXZhdGFyIHVwbG9hZCBzb2x1dGlvbiB3aXRoOlxuICogLSBJbWFnZSBzZWxlY3Rpb24gZnJvbSBkZXZpY2VcbiAqIC0gQ3JvcCBtb2RhbCB3aXRoIHJvdW5kIHByZXZpZXdcbiAqIC0gQXV0b21hdGljIGNvbXByZXNzaW9uIGFuZCB0aHVtYm5haWwgZ2VuZXJhdGlvblxuICogLSBVcGxvYWQgdG8gRmlyZWJhc2UgU3RvcmFnZVxuICogLSBCYWNrZW5kIHN5bmMgdmlhIEF1dGhTZXJ2aWNlXG4gKlxuICogQGV4YW1wbGUgQmFzaWMgdXNhZ2VcbiAqIGBgYGh0bWxcbiAqIDx2YWwtYXZhdGFyLXVwbG9hZFxuICogICBbcHJvcHNdPVwie1xuICogICAgIGN1cnJlbnRVcmw6IHVzZXIoKT8uYXZhdGFyVXJsLFxuICogICAgIGluaXRpYWxzOiAnSkQnLFxuICogICAgIHNpemU6IDEyMFxuICogICB9XCJcbiAqICAgKHVwbG9hZGVkKT1cIm9uQXZhdGFyVXBsb2FkZWQoJGV2ZW50KVwiXG4gKiAgIChlcnJvcik9XCJvbkVycm9yKCRldmVudClcIlxuICogLz5cbiAqIGBgYFxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd2YWwtYXZhdGFyLXVwbG9hZCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGUsIElvbkljb24sIElvblNwaW5uZXIsIElvbk1vZGFsLCBJbWFnZUNyb3BDb21wb25lbnRdLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXZcbiAgICAgIGNsYXNzPVwiYXZhdGFyLXVwbG9hZFwiXG4gICAgICBbc3R5bGUuLS1hdmF0YXItc2l6ZS5weF09XCJjb25maWcoKS5zaXplXCJcbiAgICAgIFtjbGFzcy5hdmF0YXItdXBsb2FkLS1sb2FkaW5nXT1cImxvYWRpbmcoKVwiXG4gICAgPlxuICAgICAgPGRpdiBjbGFzcz1cImF2YXRhci1jb250YWluZXJcIj5cbiAgICAgICAgPCEtLSBBdmF0YXIgSW1hZ2Ugb3IgSW5pdGlhbHMgLS0+XG4gICAgICAgIEBpZiAoZGlzcGxheVVybCgpKSB7XG4gICAgICAgICAgPGltZ1xuICAgICAgICAgICAgY2xhc3M9XCJhdmF0YXItaW1hZ2VcIlxuICAgICAgICAgICAgW3NyY109XCJkaXNwbGF5VXJsKClcIlxuICAgICAgICAgICAgYWx0PVwiQXZhdGFyXCJcbiAgICAgICAgICAgIChlcnJvcik9XCJvbkltYWdlRXJyb3IoKVwiXG4gICAgICAgICAgLz5cbiAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgPGRpdlxuICAgICAgICAgICAgY2xhc3M9XCJhdmF0YXItaW5pdGlhbHNcIlxuICAgICAgICAgICAgW3N0eWxlLmJhY2tncm91bmQtY29sb3JdPVwiY29uZmlnKCkuYmFja2dyb3VuZENvbG9yXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICB7eyBjb25maWcoKS5pbml0aWFscyB8fCAnPycgfX1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gRWRpdCBCdXR0b24gLS0+XG4gICAgICAgIEBpZiAoY29uZmlnKCkuZWRpdGFibGUgJiYgIWxvYWRpbmcoKSkge1xuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIGNsYXNzPVwiZWRpdC1idXR0b25cIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAoY2xpY2spPVwib3BlbkZpbGVQaWNrZXIoKVwiXG4gICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cImVkaXRCdXR0b25MYWJlbCgpXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cImNhbWVyYS1vdXRsaW5lXCI+PC9pb24taWNvbj5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gTG9hZGluZyBPdmVybGF5IC0tPlxuICAgICAgICBAaWYgKGxvYWRpbmcoKSkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJsb2FkaW5nLW92ZXJsYXlcIj5cbiAgICAgICAgICAgIDxpb24tc3Bpbm5lciBuYW1lPVwiY3Jlc2NlbnRcIj48L2lvbi1zcGlubmVyPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBIaWRkZW4gRmlsZSBJbnB1dCAtLT5cbiAgICAgIDxpbnB1dFxuICAgICAgICAjZmlsZUlucHV0XG4gICAgICAgIHR5cGU9XCJmaWxlXCJcbiAgICAgICAgYWNjZXB0PVwiaW1hZ2UvanBlZyxpbWFnZS9wbmcsaW1hZ2Uvd2VicFwiXG4gICAgICAgIChjaGFuZ2UpPVwib25GaWxlU2VsZWN0ZWQoJGV2ZW50KVwiXG4gICAgICAgIGhpZGRlblxuICAgICAgLz5cblxuICAgICAgPCEtLSBDcm9wIE1vZGFsIC0tPlxuICAgICAgPGlvbi1tb2RhbFxuICAgICAgICBbaXNPcGVuXT1cInNob3dDcm9wTW9kYWwoKVwiXG4gICAgICAgIChkaWREaXNtaXNzKT1cIm9uQ3JvcENhbmNlbCgpXCJcbiAgICAgICAgW2JyZWFrcG9pbnRzXT1cIlswLCAxXVwiXG4gICAgICAgIFtpbml0aWFsQnJlYWtwb2ludF09XCIxXCJcbiAgICAgID5cbiAgICAgICAgPG5nLXRlbXBsYXRlPlxuICAgICAgICAgIEBpZiAoc2VsZWN0ZWRGaWxlKCkpIHtcbiAgICAgICAgICAgIDx2YWwtaW1hZ2UtY3JvcFxuICAgICAgICAgICAgICBbaW1hZ2VdPVwic2VsZWN0ZWRGaWxlKCkhXCJcbiAgICAgICAgICAgICAgW2FzcGVjdFJhdGlvXT1cIjFcIlxuICAgICAgICAgICAgICBbcm91bmRDcm9wcGVyXT1cInRydWVcIlxuICAgICAgICAgICAgICBbaTE4bk5hbWVzcGFjZV09XCJjb25maWcoKS5pMThuTmFtZXNwYWNlXCJcbiAgICAgICAgICAgICAgKGNyb3BDb21wbGV0ZSk9XCJvbkNyb3BDb21wbGV0ZSgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgKGNhbmNlbCk9XCJvbkNyb3BDYW5jZWwoKVwiXG4gICAgICAgICAgICAgIChsb2FkRmFpbGVkKT1cIm9uQ3JvcExvYWRGYWlsZWQoKVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgIH1cbiAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgIDwvaW9uLW1vZGFsPlxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZVVybHM6IFsnLi9hdmF0YXItdXBsb2FkLmNvbXBvbmVudC5zY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIEF2YXRhclVwbG9hZENvbXBvbmVudCB7XG4gIHByaXZhdGUgaW1hZ2VTZXJ2aWNlID0gaW5qZWN0KEltYWdlU2VydmljZSk7XG4gIHByaXZhdGUgc3RvcmFnZVNlcnZpY2UgPSBpbmplY3QoU3RvcmFnZVNlcnZpY2UpO1xuICBwcml2YXRlIGF1dGhTZXJ2aWNlID0gaW5qZWN0KEF1dGhTZXJ2aWNlKTtcbiAgcHJpdmF0ZSBpMThuID0gaW5qZWN0KEkxOG5TZXJ2aWNlKTtcblxuICBAVmlld0NoaWxkKCdmaWxlSW5wdXQnKSBmaWxlSW5wdXQhOiBFbGVtZW50UmVmPEhUTUxJbnB1dEVsZW1lbnQ+O1xuXG4gIC8qKiBDb21wb25lbnQgY29uZmlndXJhdGlvbiAqL1xuICByZWFkb25seSBwcm9wcyA9IGlucHV0PEF2YXRhclVwbG9hZE1ldGFkYXRhPih7fSk7XG5cbiAgLyoqIEVtaXR0ZWQgYWZ0ZXIgc3VjY2Vzc2Z1bCB1cGxvYWQgYW5kIGJhY2tlbmQgc3luYyAqL1xuICBAT3V0cHV0KCkgdXBsb2FkZWQgPSBuZXcgRXZlbnRFbWl0dGVyPEF2YXRhclVwbG9hZFJlc3VsdD4oKTtcblxuICAvKiogRW1pdHRlZCBvbiBhbnkgZXJyb3IgZHVyaW5nIHRoZSBwcm9jZXNzICovXG4gIEBPdXRwdXQoKSBlcnJvciA9IG5ldyBFdmVudEVtaXR0ZXI8QXZhdGFyVXBsb2FkRXJyb3I+KCk7XG5cbiAgLyoqIEVtaXR0ZWQgd2hlbiB1cGxvYWQgc3RhcnRzICovXG4gIEBPdXRwdXQoKSB1cGxvYWRTdGFydCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICAvLyBJbnRlcm5hbCBzdGF0ZVxuICBwcm90ZWN0ZWQgbG9hZGluZyA9IHNpZ25hbChmYWxzZSk7XG4gIHByb3RlY3RlZCBzaG93Q3JvcE1vZGFsID0gc2lnbmFsKGZhbHNlKTtcbiAgcHJvdGVjdGVkIHNlbGVjdGVkRmlsZSA9IHNpZ25hbDxGaWxlIHwgbnVsbD4obnVsbCk7XG4gIHByb3RlY3RlZCBwcmV2aWV3VXJsID0gc2lnbmFsPHN0cmluZyB8IG51bGw+KG51bGwpO1xuICBwcm90ZWN0ZWQgaW1hZ2VMb2FkRXJyb3IgPSBzaWduYWwoZmFsc2UpO1xuXG4gIC8qKiBNZXJnZWQgY29uZmlnIHdpdGggZGVmYXVsdHMgKi9cbiAgcHJvdGVjdGVkIGNvbmZpZyA9IGNvbXB1dGVkKCgpID0+ICh7XG4gICAgLi4uQVZBVEFSX1VQTE9BRF9ERUZBVUxUUyxcbiAgICAuLi50aGlzLnByb3BzKCksXG4gIH0pKTtcblxuICAvKiogVVJMIHRvIGRpc3BsYXkgKHByZXZpZXcgdGFrZXMgcHJpb3JpdHkgb3ZlciBjdXJyZW50KSAqL1xuICBwcm90ZWN0ZWQgZGlzcGxheVVybCA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBpZiAodGhpcy5pbWFnZUxvYWRFcnJvcigpKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gdGhpcy5wcmV2aWV3VXJsKCkgfHwgdGhpcy5jb25maWcoKS5jdXJyZW50VXJsIHx8IG51bGw7XG4gIH0pO1xuXG4gIC8qKiBBcmlhIGxhYmVsIGZvciBlZGl0IGJ1dHRvbiAqL1xuICBwcm90ZWN0ZWQgZWRpdEJ1dHRvbkxhYmVsID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIHRoaXMuaTE4bi5sYW5nKCk7XG4gICAgcmV0dXJuIHRoaXMuaTE4bi50KCdjaGFuZ2VQaG90bycsIHRoaXMuY29uZmlnKCkuaTE4bk5hbWVzcGFjZSkgfHwgJ0NhbWJpYXIgZm90byc7XG4gIH0pO1xuXG4gIC8qKiBPcGVuIGZpbGUgcGlja2VyIGRpYWxvZyAqL1xuICBvcGVuRmlsZVBpY2tlcigpOiB2b2lkIHtcbiAgICB0aGlzLmZpbGVJbnB1dC5uYXRpdmVFbGVtZW50LmNsaWNrKCk7XG4gIH1cblxuICAvKiogSGFuZGxlIGZpbGUgc2VsZWN0aW9uICovXG4gIG9uRmlsZVNlbGVjdGVkKGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGlucHV0ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG4gICAgY29uc3QgZmlsZSA9IGlucHV0LmZpbGVzPy5bMF07XG5cbiAgICBpZiAoIWZpbGUpIHJldHVybjtcblxuICAgIC8vIFJlc2V0IGlucHV0IGZvciBzYW1lIGZpbGUgc2VsZWN0aW9uXG4gICAgaW5wdXQudmFsdWUgPSAnJztcblxuICAgIC8vIFZhbGlkYXRlIGZpbGVcbiAgICBjb25zdCB2YWxpZGF0aW9uID0gdGhpcy5pbWFnZVNlcnZpY2UudmFsaWRhdGUoZmlsZSwge1xuICAgICAgbWF4U2l6ZTogdGhpcy5jb25maWcoKS5tYXhGaWxlU2l6ZSxcbiAgICAgIGFsbG93ZWRUeXBlczogWydpbWFnZS9qcGVnJywgJ2ltYWdlL3BuZycsICdpbWFnZS93ZWJwJ10sXG4gICAgfSk7XG5cbiAgICBpZiAoIXZhbGlkYXRpb24udmFsaWQpIHtcbiAgICAgIHRoaXMuZW1pdEVycm9yKHZhbGlkYXRpb24uZXJyb3IgYXMgQXZhdGFyVXBsb2FkRXJyb3JbJ3R5cGUnXSwgdmFsaWRhdGlvbi5tZXNzYWdlISk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gT3BlbiBjcm9wIG1vZGFsXG4gICAgdGhpcy5zZWxlY3RlZEZpbGUuc2V0KGZpbGUpO1xuICAgIHRoaXMuc2hvd0Nyb3BNb2RhbC5zZXQodHJ1ZSk7XG4gIH1cblxuICAvKiogSGFuZGxlIGNyb3AgY29tcGxldGlvbiAqL1xuICBhc3luYyBvbkNyb3BDb21wbGV0ZShjcm9wcGVkQmxvYjogQmxvYik6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuc2hvd0Nyb3BNb2RhbC5zZXQoZmFsc2UpO1xuICAgIHRoaXMuc2VsZWN0ZWRGaWxlLnNldChudWxsKTtcblxuICAgIGF3YWl0IHRoaXMucHJvY2Vzc0FuZFVwbG9hZChjcm9wcGVkQmxvYik7XG4gIH1cblxuICAvKiogSGFuZGxlIGNyb3AgY2FuY2VsICovXG4gIG9uQ3JvcENhbmNlbCgpOiB2b2lkIHtcbiAgICB0aGlzLnNob3dDcm9wTW9kYWwuc2V0KGZhbHNlKTtcbiAgICB0aGlzLnNlbGVjdGVkRmlsZS5zZXQobnVsbCk7XG4gIH1cblxuICAvKiogSGFuZGxlIGNyb3AgbG9hZCBmYWlsdXJlICovXG4gIG9uQ3JvcExvYWRGYWlsZWQoKTogdm9pZCB7XG4gICAgdGhpcy5zaG93Q3JvcE1vZGFsLnNldChmYWxzZSk7XG4gICAgdGhpcy5zZWxlY3RlZEZpbGUuc2V0KG51bGwpO1xuICAgIHRoaXMuZW1pdEVycm9yKCdpbnZhbGlkVHlwZScsIHRoaXMuaTE4bi50KCdsb2FkRmFpbGVkJywgdGhpcy5jb25maWcoKS5pMThuTmFtZXNwYWNlKSB8fCAnTm8gc2UgcHVkbyBjYXJnYXIgbGEgaW1hZ2VuJyk7XG4gIH1cblxuICAvKiogSGFuZGxlIGltYWdlIGxvYWQgZXJyb3IgKi9cbiAgb25JbWFnZUVycm9yKCk6IHZvaWQge1xuICAgIHRoaXMuaW1hZ2VMb2FkRXJyb3Iuc2V0KHRydWUpO1xuICB9XG5cbiAgLyoqIFByb2Nlc3MgY3JvcHBlZCBpbWFnZSBhbmQgdXBsb2FkICovXG4gIHByaXZhdGUgYXN5bmMgcHJvY2Vzc0FuZFVwbG9hZChjcm9wcGVkQmxvYjogQmxvYik6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMubG9hZGluZy5zZXQodHJ1ZSk7XG4gICAgdGhpcy51cGxvYWRTdGFydC5lbWl0KCk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgY29uZmlnID0gdGhpcy5jb25maWcoKTtcblxuICAgICAgLy8gMS4gQ29tcHJlc3MgaW1hZ2VcbiAgICAgIGNvbnN0IGNvbXByZXNzZWQgPSBhd2FpdCB0aGlzLmltYWdlU2VydmljZS5jb21wcmVzcyhjcm9wcGVkQmxvYiwge1xuICAgICAgICBtYXhXaWR0aDogY29uZmlnLm1heFdpZHRoLFxuICAgICAgICBtYXhIZWlnaHQ6IGNvbmZpZy5tYXhXaWR0aCxcbiAgICAgICAgcXVhbGl0eTogY29uZmlnLmNvbXByZXNzUXVhbGl0eSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyAyLiBHZW5lcmF0ZSB0aHVtYm5haWxcbiAgICAgIGNvbnN0IHRodW1ibmFpbCA9IGF3YWl0IHRoaXMuaW1hZ2VTZXJ2aWNlLnRodW1ibmFpbChcbiAgICAgICAgY29tcHJlc3NlZC5ibG9iLFxuICAgICAgICBjb25maWcudGh1bWJuYWlsU2l6ZVxuICAgICAgKTtcblxuICAgICAgLy8gMy4gU2V0IHByZXZpZXcgaW1tZWRpYXRlbHlcbiAgICAgIHRoaXMucHJldmlld1VybC5zZXQoY29tcHJlc3NlZC5kYXRhVXJsKTtcbiAgICAgIHRoaXMuaW1hZ2VMb2FkRXJyb3Iuc2V0KGZhbHNlKTtcblxuICAgICAgLy8gNC4gR2V0IHVzZXIgSUQgZm9yIHN0b3JhZ2UgcGF0aFxuICAgICAgY29uc3QgdXNlcklkID0gdGhpcy5hdXRoU2VydmljZS51c2VyKCk/LnVzZXJJZDtcbiAgICAgIGlmICghdXNlcklkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVXNlciBub3QgYXV0aGVudGljYXRlZCcpO1xuICAgICAgfVxuXG4gICAgICAvLyA1LiBVcGxvYWQgdG8gRmlyZWJhc2UgU3RvcmFnZVxuICAgICAgY29uc3QgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IGF2YXRhclBhdGggPSBgJHtjb25maWcuc3RvcmFnZVBhdGh9LyR7dXNlcklkfS9hdmF0YXJfJHt0aW1lc3RhbXB9LmpwZ2A7XG4gICAgICBjb25zdCB0aHVtYlBhdGggPSBgJHtjb25maWcuc3RvcmFnZVBhdGh9LyR7dXNlcklkfS90aHVtYl8ke3RpbWVzdGFtcH0uanBnYDtcblxuICAgICAgY29uc3QgW2F2YXRhclJlc3VsdCwgdGh1bWJSZXN1bHRdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICB0aGlzLnN0b3JhZ2VTZXJ2aWNlLnVwbG9hZEFuZEdldFVybChhdmF0YXJQYXRoLCBjb21wcmVzc2VkLmJsb2IpLFxuICAgICAgICB0aGlzLnN0b3JhZ2VTZXJ2aWNlLnVwbG9hZEFuZEdldFVybCh0aHVtYlBhdGgsIHRodW1ibmFpbC5ibG9iKSxcbiAgICAgIF0pO1xuXG4gICAgICAvLyA2LiBVcGRhdGUgYmFja2VuZFxuICAgICAgYXdhaXQgZmlyc3RWYWx1ZUZyb20oXG4gICAgICAgIHRoaXMuYXV0aFNlcnZpY2UudXBkYXRlQXZhdGFyKHtcbiAgICAgICAgICBhdmF0YXJVcmw6IGF2YXRhclJlc3VsdC5kb3dubG9hZFVybCxcbiAgICAgICAgICBhdmF0YXJUaHVtYm5haWw6IHRodW1iUmVzdWx0LmRvd25sb2FkVXJsLFxuICAgICAgICB9KVxuICAgICAgKTtcblxuICAgICAgLy8gNy4gRW1pdCBzdWNjZXNzXG4gICAgICBjb25zdCByZXN1bHQ6IEF2YXRhclVwbG9hZFJlc3VsdCA9IHtcbiAgICAgICAgYXZhdGFyVXJsOiBhdmF0YXJSZXN1bHQuZG93bmxvYWRVcmwsXG4gICAgICAgIHRodW1ibmFpbFVybDogdGh1bWJSZXN1bHQuZG93bmxvYWRVcmwsXG4gICAgICB9O1xuXG4gICAgICB0aGlzLnVwbG9hZGVkLmVtaXQocmVzdWx0KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIFJldmVydCBwcmV2aWV3IG9uIGVycm9yXG4gICAgICB0aGlzLnByZXZpZXdVcmwuc2V0KG51bGwpO1xuXG4gICAgICBjb25zdCBtZXNzYWdlID1cbiAgICAgICAgZXJyIGluc3RhbmNlb2YgRXJyb3JcbiAgICAgICAgICA/IGVyci5tZXNzYWdlXG4gICAgICAgICAgOiB0aGlzLmkxOG4udCgndXBsb2FkRXJyb3InLCB0aGlzLmNvbmZpZygpLmkxOG5OYW1lc3BhY2UpIHx8ICdFcnJvciBhbCBzdWJpciBsYSBpbWFnZW4nO1xuXG4gICAgICB0aGlzLmVtaXRFcnJvcigndXBsb2FkRmFpbGVkJywgbWVzc2FnZSwgZXJyKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5sb2FkaW5nLnNldChmYWxzZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIEVtaXQgZXJyb3IgZXZlbnQgKi9cbiAgcHJpdmF0ZSBlbWl0RXJyb3IoXG4gICAgdHlwZTogQXZhdGFyVXBsb2FkRXJyb3JbJ3R5cGUnXSxcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgb3JpZ2luYWxFcnJvcj86IHVua25vd25cbiAgKTogdm9pZCB7XG4gICAgdGhpcy5lcnJvci5lbWl0KHsgdHlwZSwgbWVzc2FnZSwgb3JpZ2luYWxFcnJvciB9KTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default values
|
|
3
|
+
*/
|
|
4
|
+
export const AVATAR_UPLOAD_DEFAULTS = {
|
|
5
|
+
size: 100,
|
|
6
|
+
editable: true,
|
|
7
|
+
storagePath: 'avatars',
|
|
8
|
+
i18nNamespace: 'AvatarUpload',
|
|
9
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
10
|
+
compressQuality: 0.8,
|
|
11
|
+
maxWidth: 800,
|
|
12
|
+
thumbnailSize: 150,
|
|
13
|
+
backgroundColor: '#6366f1', // Indigo
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvb3JnYW5pc21zL2F2YXRhci11cGxvYWQvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBeURBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUc7SUFDcEMsSUFBSSxFQUFFLEdBQUc7SUFDVCxRQUFRLEVBQUUsSUFBSTtJQUNkLFdBQVcsRUFBRSxTQUFTO0lBQ3RCLGFBQWEsRUFBRSxjQUFjO0lBQzdCLFdBQVcsRUFBRSxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksRUFBRSxPQUFPO0lBQ3RDLGVBQWUsRUFBRSxHQUFHO0lBQ3BCLFFBQVEsRUFBRSxHQUFHO0lBQ2IsYUFBYSxFQUFFLEdBQUc7SUFDbEIsZUFBZSxFQUFFLFNBQVMsRUFBRSxTQUFTO0NBQ3RDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIEF2YXRhclVwbG9hZENvbXBvbmVudFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEF2YXRhclVwbG9hZE1ldGFkYXRhIHtcbiAgLyoqIEN1cnJlbnQgYXZhdGFyIFVSTCAqL1xuICBjdXJyZW50VXJsPzogc3RyaW5nO1xuICAvKiogSW5pdGlhbHMgdG8gc2hvdyB3aGVuIG5vIGF2YXRhciAoZS5nLiwgXCJKRFwiIGZvciBKb2huIERvZSkgKi9cbiAgaW5pdGlhbHM/OiBzdHJpbmc7XG4gIC8qKiBCYWNrZ3JvdW5kIGNvbG9yIGZvciBpbml0aWFscyBhdmF0YXIgKi9cbiAgYmFja2dyb3VuZENvbG9yPzogc3RyaW5nO1xuICAvKiogQXZhdGFyIHNpemUgaW4gcGl4ZWxzIChkZWZhdWx0OiAxMDApICovXG4gIHNpemU/OiBudW1iZXI7XG4gIC8qKiBTaG93IGVkaXQgYnV0dG9uIChkZWZhdWx0OiB0cnVlKSAqL1xuICBlZGl0YWJsZT86IGJvb2xlYW47XG4gIC8qKiBTdG9yYWdlIHBhdGggcHJlZml4IHdpdGhvdXQgdXNlcklkIChkZWZhdWx0OiAnYXZhdGFycycpICovXG4gIHN0b3JhZ2VQYXRoPzogc3RyaW5nO1xuICAvKiogaTE4biBuYW1lc3BhY2UgZm9yIGxhYmVscyAoZGVmYXVsdDogJ0F2YXRhclVwbG9hZCcpICovXG4gIGkxOG5OYW1lc3BhY2U/OiBzdHJpbmc7XG4gIC8qKiBNYXggZmlsZSBzaXplIGluIGJ5dGVzIChkZWZhdWx0OiAxME1CKSAqL1xuICBtYXhGaWxlU2l6ZT86IG51bWJlcjtcbiAgLyoqIFF1YWxpdHkgZm9yIGNvbXByZXNzZWQgaW1hZ2UgMC0xIChkZWZhdWx0OiAwLjgpICovXG4gIGNvbXByZXNzUXVhbGl0eT86IG51bWJlcjtcbiAgLyoqIE1heCB3aWR0aCBmb3IgYXZhdGFyIChkZWZhdWx0OiA4MDApICovXG4gIG1heFdpZHRoPzogbnVtYmVyO1xuICAvKiogVGh1bWJuYWlsIHNpemUgKGRlZmF1bHQ6IDE1MCkgKi9cbiAgdGh1bWJuYWlsU2l6ZT86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBSZXN1bHQgZW1pdHRlZCBhZnRlciBzdWNjZXNzZnVsIHVwbG9hZFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEF2YXRhclVwbG9hZFJlc3VsdCB7XG4gIC8qKiBGdWxsLXNpemUgYXZhdGFyIFVSTCAqL1xuICBhdmF0YXJVcmw6IHN0cmluZztcbiAgLyoqIFRodW1ibmFpbCBVUkwgKi9cbiAgdGh1bWJuYWlsVXJsOiBzdHJpbmc7XG59XG5cbi8qKlxuICogRXJyb3IgdHlwZXMgdGhhdCBjYW4gb2NjdXIgZHVyaW5nIHVwbG9hZFxuICovXG5leHBvcnQgdHlwZSBBdmF0YXJVcGxvYWRFcnJvclR5cGUgPVxuICB8ICdpbnZhbGlkVHlwZSdcbiAgfCAnZmlsZVRvb0xhcmdlJ1xuICB8ICd1cGxvYWRGYWlsZWQnXG4gIHwgJ2JhY2tlbmRGYWlsZWQnXG4gIHwgJ2NhbmNlbGxlZCc7XG5cbi8qKlxuICogRXJyb3Igb2JqZWN0IGVtaXR0ZWQgb24gZmFpbHVyZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEF2YXRhclVwbG9hZEVycm9yIHtcbiAgdHlwZTogQXZhdGFyVXBsb2FkRXJyb3JUeXBlO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIG9yaWdpbmFsRXJyb3I/OiB1bmtub3duO1xufVxuXG4vKipcbiAqIERlZmF1bHQgdmFsdWVzXG4gKi9cbmV4cG9ydCBjb25zdCBBVkFUQVJfVVBMT0FEX0RFRkFVTFRTID0ge1xuICBzaXplOiAxMDAsXG4gIGVkaXRhYmxlOiB0cnVlLFxuICBzdG9yYWdlUGF0aDogJ2F2YXRhcnMnLFxuICBpMThuTmFtZXNwYWNlOiAnQXZhdGFyVXBsb2FkJyxcbiAgbWF4RmlsZVNpemU6IDEwICogMTAyNCAqIDEwMjQsIC8vIDEwTUJcbiAgY29tcHJlc3NRdWFsaXR5OiAwLjgsXG4gIG1heFdpZHRoOiA4MDAsXG4gIHRodW1ibmFpbFNpemU6IDE1MCxcbiAgYmFja2dyb3VuZENvbG9yOiAnIzYzNjZmMScsIC8vIEluZGlnb1xufTtcbiJdfQ==
|