@dataclouder/ngx-cloud-storage 0.0.30 → 0.0.34

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.
@@ -1,30 +1,38 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injectable, input, output, ViewChild, Component, Pipe, ChangeDetectorRef, Input, signal, computed } from '@angular/core';
2
+ import { inject, Injectable, input, output, ViewChild, Component, Pipe, ChangeDetectorRef, Input, signal, InjectionToken, EventEmitter, Output, computed } from '@angular/core';
3
3
  import { ImageCropperComponent } from 'ngx-image-cropper';
4
4
  import * as i1 from '@angular/forms';
5
5
  import { FormsModule } from '@angular/forms';
6
6
  import { AngularFireStorage } from '@angular/fire/compat/storage';
7
7
  import { getStorage, ref, listAll, deleteObject, getDownloadURL, Storage } from '@angular/fire/storage';
8
- import { lastValueFrom, BehaviorSubject } from 'rxjs';
9
- import * as i5$1 from 'primeng/dialog';
8
+ import { lastValueFrom, BehaviorSubject, firstValueFrom } from 'rxjs';
9
+ import * as i4 from 'primeng/dialog';
10
10
  import { DialogModule } from 'primeng/dialog';
11
- import * as i4 from 'primeng/tooltip';
11
+ import * as i5 from 'primeng/tooltip';
12
12
  import { TooltipModule } from 'primeng/tooltip';
13
13
  import * as i2 from 'primeng/button';
14
14
  import { ButtonModule } from 'primeng/button';
15
- import * as i5 from 'primeng/message';
15
+ import * as i6 from 'primeng/message';
16
16
  import { MessageModule } from 'primeng/message';
17
- import * as i6 from 'primeng/select';
17
+ import * as i7 from 'primeng/select';
18
18
  import { SelectModule } from 'primeng/select';
19
- import * as i7 from 'primeng/inputtext';
19
+ import * as i8 from 'primeng/inputtext';
20
20
  import { InputTextModule } from 'primeng/inputtext';
21
- import { MoodStateOptions, CharacterEventActions } from '@dataclouder/ngx-core';
22
- import { FieldsetModule } from 'primeng/fieldset';
21
+ import { MoodStateOptions, CharacterEventActions, APP_CONFIG } from '@dataclouder/ngx-core';
23
22
  import * as i1$1 from '@angular/platform-browser';
24
- import { DynamicDialogRef, DynamicDialogConfig, DialogService, DynamicDialogModule } from 'primeng/dynamicdialog';
25
23
  import * as i3 from 'primeng/api';
24
+ import * as i1$2 from '@angular/common';
26
25
  import { AsyncPipe, CommonModule } from '@angular/common';
27
- import * as i3$1 from 'primeng/tag';
26
+ import { HttpClient } from '@angular/common/http';
27
+ import * as i2$1 from 'primeng/fileupload';
28
+ import { FileUploadModule } from 'primeng/fileupload';
29
+ import * as i3$1 from 'primeng/toast';
30
+ import { ToastModule } from 'primeng/toast';
31
+ import * as i4$1 from 'primeng/progressbar';
32
+ import { ProgressBarModule } from 'primeng/progressbar';
33
+ import * as i5$1 from 'primeng/badge';
34
+ import { BadgeModule } from 'primeng/badge';
35
+ import * as i3$2 from 'primeng/tag';
28
36
  import { TagModule } from 'primeng/tag';
29
37
 
30
38
  const AspectRatioOptions = [
@@ -71,6 +79,7 @@ const AspectRatioOptions = [
71
79
  low: { w: 360, h: 640 },
72
80
  sd: { w: 450, h: 800 },
73
81
  sdLarge: { w: 540, h: 960 },
82
+ semiHd: { w: 630, h: 1120 },
74
83
  hd: { w: 720, h: 1280 },
75
84
  fullhd: { w: 1080, h: 1920 },
76
85
  '4k': { w: 2160, h: 3840 },
@@ -378,10 +387,10 @@ class MultiImagesStorageService {
378
387
  return null;
379
388
  }
380
389
  }
381
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: MultiImagesStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
382
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: MultiImagesStorageService, providedIn: 'root' }); }
390
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MultiImagesStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
391
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MultiImagesStorageService, providedIn: 'root' }); }
383
392
  }
384
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: MultiImagesStorageService, decorators: [{
393
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MultiImagesStorageService, decorators: [{
385
394
  type: Injectable,
386
395
  args: [{
387
396
  providedIn: 'root',
@@ -450,13 +459,13 @@ class CropperComponent {
450
459
  closeModal() {
451
460
  this.showModal = false;
452
461
  }
453
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CropperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
454
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: CropperComponent, isStandalone: true, selector: "app-cropper", inputs: { imageSettings: { classPropertyName: "imageSettings", publicName: "imageSettings", isSignal: true, isRequired: false, transformFunction: null }, ratioType: { classPropertyName: "ratioType", publicName: "ratioType", isSignal: true, isRequired: false, transformFunction: null }, resolutions: { classPropertyName: "resolutions", publicName: "resolutions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageUploaded: "imageUploaded", onImageCropped: "onImageCropped", onFileSelected: "onFileSelected" }, viewQueries: [{ propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true }], ngImport: i0, template: "<div> path: {{ storagePath }} </div>\n\n<div class=\"options\">\n @if (!isUploaded) {\n <div>\n <input type=\"file\" id=\"file-upload\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label for=\"file-upload\" class=\"btn-upload\">Seleccionar archivo</label>\n @if (!fileMetadata) {\n <em>Carga una imagen para comenzar</em>\n }\n </div>\n }\n\n @if (fileMetadata) {\n <span>\n <span style=\"margin: 1px 20px\"> tipo: {{ fileMetadata.type }} </span>\n <span style=\"margin: 1px 20px\"> tama\u00F1o {{ fileMetadata.size }} </span>\n <br />\n <input\n [disabled]=\"imageSettings()?.fileName\"\n style=\"margin: 1px 20px; width: 400px\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\" />\n <button class=\"btn-crop\" (click)=\"closeModal()\"> Recortar y Subir </button>\n </span>\n }\n</div>\n\n@if (fileMetadata && !isUploaded) {\n <div class=\"modal\" [class.show-modal]=\"showModal\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h3>Recortar imagen</h3>\n <button class=\"close-button\" (click)=\"closeModal()\">\u00D7</button>\n </div>\n <div class=\"modal-body\">\n <h1>Hlloa</h1>\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatio\"\n format=\"webp\"\n [resizeToWidth]=\"450\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (imageLoaded)=\"imageLoaded($event)\"\n [autoCrop]=\"false\"></image-cropper>\n <div class=\"modal-footer\">\n <button class=\"btn-crop\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n </div>\n </div>\n </div>\n </div>\n}\n\n@if (croppedImage && !isUploaded) {\n <button [disabled]=\"isLoading\" nbButton status=\"info\"> upload </button>\n}\n", styles: [".options{display:flex}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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"] }] }); }
462
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CropperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
463
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: CropperComponent, isStandalone: true, selector: "app-cropper", inputs: { imageSettings: { classPropertyName: "imageSettings", publicName: "imageSettings", isSignal: true, isRequired: false, transformFunction: null }, ratioType: { classPropertyName: "ratioType", publicName: "ratioType", isSignal: true, isRequired: false, transformFunction: null }, resolutions: { classPropertyName: "resolutions", publicName: "resolutions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageUploaded: "imageUploaded", onImageCropped: "onImageCropped", onFileSelected: "onFileSelected" }, viewQueries: [{ propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true }], ngImport: i0, template: "<div> path: {{ storagePath }} </div>\n\n<div class=\"options\">\n @if (!isUploaded) {\n <div>\n <input type=\"file\" id=\"file-upload\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label for=\"file-upload\" class=\"btn-upload\">Seleccionar archivo</label>\n @if (!fileMetadata) {\n <em>Carga una imagen para comenzar</em>\n }\n </div>\n }\n\n @if (fileMetadata) {\n <span>\n <span style=\"margin: 1px 20px\"> tipo: {{ fileMetadata.type }} </span>\n <span style=\"margin: 1px 20px\"> tama\u00F1o {{ fileMetadata.size }} </span>\n <br />\n <input\n [disabled]=\"imageSettings()?.fileName\"\n style=\"margin: 1px 20px; width: 400px\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\" />\n <button class=\"btn-crop\" (click)=\"closeModal()\"> Recortar y Subir </button>\n </span>\n }\n</div>\n\n@if (fileMetadata && !isUploaded) {\n <div class=\"modal\" [class.show-modal]=\"showModal\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h3>Recortar imagen</h3>\n <button class=\"close-button\" (click)=\"closeModal()\">\u00D7</button>\n </div>\n <div class=\"modal-body\">\n <h1>Hlloa</h1>\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatio\"\n format=\"webp\"\n [resizeToWidth]=\"450\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (imageLoaded)=\"imageLoaded($event)\"\n [autoCrop]=\"false\"></image-cropper>\n <div class=\"modal-footer\">\n <button class=\"btn-crop\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n </div>\n </div>\n </div>\n </div>\n}\n\n@if (croppedImage && !isUploaded) {\n <button [disabled]=\"isLoading\" nbButton status=\"info\"> upload </button>\n}\n", styles: [".options{display:flex}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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"] }] }); }
455
464
  }
456
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CropperComponent, decorators: [{
465
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CropperComponent, decorators: [{
457
466
  type: Component,
458
467
  args: [{ selector: 'app-cropper', standalone: true, imports: [FormsModule, ImageCropperComponent], template: "<div> path: {{ storagePath }} </div>\n\n<div class=\"options\">\n @if (!isUploaded) {\n <div>\n <input type=\"file\" id=\"file-upload\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label for=\"file-upload\" class=\"btn-upload\">Seleccionar archivo</label>\n @if (!fileMetadata) {\n <em>Carga una imagen para comenzar</em>\n }\n </div>\n }\n\n @if (fileMetadata) {\n <span>\n <span style=\"margin: 1px 20px\"> tipo: {{ fileMetadata.type }} </span>\n <span style=\"margin: 1px 20px\"> tama\u00F1o {{ fileMetadata.size }} </span>\n <br />\n <input\n [disabled]=\"imageSettings()?.fileName\"\n style=\"margin: 1px 20px; width: 400px\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\" />\n <button class=\"btn-crop\" (click)=\"closeModal()\"> Recortar y Subir </button>\n </span>\n }\n</div>\n\n@if (fileMetadata && !isUploaded) {\n <div class=\"modal\" [class.show-modal]=\"showModal\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h3>Recortar imagen</h3>\n <button class=\"close-button\" (click)=\"closeModal()\">\u00D7</button>\n </div>\n <div class=\"modal-body\">\n <h1>Hlloa</h1>\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatio\"\n format=\"webp\"\n [resizeToWidth]=\"450\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (imageLoaded)=\"imageLoaded($event)\"\n [autoCrop]=\"false\"></image-cropper>\n <div class=\"modal-footer\">\n <button class=\"btn-crop\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n </div>\n </div>\n </div>\n </div>\n}\n\n@if (croppedImage && !isUploaded) {\n <button [disabled]=\"isLoading\" nbButton status=\"info\"> upload </button>\n}\n", styles: [".options{display:flex}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"] }]
459
- }], propDecorators: { imageCropper: [{
468
+ }], propDecorators: { imageSettings: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageSettings", required: false }] }], ratioType: [{ type: i0.Input, args: [{ isSignal: true, alias: "ratioType", required: false }] }], resolutions: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolutions", required: false }] }], imageUploaded: [{ type: i0.Output, args: ["imageUploaded"] }], onImageCropped: [{ type: i0.Output, args: ["onImageCropped"] }], onFileSelected: [{ type: i0.Output, args: ["onFileSelected"] }], imageCropper: [{
460
469
  type: ViewChild,
461
470
  args: [ImageCropperComponent]
462
471
  }] } });
@@ -468,10 +477,10 @@ class SafeHtmlPipe {
468
477
  transform(value) {
469
478
  return this.sanitizer.bypassSecurityTrustHtml(value);
470
479
  }
471
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
472
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: SafeHtmlPipe, isStandalone: true, name: "safeHtml" }); }
480
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
481
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.2", ngImport: i0, type: SafeHtmlPipe, isStandalone: true, name: "safeHtml" }); }
473
482
  }
474
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SafeHtmlPipe, decorators: [{
483
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SafeHtmlPipe, decorators: [{
475
484
  type: Pipe,
476
485
  args: [{
477
486
  name: 'safeHtml',
@@ -483,9 +492,6 @@ class CropperComponentModal {
483
492
  constructor() {
484
493
  this.multiImagesStorageService = inject(MultiImagesStorageService);
485
494
  this.changeDetectorRef = inject(ChangeDetectorRef);
486
- this.ref = inject(DynamicDialogRef, { optional: true });
487
- this.config = inject(DynamicDialogConfig, { optional: true });
488
- this.dialogService = inject(DialogService);
489
495
  // overrides name, path and resizeToWidth
490
496
  this.imgStorageSettings = input(DEFAULT_SETTINGS, ...(ngDevMode ? [{ debugName: "imgStorageSettings" }] : []));
491
497
  this.buttonLabel = input('Seleccionar archivo', ...(ngDevMode ? [{ debugName: "buttonLabel" }] : []));
@@ -496,6 +502,7 @@ class CropperComponentModal {
496
502
  this.aspectRatioOptions = AspectRatioOptions;
497
503
  this.MoodStateOptions = MoodStateOptions;
498
504
  this.fileMetadata = null;
505
+ this.displayDialog = false;
499
506
  this.aspectRatioValue = 1;
500
507
  this.croppedImage = '';
501
508
  this.renameFile = '';
@@ -510,12 +517,6 @@ class CropperComponentModal {
510
517
  if (!this.imgStorageSettings().path) {
511
518
  console.warn('⚠️ Remember to set imgStorageSettings, path and fileName are required , path example: /collection/id/subcollection ');
512
519
  }
513
- // This happens when the component is opened as a dialog
514
- if (this.config?.data) {
515
- this.imageChangedEvent = this.config.data.imageChangedEvent;
516
- this.fileMetadata = this.config.data.file;
517
- }
518
- this.setSettingsForComponent();
519
520
  this.reloadPath();
520
521
  }
521
522
  reloadPath() {
@@ -524,60 +525,48 @@ class CropperComponentModal {
524
525
  this.storagePath = `${this.imgStorageSettings().path}/${fileName}-${randomCharacters}.webp`;
525
526
  }
526
527
  setSettingsForComponent() {
527
- const settings = this.imgStorageSettings();
528
- if (!settings)
529
- return;
530
- const { cropSettings, path, fileName } = settings;
531
- if (cropSettings) {
532
- const { aspectRatio, resizeToWidth } = cropSettings;
533
- if (aspectRatio) {
534
- this.aspectRatioValue = AspectRatio[aspectRatio];
535
- const defaultRatio = this.aspectRatioOptions.find((option) => option.valueRatio === this.aspectRatioValue);
536
- if (defaultRatio) {
537
- this.ratioSelected = defaultRatio;
538
- }
539
- }
540
- if (resizeToWidth) {
541
- this.resizeToWidth = resizeToWidth;
542
- }
528
+ const imgStorageSettings = this.imgStorageSettings();
529
+ console.log('setSettingsForComponent', imgStorageSettings);
530
+ // TODO: remove all the imageSettings and keep only imgStorageSettings
531
+ this.aspectRatioValue = imgStorageSettings?.cropSettings?.aspectRatio
532
+ ? AspectRatio[imgStorageSettings?.cropSettings?.aspectRatio]
533
+ : AspectRatio[AspectType.Square];
534
+ if (imgStorageSettings?.path) {
535
+ this.storagePath = `${imgStorageSettings.path}/${imgStorageSettings.fileName}.webp`;
536
+ }
537
+ else if (imgStorageSettings.path) {
538
+ this.storagePath = `${imgStorageSettings.path}/${imgStorageSettings.fileName}.webp`;
539
+ }
540
+ if (imgStorageSettings?.cropSettings?.resizeToWidth) {
541
+ this.resizeToWidth = imgStorageSettings.cropSettings.resizeToWidth;
543
542
  }
544
- if (path && fileName) {
545
- this.storagePath = `${path}/${fileName}.webp`;
543
+ else if (imgStorageSettings.cropSettings.resizeToWidth) {
544
+ this.resizeToWidth = imgStorageSettings.cropSettings.resizeToWidth;
546
545
  }
547
- if (fileName) {
548
- this.renameFile = fileName;
546
+ if (imgStorageSettings?.fileName) {
547
+ this.renameFile = imgStorageSettings.fileName;
548
+ }
549
+ else if (imgStorageSettings.fileName) {
550
+ this.renameFile = imgStorageSettings.fileName;
549
551
  }
550
552
  }
551
553
  async fileChangeEvent(event) {
552
554
  this.setSettingsForComponent();
555
+ console.log(this.fileInputId);
556
+ this.imageChangedEvent = event;
553
557
  const file = event?.target?.files[0];
554
558
  if (file) {
555
- this.dialogService
556
- .open(CropperComponentModal, {
557
- header: 'Recortar y subir imagen',
558
- width: '70vw',
559
- modal: true,
560
- closable: true,
561
- maximizable: true,
562
- data: {
563
- imageChangedEvent: event,
564
- file: file,
565
- },
566
- })
567
- .onClose.subscribe((result) => {
568
- if (result) {
569
- this.imageUploaded.emit(result);
570
- }
571
- });
572
559
  this.fileMetadata = file;
573
560
  this.onFileSelected.emit(file);
574
561
  this.renameFile = this.fileMetadata?.name
575
562
  ?.split('.')[0]
576
563
  .replace(/[^a-zA-Z0-9]/g, '')
577
564
  .slice(0, 80);
565
+ console.log(this.renameFile);
578
566
  if (!this.imgStorageSettings().fileName) {
579
567
  this.reloadPath();
580
568
  }
569
+ this.displayDialog = true;
581
570
  this.changeDetectorRef.detectChanges();
582
571
  }
583
572
  }
@@ -605,7 +594,7 @@ class CropperComponentModal {
605
594
  }
606
595
  console.log('imgStorage', imgStorage);
607
596
  this.imageUploaded.emit({ ...imgStorage, metadata: this.emotionSelected });
608
- this.ref.close({ ...imgStorage, metadata: this.emotionSelected });
597
+ this.displayDialog = false;
609
598
  this.changeDetectorRef.detectChanges();
610
599
  }
611
600
  changeRatio(event) {
@@ -619,27 +608,15 @@ class CropperComponentModal {
619
608
  console.log('addEmotion', event);
620
609
  this.emotionSelected = event;
621
610
  }
622
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CropperComponentModal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
623
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: CropperComponentModal, isStandalone: true, selector: "dc-cropper-modal", inputs: { imgStorageSettings: { classPropertyName: "imgStorageSettings", publicName: "imgStorageSettings", isSignal: true, isRequired: false, transformFunction: null }, buttonLabel: { classPropertyName: "buttonLabel", publicName: "buttonLabel", isSignal: true, isRequired: false, transformFunction: null }, currentStorage: { classPropertyName: "currentStorage", publicName: "currentStorage", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { imageUploaded: "imageUploaded", onImageCropped: "onImageCropped", onFileSelected: "onFileSelected" }, providers: [DialogService], viewQueries: [{ propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true }], ngImport: i0, template: "<!-- src/app/components/cropper-modal/cropper-modal.component.html -->\n@if(!config?.data) {\n<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel() }}\n </label>\n</div>\n} @else {\n<!-- Image Settings Section -->\n<div class=\"settings-section\">\n @if(!imgStorageSettings().path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage?.url) {\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n }\n\n <div class=\"grid\">\n <div class=\"col-12 md:col-6\">\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n <ul>\n <li><b>Path to save:</b> {{ storagePath }}</li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings()?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings()?.cropSettings?.aspectRatio }}</p>\n </div>\n\n @if (fileMetadata) {\n <div class=\"metadata-section\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tama\u00F1o: {{ fileMetadata.size }}</span>\n </div>\n }\n </div>\n <div class=\"col-12 md:col-6\">\n <div class=\"flex flex-column gap-2\">\n <div>\n <span>Nombre del archivo</span>\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\">\n <ng-template pTemplate=\"selectedItem\" let-selectedOption>\n @if(selectedOption) {\n <div class=\"flex items-center gap-2\">\n <div [innerHTML]=\"selectedOption.icon | safeHtml\"></div>\n <div>{{ selectedOption.description }}</div>\n </div>\n }\n </ng-template>\n <ng-template let-ratio pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <div [innerHTML]=\"ratio.icon | safeHtml\"></div>\n <div>{{ ratio.description }}</div>\n </div>\n </ng-template>\n </p-select>\n </div>\n\n <div>\n <span>Nombre del archivo</span>\n <input\n pInputText\n [disabled]=\"imgStorageSettings()?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <div>\n <span>Datos adicionales</span>\n <p-select\n [options]=\"MoodStateOptions\"\n [(ngModel)]=\"emotionSelected\"\n (ngModelChange)=\"addEmotion($event)\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select an emotion\" />\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<!-- Image Cropper -->\n<hr />\n\n<div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n</div>\n\n<!-- Dialog Footer -->\n<div class=\"p-dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n</div>\n}\n", styles: [":host{display:block}:host ::ng-deep .ngx-ic-overlay{width:100%!important}.upload-section{margin-bottom:1rem}.upload-section .file-input{display:none}.upload-section .upload-button{cursor:pointer}::ng-deep .cropper-dialog{max-width:90vw;width:800px}::ng-deep .cropper-dialog .p-dialog-content{padding:1.5rem}.settings-section{margin-bottom:1.5rem}.settings-section .grid .col-12{padding-top:0;padding-bottom:0}.settings-section .settings-header{color:var(--text-color-secondary);margin-bottom:1rem}.settings-section .settings-grid{display:grid;gap:1rem;margin-bottom:1.5rem}.settings-section .settings-grid .setting-item .setting-label{font-weight:600;color:var(--text-color);display:block;margin-bottom:.5rem}.settings-section .settings-grid .setting-item .setting-value{color:var(--text-color-secondary);margin:0}.metadata-section{display:flex;gap:1.5rem;margin-bottom:1rem}.metadata-section .metadata-item{color:var(--text-color-secondary)}.rename-section{margin-bottom:5px}.rename-section .rename-input{width:100%;padding:.5rem;border:1px solid var(--surface-border);border-radius:4px}.rename-section .rename-input:disabled{background-color:var(--surface-200);cursor:not-allowed}.cropper-container-father{display:flex;justify-content:center;align-items:center;height:65vh}.dialog-footer{display:flex;justify-content:flex-end;gap:1rem}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem;height:100vh;display:flex;flex-direction:column}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i4.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i5.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i6.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i7.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FieldsetModule }, { kind: "ngmodule", type: DynamicDialogModule }, { kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }] }); }
611
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CropperComponentModal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
612
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: CropperComponentModal, isStandalone: true, selector: "dc-cropper-modal", inputs: { imgStorageSettings: { classPropertyName: "imgStorageSettings", publicName: "imgStorageSettings", isSignal: true, isRequired: false, transformFunction: null }, buttonLabel: { classPropertyName: "buttonLabel", publicName: "buttonLabel", isSignal: true, isRequired: false, transformFunction: null }, currentStorage: { classPropertyName: "currentStorage", publicName: "currentStorage", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { imageUploaded: "imageUploaded", onImageCropped: "onImageCropped", onFileSelected: "onFileSelected" }, viewQueries: [{ propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true }], ngImport: i0, template: "<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel() }}\n </label>\n</div>\n@if(displayDialog) {\n<!-- Cropper Dialog -->\n\n<p-dialog\n header=\"Recortar y subir imagen\"\n [maximizable]=\"true\"\n [(visible)]=\"displayDialog\"\n [modal]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n styleClass=\"cropper-dialog\">\n <!-- Image Settings Section -->\n <div class=\"settings-section\">\n @if(!imgStorageSettings().path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage?.url) {\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n }\n\n <div class=\"grid\">\n <div class=\"col-12 md:col-6\">\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n <ul>\n <li><b>Path to save:</b> {{ storagePath }}</li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings()?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings()?.cropSettings?.aspectRatio }}</p>\n </div>\n\n @if (fileMetadata) {\n <div class=\"metadata-section\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tama\u00F1o: {{ fileMetadata.size }}</span>\n </div>\n }\n </div>\n <div class=\"col-12 md:col-6\">\n <div class=\"flex flex-column gap-2\">\n <div>\n <span>Nombre del archivo</span>\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\">\n <ng-template pTemplate=\"selectedItem\" let-selectedOption>\n @if(selectedOption) {\n <div class=\"flex items-center gap-2\">\n <div [innerHTML]=\"selectedOption.icon | safeHtml\"></div>\n <div>{{ selectedOption.description }}</div>\n </div>\n }\n </ng-template>\n <ng-template let-ratio pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <div [innerHTML]=\"ratio.icon | safeHtml\"></div>\n <div>{{ ratio.description }}</div>\n </div>\n </ng-template>\n </p-select>\n </div>\n\n <div>\n <span>Nombre del archivo</span>\n <input\n pInputText\n [disabled]=\"imgStorageSettings()?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <div>\n <span>Datos adicionales</span>\n <p-select\n [options]=\"MoodStateOptions\"\n [(ngModel)]=\"emotionSelected\"\n (ngModelChange)=\"addEmotion($event)\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select an emotion\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Image Cropper -->\n\n <hr />\n\n <div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n </div>\n <!-- Dialog Footer -->\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\"> Recortar y Subir </button>\n </div>\n </ng-template>\n</p-dialog>\n}\n", styles: [":host{display:block}:host ::ng-deep .ngx-ic-overlay{width:100%!important}.upload-section{margin-bottom:1rem}.upload-section .file-input{display:none}.upload-section .upload-button{cursor:pointer}::ng-deep .cropper-dialog{max-width:90vw;width:800px}::ng-deep .cropper-dialog .p-dialog-content{padding:1.5rem}.settings-section{margin-bottom:1.5rem}.settings-section .grid .col-12{padding-top:0;padding-bottom:0}.settings-section .settings-header{color:var(--text-color-secondary);margin-bottom:1rem}.settings-section .settings-grid{display:grid;gap:1rem;margin-bottom:1.5rem}.settings-section .settings-grid .setting-item .setting-label{font-weight:600;color:var(--text-color);display:block;margin-bottom:.5rem}.settings-section .settings-grid .setting-item .setting-value{color:var(--text-color-secondary);margin:0}.metadata-section{display:flex;gap:1.5rem;margin-bottom:1rem}.metadata-section .metadata-item{color:var(--text-color-secondary)}.rename-section{margin-bottom:5px}.rename-section .rename-input{width:100%;padding:.5rem;border:1px solid var(--surface-border);border-radius:4px}.rename-section .rename-input:disabled{background-color:var(--surface-200);cursor:not-allowed}.cropper-container-father{display:flex;justify-content:center;align-items:center;height:65vh}.dialog-footer{display:flex;justify-content:flex-end;gap:1rem}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem;height:100vh;display:flex;flex-direction:column}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i6.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant", "motionOptions"], outputs: ["onClose"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i7.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i8.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }] }); }
624
613
  }
625
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CropperComponentModal, decorators: [{
614
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CropperComponentModal, decorators: [{
626
615
  type: Component,
627
- args: [{ selector: 'dc-cropper-modal', standalone: true, imports: [
628
- FormsModule,
629
- ImageCropperComponent,
630
- ButtonModule,
631
- DialogModule,
632
- TooltipModule,
633
- MessageModule,
634
- SelectModule,
635
- InputTextModule,
636
- SafeHtmlPipe,
637
- FieldsetModule,
638
- DynamicDialogModule,
639
- ], providers: [DialogService], template: "<!-- src/app/components/cropper-modal/cropper-modal.component.html -->\n@if(!config?.data) {\n<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel() }}\n </label>\n</div>\n} @else {\n<!-- Image Settings Section -->\n<div class=\"settings-section\">\n @if(!imgStorageSettings().path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage?.url) {\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n }\n\n <div class=\"grid\">\n <div class=\"col-12 md:col-6\">\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n <ul>\n <li><b>Path to save:</b> {{ storagePath }}</li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings()?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings()?.cropSettings?.aspectRatio }}</p>\n </div>\n\n @if (fileMetadata) {\n <div class=\"metadata-section\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tama\u00F1o: {{ fileMetadata.size }}</span>\n </div>\n }\n </div>\n <div class=\"col-12 md:col-6\">\n <div class=\"flex flex-column gap-2\">\n <div>\n <span>Nombre del archivo</span>\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\">\n <ng-template pTemplate=\"selectedItem\" let-selectedOption>\n @if(selectedOption) {\n <div class=\"flex items-center gap-2\">\n <div [innerHTML]=\"selectedOption.icon | safeHtml\"></div>\n <div>{{ selectedOption.description }}</div>\n </div>\n }\n </ng-template>\n <ng-template let-ratio pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <div [innerHTML]=\"ratio.icon | safeHtml\"></div>\n <div>{{ ratio.description }}</div>\n </div>\n </ng-template>\n </p-select>\n </div>\n\n <div>\n <span>Nombre del archivo</span>\n <input\n pInputText\n [disabled]=\"imgStorageSettings()?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <div>\n <span>Datos adicionales</span>\n <p-select\n [options]=\"MoodStateOptions\"\n [(ngModel)]=\"emotionSelected\"\n (ngModelChange)=\"addEmotion($event)\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select an emotion\" />\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<!-- Image Cropper -->\n<hr />\n\n<div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n</div>\n\n<!-- Dialog Footer -->\n<div class=\"p-dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n</div>\n}\n", styles: [":host{display:block}:host ::ng-deep .ngx-ic-overlay{width:100%!important}.upload-section{margin-bottom:1rem}.upload-section .file-input{display:none}.upload-section .upload-button{cursor:pointer}::ng-deep .cropper-dialog{max-width:90vw;width:800px}::ng-deep .cropper-dialog .p-dialog-content{padding:1.5rem}.settings-section{margin-bottom:1.5rem}.settings-section .grid .col-12{padding-top:0;padding-bottom:0}.settings-section .settings-header{color:var(--text-color-secondary);margin-bottom:1rem}.settings-section .settings-grid{display:grid;gap:1rem;margin-bottom:1.5rem}.settings-section .settings-grid .setting-item .setting-label{font-weight:600;color:var(--text-color);display:block;margin-bottom:.5rem}.settings-section .settings-grid .setting-item .setting-value{color:var(--text-color-secondary);margin:0}.metadata-section{display:flex;gap:1.5rem;margin-bottom:1rem}.metadata-section .metadata-item{color:var(--text-color-secondary)}.rename-section{margin-bottom:5px}.rename-section .rename-input{width:100%;padding:.5rem;border:1px solid var(--surface-border);border-radius:4px}.rename-section .rename-input:disabled{background-color:var(--surface-200);cursor:not-allowed}.cropper-container-father{display:flex;justify-content:center;align-items:center;height:65vh}.dialog-footer{display:flex;justify-content:flex-end;gap:1rem}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem;height:100vh;display:flex;flex-direction:column}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"] }]
640
- }], ctorParameters: () => [], propDecorators: { currentStorage: [{
616
+ args: [{ selector: 'dc-cropper-modal', standalone: true, imports: [FormsModule, ImageCropperComponent, ButtonModule, DialogModule, TooltipModule, MessageModule, SelectModule, InputTextModule, SafeHtmlPipe], template: "<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel() }}\n </label>\n</div>\n@if(displayDialog) {\n<!-- Cropper Dialog -->\n\n<p-dialog\n header=\"Recortar y subir imagen\"\n [maximizable]=\"true\"\n [(visible)]=\"displayDialog\"\n [modal]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n styleClass=\"cropper-dialog\">\n <!-- Image Settings Section -->\n <div class=\"settings-section\">\n @if(!imgStorageSettings().path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage?.url) {\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n }\n\n <div class=\"grid\">\n <div class=\"col-12 md:col-6\">\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n <ul>\n <li><b>Path to save:</b> {{ storagePath }}</li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings()?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings()?.cropSettings?.aspectRatio }}</p>\n </div>\n\n @if (fileMetadata) {\n <div class=\"metadata-section\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tama\u00F1o: {{ fileMetadata.size }}</span>\n </div>\n }\n </div>\n <div class=\"col-12 md:col-6\">\n <div class=\"flex flex-column gap-2\">\n <div>\n <span>Nombre del archivo</span>\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\">\n <ng-template pTemplate=\"selectedItem\" let-selectedOption>\n @if(selectedOption) {\n <div class=\"flex items-center gap-2\">\n <div [innerHTML]=\"selectedOption.icon | safeHtml\"></div>\n <div>{{ selectedOption.description }}</div>\n </div>\n }\n </ng-template>\n <ng-template let-ratio pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <div [innerHTML]=\"ratio.icon | safeHtml\"></div>\n <div>{{ ratio.description }}</div>\n </div>\n </ng-template>\n </p-select>\n </div>\n\n <div>\n <span>Nombre del archivo</span>\n <input\n pInputText\n [disabled]=\"imgStorageSettings()?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <div>\n <span>Datos adicionales</span>\n <p-select\n [options]=\"MoodStateOptions\"\n [(ngModel)]=\"emotionSelected\"\n (ngModelChange)=\"addEmotion($event)\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select an emotion\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Image Cropper -->\n\n <hr />\n\n <div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n </div>\n <!-- Dialog Footer -->\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\"> Recortar y Subir </button>\n </div>\n </ng-template>\n</p-dialog>\n}\n", styles: [":host{display:block}:host ::ng-deep .ngx-ic-overlay{width:100%!important}.upload-section{margin-bottom:1rem}.upload-section .file-input{display:none}.upload-section .upload-button{cursor:pointer}::ng-deep .cropper-dialog{max-width:90vw;width:800px}::ng-deep .cropper-dialog .p-dialog-content{padding:1.5rem}.settings-section{margin-bottom:1.5rem}.settings-section .grid .col-12{padding-top:0;padding-bottom:0}.settings-section .settings-header{color:var(--text-color-secondary);margin-bottom:1rem}.settings-section .settings-grid{display:grid;gap:1rem;margin-bottom:1.5rem}.settings-section .settings-grid .setting-item .setting-label{font-weight:600;color:var(--text-color);display:block;margin-bottom:.5rem}.settings-section .settings-grid .setting-item .setting-value{color:var(--text-color-secondary);margin:0}.metadata-section{display:flex;gap:1.5rem;margin-bottom:1rem}.metadata-section .metadata-item{color:var(--text-color-secondary)}.rename-section{margin-bottom:5px}.rename-section .rename-input{width:100%;padding:.5rem;border:1px solid var(--surface-border);border-radius:4px}.rename-section .rename-input:disabled{background-color:var(--surface-200);cursor:not-allowed}.cropper-container-father{display:flex;justify-content:center;align-items:center;height:65vh}.dialog-footer{display:flex;justify-content:flex-end;gap:1rem}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem;height:100vh;display:flex;flex-direction:column}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"] }]
617
+ }], ctorParameters: () => [], propDecorators: { imgStorageSettings: [{ type: i0.Input, args: [{ isSignal: true, alias: "imgStorageSettings", required: false }] }], buttonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonLabel", required: false }] }], currentStorage: [{
641
618
  type: Input
642
- }], imageCropper: [{
619
+ }], imageUploaded: [{ type: i0.Output, args: ["imageUploaded"] }], onImageCropped: [{ type: i0.Output, args: ["onImageCropped"] }], onFileSelected: [{ type: i0.Output, args: ["onFileSelected"] }], imageCropper: [{
643
620
  type: ViewChild,
644
621
  args: [ImageCropperComponent]
645
622
  }] } });
@@ -717,13 +694,13 @@ class ImageStoragePreviewComponent {
717
694
  selectImage(image) {
718
695
  this.imageSelected.emit(image);
719
696
  }
720
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ImageStoragePreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
721
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: ImageStoragePreviewComponent, isStandalone: true, selector: "dc-image-storage-preview", outputs: { imageSelected: "imageSelected" }, ngImport: i0, template: "<div class=\"image-storage-preview-container\">\n <div class=\"header\">\n <h2>Storage Images</h2>\n <button class=\"refresh-btn\" (click)=\"refreshImages()\" [disabled]=\"loading$ | async\">\n @if (!(loading$ | async)) {\n <span>Refresh</span>\n }\n @if (loading$ | async) {\n <span>Loading...</span>\n }\n </button>\n </div>\n\n @if (loading$ | async) {\n <div class=\"loading-container\">\n <div class=\"spinner\"></div>\n <p>Loading images...</p>\n </div>\n }\n\n @if (error$ | async) {\n <div class=\"error-container\">\n <p class=\"error-message\">{{ error$ | async }}</p>\n <button (click)=\"refreshImages()\">Try Again</button>\n </div>\n }\n\n @if (!(loading$ | async) && !(error$ | async)) {\n <div class=\"images-grid\">\n @if ((images$ | async)?.length) {\n @for (image of images$ | async; track image) {\n <div class=\"image-card\">\n <div class=\"image-container\">\n <img [src]=\"image.url\" [alt]=\"image.name || 'Storage image'\" loading=\"lazy\" />\n </div>\n <div class=\"image-info\">\n <p class=\"image-name\" [title]=\"image.name\">{{ image.name }}</p>\n <div class=\"image-actions\">\n <a [href]=\"image.url\" target=\"_blank\" class=\"action-btn\">View</a>\n <button (click)=\"selectImage(image)\" class=\"action-btn\">Select</button>\n </div>\n </div>\n </div>\n }\n } @else {\n <div class=\"no-images\">\n <p>No images found in the storage path: {{ storagePath }}</p>\n </div>\n }\n <dc-cropper-modal [imgStorageSettings]=\"imgStorageSettings\"></dc-cropper-modal>\n </div>\n }\n</div>\n", styles: [".image-storage-preview-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;padding:20px;max-width:1200px;margin:0 auto}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.header h2{margin:0;color:#333}.refresh-btn{background-color:#4285f4;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px;transition:background-color .2s}.refresh-btn:hover{background-color:#3367d6}.refresh-btn:disabled{background-color:#a9a9a9;cursor:not-allowed}.loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 0}.spinner{border:4px solid rgba(0,0,0,.1);border-radius:50%;border-top:4px solid #4285f4;width:30px;height:30px;animation:spin 1s linear infinite;margin-bottom:15px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.error-container{background-color:#ffebee;border:1px solid #ffcdd2;border-radius:4px;padding:16px;margin:20px 0;text-align:center}.error-message{color:#d32f2f;margin-bottom:10px}.error-container button{background-color:#d32f2f;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px}.images-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:20px}.image-card{border-radius:8px;overflow:hidden;box-shadow:0 2px 10px #0000001a;transition:transform .2s,box-shadow .2s;background-color:#fff}.image-card:hover{transform:translateY(-5px);box-shadow:0 5px 15px #00000026}.image-container{height:200px;overflow:hidden;position:relative;background-color:#f5f5f5}.image-container img{width:100%;height:100%;object-fit:cover;transition:transform .3s}.image-card:hover .image-container img{transform:scale(1.05)}.image-info{padding:15px}.image-name{margin:0 0 10px;font-size:14px;font-weight:500;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.image-actions{display:flex;justify-content:flex-end}.action-btn{background-color:#4285f4;color:#fff;text-decoration:none;border-radius:4px;padding:6px 12px;font-size:12px;transition:background-color .2s}.action-btn:hover{background-color:#3367d6}.no-images{grid-column:1 / -1;text-align:center;padding:40px 0;color:#757575;background-color:#f5f5f5;border-radius:8px}\n"], dependencies: [{ kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
697
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ImageStoragePreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
698
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: ImageStoragePreviewComponent, isStandalone: true, selector: "dc-image-storage-preview", outputs: { imageSelected: "imageSelected" }, ngImport: i0, template: "<div class=\"image-storage-preview-container\">\n <div class=\"header\">\n <h2>Storage Images</h2>\n <button class=\"refresh-btn\" (click)=\"refreshImages()\" [disabled]=\"loading$ | async\">\n @if (!(loading$ | async)) {\n <span>Refresh</span>\n }\n @if (loading$ | async) {\n <span>Loading...</span>\n }\n </button>\n </div>\n\n @if (loading$ | async) {\n <div class=\"loading-container\">\n <div class=\"spinner\"></div>\n <p>Loading images...</p>\n </div>\n }\n\n @if (error$ | async) {\n <div class=\"error-container\">\n <p class=\"error-message\">{{ error$ | async }}</p>\n <button (click)=\"refreshImages()\">Try Again</button>\n </div>\n }\n\n @if (!(loading$ | async) && !(error$ | async)) {\n <div class=\"images-grid\">\n @if ((images$ | async)?.length) {\n @for (image of images$ | async; track image) {\n <div class=\"image-card\">\n <div class=\"image-container\">\n <img [src]=\"image.url\" [alt]=\"image.name || 'Storage image'\" loading=\"lazy\" />\n </div>\n <div class=\"image-info\">\n <p class=\"image-name\" [title]=\"image.name\">{{ image.name }}</p>\n <div class=\"image-actions\">\n <a [href]=\"image.url\" target=\"_blank\" class=\"action-btn\">View</a>\n <button (click)=\"selectImage(image)\" class=\"action-btn\">Select</button>\n </div>\n </div>\n </div>\n }\n } @else {\n <div class=\"no-images\">\n <p>No images found in the storage path: {{ storagePath }}</p>\n </div>\n }\n <dc-cropper-modal [imgStorageSettings]=\"imgStorageSettings\"></dc-cropper-modal>\n </div>\n }\n</div>\n", styles: [".image-storage-preview-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;padding:20px;max-width:1200px;margin:0 auto}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.header h2{margin:0;color:#333}.refresh-btn{background-color:#4285f4;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px;transition:background-color .2s}.refresh-btn:hover{background-color:#3367d6}.refresh-btn:disabled{background-color:#a9a9a9;cursor:not-allowed}.loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 0}.spinner{border:4px solid rgba(0,0,0,.1);border-radius:50%;border-top:4px solid #4285f4;width:30px;height:30px;animation:spin 1s linear infinite;margin-bottom:15px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.error-container{background-color:#ffebee;border:1px solid #ffcdd2;border-radius:4px;padding:16px;margin:20px 0;text-align:center}.error-message{color:#d32f2f;margin-bottom:10px}.error-container button{background-color:#d32f2f;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px}.images-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:20px}.image-card{border-radius:8px;overflow:hidden;box-shadow:0 2px 10px #0000001a;transition:transform .2s,box-shadow .2s;background-color:#fff}.image-card:hover{transform:translateY(-5px);box-shadow:0 5px 15px #00000026}.image-container{height:200px;overflow:hidden;position:relative;background-color:#f5f5f5}.image-container img{width:100%;height:100%;object-fit:cover;transition:transform .3s}.image-card:hover .image-container img{transform:scale(1.05)}.image-info{padding:15px}.image-name{margin:0 0 10px;font-size:14px;font-weight:500;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.image-actions{display:flex;justify-content:flex-end}.action-btn{background-color:#4285f4;color:#fff;text-decoration:none;border-radius:4px;padding:6px 12px;font-size:12px;transition:background-color .2s}.action-btn:hover{background-color:#3367d6}.no-images{grid-column:1 / -1;text-align:center;padding:40px 0;color:#757575;background-color:#f5f5f5;border-radius:8px}\n"], dependencies: [{ kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
722
699
  }
723
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ImageStoragePreviewComponent, decorators: [{
700
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ImageStoragePreviewComponent, decorators: [{
724
701
  type: Component,
725
702
  args: [{ selector: 'dc-image-storage-preview', standalone: true, imports: [AsyncPipe, CropperComponentModal], template: "<div class=\"image-storage-preview-container\">\n <div class=\"header\">\n <h2>Storage Images</h2>\n <button class=\"refresh-btn\" (click)=\"refreshImages()\" [disabled]=\"loading$ | async\">\n @if (!(loading$ | async)) {\n <span>Refresh</span>\n }\n @if (loading$ | async) {\n <span>Loading...</span>\n }\n </button>\n </div>\n\n @if (loading$ | async) {\n <div class=\"loading-container\">\n <div class=\"spinner\"></div>\n <p>Loading images...</p>\n </div>\n }\n\n @if (error$ | async) {\n <div class=\"error-container\">\n <p class=\"error-message\">{{ error$ | async }}</p>\n <button (click)=\"refreshImages()\">Try Again</button>\n </div>\n }\n\n @if (!(loading$ | async) && !(error$ | async)) {\n <div class=\"images-grid\">\n @if ((images$ | async)?.length) {\n @for (image of images$ | async; track image) {\n <div class=\"image-card\">\n <div class=\"image-container\">\n <img [src]=\"image.url\" [alt]=\"image.name || 'Storage image'\" loading=\"lazy\" />\n </div>\n <div class=\"image-info\">\n <p class=\"image-name\" [title]=\"image.name\">{{ image.name }}</p>\n <div class=\"image-actions\">\n <a [href]=\"image.url\" target=\"_blank\" class=\"action-btn\">View</a>\n <button (click)=\"selectImage(image)\" class=\"action-btn\">Select</button>\n </div>\n </div>\n </div>\n }\n } @else {\n <div class=\"no-images\">\n <p>No images found in the storage path: {{ storagePath }}</p>\n </div>\n }\n <dc-cropper-modal [imgStorageSettings]=\"imgStorageSettings\"></dc-cropper-modal>\n </div>\n }\n</div>\n", styles: [".image-storage-preview-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;padding:20px;max-width:1200px;margin:0 auto}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.header h2{margin:0;color:#333}.refresh-btn{background-color:#4285f4;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px;transition:background-color .2s}.refresh-btn:hover{background-color:#3367d6}.refresh-btn:disabled{background-color:#a9a9a9;cursor:not-allowed}.loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 0}.spinner{border:4px solid rgba(0,0,0,.1);border-radius:50%;border-top:4px solid #4285f4;width:30px;height:30px;animation:spin 1s linear infinite;margin-bottom:15px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.error-container{background-color:#ffebee;border:1px solid #ffcdd2;border-radius:4px;padding:16px;margin:20px 0;text-align:center}.error-message{color:#d32f2f;margin-bottom:10px}.error-container button{background-color:#d32f2f;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px}.images-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:20px}.image-card{border-radius:8px;overflow:hidden;box-shadow:0 2px 10px #0000001a;transition:transform .2s,box-shadow .2s;background-color:#fff}.image-card:hover{transform:translateY(-5px);box-shadow:0 5px 15px #00000026}.image-container{height:200px;overflow:hidden;position:relative;background-color:#f5f5f5}.image-container img{width:100%;height:100%;object-fit:cover;transition:transform .3s}.image-card:hover .image-container img{transform:scale(1.05)}.image-info{padding:15px}.image-name{margin:0 0 10px;font-size:14px;font-weight:500;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.image-actions{display:flex;justify-content:flex-end}.action-btn{background-color:#4285f4;color:#fff;text-decoration:none;border-radius:4px;padding:6px 12px;font-size:12px;transition:background-color .2s}.action-btn:hover{background-color:#3367d6}.no-images{grid-column:1 / -1;text-align:center;padding:40px 0;color:#757575;background-color:#f5f5f5;border-radius:8px}\n"] }]
726
- }], ctorParameters: () => [] });
703
+ }], ctorParameters: () => [], propDecorators: { imageSelected: [{ type: i0.Output, args: ["imageSelected"] }] } });
727
704
 
728
705
  class SimpleUploaderComponent {
729
706
  constructor() {
@@ -794,13 +771,13 @@ class SimpleUploaderComponent {
794
771
  }
795
772
  }
796
773
  }
797
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SimpleUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
798
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: SimpleUploaderComponent, isStandalone: true, selector: "dc-simple-uploader", inputs: { storagePath: { classPropertyName: "storagePath", publicName: "storagePath", isSignal: true, isRequired: true, transformFunction: null }, buttonLabel: { classPropertyName: "buttonLabel", publicName: "buttonLabel", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fileUploaded: "fileUploaded", uploadError: "uploadError" }, ngImport: i0, template: "<p-button\n size=\"large\"\n [label]=\"buttonLabel()\"\n (click)=\"openDialog()\"\n [loading]=\"isLoading()\"\n [disabled]=\"disabled() || isLoading()\"\n pTooltip=\"Upload a file with metadata\"></p-button>\n\n@if(displayDialog()){\n<p-dialog\n header=\"Upload File\"\n [(visible)]=\"displayDialog\"\n [modal]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [contentStyle]=\"{ width: '50vw', height: '50vh' }\">\n <div class=\"upload-dialog\">\n @if(!fileSelected()){\n <div class=\"file-input-container\">\n <input #fileInput type=\"file\" [id]=\"fileInputId\" (change)=\"onFileSelected($event)\" [accept]=\"accept()\" style=\"display: none\" />\n <p-button label=\"Select File\" (click)=\"triggerFileInputClick(fileInput)\"></p-button>\n </div>\n } @else {\n <div class=\"file-details\">\n <p>File: {{ fileSelected()?.name }}</p>\n <p>Size: {{ fileSelected()?.size }} bytes</p>\n </div>\n\n <div class=\"metadata-container\">\n <h5>Metadata</h5>\n <div class=\"p-fluid\">\n @for (key of objectKeys(metadata()); track key) {\n <div class=\"p-field\">\n <label [for]=\"key\">{{ key }}</label>\n <input pInputText [id]=\"key\" [(ngModel)]=\"metadataInput[key]\" />\n </div>\n }\n\n <div class=\"p-field\">\n <label for=\"emotion\">Emotion</label>\n <br />\n <p-select [options]=\"MoodStateOptions\" [(ngModel)]=\"moodSelected\" optionLabel=\"label\" optionValue=\"value\" placeholder=\"Select an emotion\"></p-select>\n </div>\n <div class=\"p-field\">\n <label for=\"emotion\">Event</label>\n <br />\n <p-select\n [options]=\"CharacterEventActions\"\n [(ngModel)]=\"eventSelected\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select an event\"></p-select>\n </div>\n </div>\n </div>\n }\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <p-button label=\"Cancel\" styleClass=\"p-button-secondary\" (click)=\"displayDialog.set(false)\"></p-button>\n <p-button label=\"Upload\" (click)=\"uploadFile()\" [disabled]=\"!fileSelected() || isLoading()\"></p-button>\n </div>\n </ng-template>\n</p-dialog>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i4.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i5$1.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i7.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i6.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }] }); }
774
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SimpleUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
775
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: SimpleUploaderComponent, isStandalone: true, selector: "dc-simple-uploader", inputs: { storagePath: { classPropertyName: "storagePath", publicName: "storagePath", isSignal: true, isRequired: true, transformFunction: null }, buttonLabel: { classPropertyName: "buttonLabel", publicName: "buttonLabel", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fileUploaded: "fileUploaded", uploadError: "uploadError" }, ngImport: i0, template: "<p-button\n size=\"large\"\n [label]=\"buttonLabel()\"\n (click)=\"openDialog()\"\n [loading]=\"isLoading()\"\n [disabled]=\"disabled() || isLoading()\"\n pTooltip=\"Upload a file with metadata\"></p-button>\n\n@if(displayDialog()){\n<p-dialog\n header=\"Upload File\"\n [(visible)]=\"displayDialog\"\n [modal]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [contentStyle]=\"{ width: '50vw', height: '50vh' }\">\n <div class=\"upload-dialog\">\n @if(!fileSelected()){\n <div class=\"file-input-container\">\n <input #fileInput type=\"file\" [id]=\"fileInputId\" (change)=\"onFileSelected($event)\" [accept]=\"accept()\" style=\"display: none\" />\n <p-button label=\"Select File\" (click)=\"triggerFileInputClick(fileInput)\"></p-button>\n </div>\n } @else {\n <div class=\"file-details\">\n <p>File: {{ fileSelected()?.name }}</p>\n <p>Size: {{ fileSelected()?.size }} bytes</p>\n </div>\n\n <div class=\"metadata-container\">\n <h5>Metadata</h5>\n <div class=\"p-fluid\">\n @for (key of objectKeys(metadata()); track key) {\n <div class=\"p-field\">\n <label [for]=\"key\">{{ key }}</label>\n <input pInputText [id]=\"key\" [(ngModel)]=\"metadataInput[key]\" />\n </div>\n }\n\n <div class=\"p-field\">\n <label for=\"emotion\">Emotion</label>\n <br />\n <p-select [options]=\"MoodStateOptions\" [(ngModel)]=\"moodSelected\" optionLabel=\"label\" optionValue=\"value\" placeholder=\"Select an emotion\"></p-select>\n </div>\n <div class=\"p-field\">\n <label for=\"emotion\">Event</label>\n <br />\n <p-select\n [options]=\"CharacterEventActions\"\n [(ngModel)]=\"eventSelected\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select an event\"></p-select>\n </div>\n </div>\n </div>\n }\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <p-button label=\"Cancel\" styleClass=\"p-button-secondary\" (click)=\"displayDialog.set(false)\"></p-button>\n <p-button label=\"Upload\" (click)=\"uploadFile()\" [disabled]=\"!fileSelected() || isLoading()\"></p-button>\n </div>\n </ng-template>\n</p-dialog>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i8.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i7.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }] }); }
799
776
  }
800
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SimpleUploaderComponent, decorators: [{
777
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SimpleUploaderComponent, decorators: [{
801
778
  type: Component,
802
779
  args: [{ selector: 'dc-simple-uploader', standalone: true, imports: [CommonModule, FormsModule, ButtonModule, TooltipModule, DialogModule, InputTextModule, SelectModule], template: "<p-button\n size=\"large\"\n [label]=\"buttonLabel()\"\n (click)=\"openDialog()\"\n [loading]=\"isLoading()\"\n [disabled]=\"disabled() || isLoading()\"\n pTooltip=\"Upload a file with metadata\"></p-button>\n\n@if(displayDialog()){\n<p-dialog\n header=\"Upload File\"\n [(visible)]=\"displayDialog\"\n [modal]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [contentStyle]=\"{ width: '50vw', height: '50vh' }\">\n <div class=\"upload-dialog\">\n @if(!fileSelected()){\n <div class=\"file-input-container\">\n <input #fileInput type=\"file\" [id]=\"fileInputId\" (change)=\"onFileSelected($event)\" [accept]=\"accept()\" style=\"display: none\" />\n <p-button label=\"Select File\" (click)=\"triggerFileInputClick(fileInput)\"></p-button>\n </div>\n } @else {\n <div class=\"file-details\">\n <p>File: {{ fileSelected()?.name }}</p>\n <p>Size: {{ fileSelected()?.size }} bytes</p>\n </div>\n\n <div class=\"metadata-container\">\n <h5>Metadata</h5>\n <div class=\"p-fluid\">\n @for (key of objectKeys(metadata()); track key) {\n <div class=\"p-field\">\n <label [for]=\"key\">{{ key }}</label>\n <input pInputText [id]=\"key\" [(ngModel)]=\"metadataInput[key]\" />\n </div>\n }\n\n <div class=\"p-field\">\n <label for=\"emotion\">Emotion</label>\n <br />\n <p-select [options]=\"MoodStateOptions\" [(ngModel)]=\"moodSelected\" optionLabel=\"label\" optionValue=\"value\" placeholder=\"Select an emotion\"></p-select>\n </div>\n <div class=\"p-field\">\n <label for=\"emotion\">Event</label>\n <br />\n <p-select\n [options]=\"CharacterEventActions\"\n [(ngModel)]=\"eventSelected\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select an event\"></p-select>\n </div>\n </div>\n </div>\n }\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <p-button label=\"Cancel\" styleClass=\"p-button-secondary\" (click)=\"displayDialog.set(false)\"></p-button>\n <p-button label=\"Upload\" (click)=\"uploadFile()\" [disabled]=\"!fileSelected() || isLoading()\"></p-button>\n </div>\n </ng-template>\n</p-dialog>\n}\n" }]
803
- }], ctorParameters: () => [] });
780
+ }], ctorParameters: () => [], propDecorators: { storagePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "storagePath", required: true }] }], buttonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonLabel", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], metadata: [{ type: i0.Input, args: [{ isSignal: true, alias: "metadata", required: false }] }], fileUploaded: [{ type: i0.Output, args: ["fileUploaded"] }], uploadError: [{ type: i0.Output, args: ["uploadError"] }] } });
804
781
 
805
782
  class DCFilesCacheService {
806
783
  constructor() {
@@ -838,10 +815,10 @@ class DCFilesCacheService {
838
815
  const blob = await this.getBlob(url);
839
816
  return URL.createObjectURL(blob);
840
817
  }
841
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCFilesCacheService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
842
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCFilesCacheService, providedIn: 'root' }); }
818
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: DCFilesCacheService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
819
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: DCFilesCacheService, providedIn: 'root' }); }
843
820
  }
844
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCFilesCacheService, decorators: [{
821
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: DCFilesCacheService, decorators: [{
845
822
  type: Injectable,
846
823
  args: [{
847
824
  providedIn: 'root',
@@ -936,16 +913,337 @@ class MultiObjectStorageService {
936
913
  };
937
914
  return meta;
938
915
  }
939
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: MultiObjectStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
940
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: MultiObjectStorageService, providedIn: 'root' }); }
916
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MultiObjectStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
917
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MultiObjectStorageService, providedIn: 'root' }); }
918
+ }
919
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MultiObjectStorageService, decorators: [{
920
+ type: Injectable,
921
+ args: [{
922
+ providedIn: 'root',
923
+ }]
924
+ }] });
925
+
926
+ class FirebaseStorageProvider {
927
+ constructor() {
928
+ this.storage = inject(AngularFireStorage);
929
+ }
930
+ async uploadImage(image, path) {
931
+ try {
932
+ const refStorage = this.storage.ref(path);
933
+ const task = await refStorage.put(image);
934
+ const url = await lastValueFrom(refStorage.getDownloadURL());
935
+ return {
936
+ url,
937
+ name: task.metadata.name,
938
+ type: task.metadata.contentType,
939
+ size: task.metadata.size,
940
+ };
941
+ }
942
+ catch (error) {
943
+ console.error('Firebase upload image error:', error);
944
+ return null;
945
+ }
946
+ }
947
+ async uploadGenericFile(file, storagePath, metadata, keepOriginalName) {
948
+ try {
949
+ const fileName = keepOriginalName ? file.name : `${Date.now()}-${file.name}`;
950
+ const fullFilePath = `${storagePath.replace(/\/$/, '')}/${fileName}`;
951
+ const refStorage = this.storage.ref(fullFilePath);
952
+ const task = await refStorage.put(file, { customMetadata: metadata });
953
+ const url = await lastValueFrom(refStorage.getDownloadURL());
954
+ return {
955
+ url,
956
+ name: file.name,
957
+ type: file.type,
958
+ size: file.size,
959
+ metadata: task.metadata,
960
+ };
961
+ }
962
+ catch (error) {
963
+ console.error('Firebase upload generic file error:', error);
964
+ return null;
965
+ }
966
+ }
967
+ async uploadMultipleFiles(files, storagePath, metadata, keepOriginalName) {
968
+ try {
969
+ const uploadPromises = files.map(file => this.uploadGenericFile(file, storagePath, metadata, keepOriginalName));
970
+ const results = await Promise.all(uploadPromises);
971
+ return results.filter((r) => r !== null);
972
+ }
973
+ catch (error) {
974
+ console.error('Firebase upload multiple files error:', error);
975
+ return null;
976
+ }
977
+ }
978
+ async deleteImage(imagePath) {
979
+ const storageRef = this.storage.ref(imagePath);
980
+ await lastValueFrom(storageRef.delete());
981
+ }
982
+ async deleteDirectory(directoryPath) {
983
+ const storage = getStorage();
984
+ const directoryRef = ref(storage, directoryPath);
985
+ const res = await listAll(directoryRef);
986
+ const promises = res.items.map((itemRef) => deleteObject(itemRef));
987
+ await Promise.all(promises);
988
+ }
989
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: FirebaseStorageProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
990
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: FirebaseStorageProvider, providedIn: 'root' }); }
991
+ }
992
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: FirebaseStorageProvider, decorators: [{
993
+ type: Injectable,
994
+ args: [{
995
+ providedIn: 'root',
996
+ }]
997
+ }] });
998
+
999
+ class BackendStorageProvider {
1000
+ constructor() {
1001
+ this.http = inject(HttpClient);
1002
+ this.appConfig = inject(APP_CONFIG);
1003
+ this.apiUrl = this.appConfig.backendNodeUrl + '/storage'; // This should ideally come from an environment config
1004
+ }
1005
+ async uploadImage(image, path) {
1006
+ const formData = new FormData();
1007
+ formData.append('file', image, 'image.webp');
1008
+ const params = {
1009
+ path,
1010
+ provider: 'GOOGLE'
1011
+ };
1012
+ try {
1013
+ return await firstValueFrom(this.http.post(`${this.apiUrl}/upload`, formData, { params }));
1014
+ }
1015
+ catch (error) {
1016
+ console.error('Backend upload image error:', error);
1017
+ return null;
1018
+ }
1019
+ }
1020
+ async uploadGenericFile(file, storagePath, metadata, keepOriginalName) {
1021
+ const formData = new FormData();
1022
+ if (metadata) {
1023
+ formData.append('metadata', JSON.stringify(metadata));
1024
+ }
1025
+ formData.append('file', file);
1026
+ const params = {
1027
+ path: storagePath,
1028
+ provider: 'GOOGLE'
1029
+ };
1030
+ if (keepOriginalName) {
1031
+ params.keepOriginalName = 'true';
1032
+ }
1033
+ try {
1034
+ return await firstValueFrom(this.http.post(`${this.apiUrl}/upload`, formData, { params }));
1035
+ }
1036
+ catch (error) {
1037
+ console.error('Backend upload generic file error:', error);
1038
+ return null;
1039
+ }
1040
+ }
1041
+ async uploadMultipleFiles(files, storagePath, metadata, keepOriginalName) {
1042
+ const formData = new FormData();
1043
+ if (metadata) {
1044
+ formData.append('metadata', JSON.stringify(metadata));
1045
+ }
1046
+ files.forEach(file => {
1047
+ formData.append('file', file, file.name);
1048
+ });
1049
+ const params = {
1050
+ path: storagePath,
1051
+ provider: 'GOOGLE'
1052
+ };
1053
+ if (keepOriginalName) {
1054
+ params.keepOriginalName = 'true';
1055
+ }
1056
+ try {
1057
+ return await firstValueFrom(this.http.post(`${this.apiUrl}/upload-multiple`, formData, { params }));
1058
+ }
1059
+ catch (error) {
1060
+ console.error('Backend upload multiple files error:', error);
1061
+ return null;
1062
+ }
1063
+ }
1064
+ async deleteImage(imagePath) {
1065
+ // Implement delete if the backend controller supports it
1066
+ console.warn('Backend delete image not implemented yet');
1067
+ }
1068
+ async deleteDirectory(directoryPath) {
1069
+ // Implement delete directory if the backend controller supports it
1070
+ console.warn('Backend delete directory not implemented yet');
1071
+ }
1072
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: BackendStorageProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1073
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: BackendStorageProvider, providedIn: 'root' }); }
941
1074
  }
942
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: MultiObjectStorageService, decorators: [{
1075
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: BackendStorageProvider, decorators: [{
943
1076
  type: Injectable,
944
1077
  args: [{
945
1078
  providedIn: 'root',
946
1079
  }]
947
1080
  }] });
948
1081
 
1082
+ const STORAGE_PROVIDER_TYPE = new InjectionToken('STORAGE_PROVIDER_TYPE');
1083
+ class UniversalStorageService {
1084
+ constructor() {
1085
+ this.firebaseProvider = inject(FirebaseStorageProvider);
1086
+ this.backendProvider = inject(BackendStorageProvider);
1087
+ this.providerType = inject(STORAGE_PROVIDER_TYPE, { optional: true }) || 'FIREBASE';
1088
+ }
1089
+ get provider() {
1090
+ return this.providerType === 'BACKEND' ? this.backendProvider : this.firebaseProvider;
1091
+ }
1092
+ async uploadImage(image, path) {
1093
+ return this.provider.uploadImage(image, path);
1094
+ }
1095
+ uploadGenericFile(file, storagePath, metadata, keepOriginalName) {
1096
+ return this.provider.uploadGenericFile(file, storagePath, metadata, keepOriginalName);
1097
+ }
1098
+ uploadMultipleFiles(files, storagePath, metadata, keepOriginalName) {
1099
+ return this.provider.uploadMultipleFiles(files, storagePath, metadata, keepOriginalName);
1100
+ }
1101
+ async deleteImage(imagePath) {
1102
+ return this.provider.deleteImage(imagePath);
1103
+ }
1104
+ async deleteDirectory(directoryPath) {
1105
+ return this.provider.deleteDirectory(directoryPath);
1106
+ }
1107
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UniversalStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1108
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UniversalStorageService, providedIn: 'root' }); }
1109
+ }
1110
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UniversalStorageService, decorators: [{
1111
+ type: Injectable,
1112
+ args: [{
1113
+ providedIn: 'root',
1114
+ }]
1115
+ }] });
1116
+
1117
+ class BackendUploadComponent {
1118
+ constructor() {
1119
+ this.storageService = inject(UniversalStorageService);
1120
+ this.onUploadFinish = new EventEmitter();
1121
+ this.storagePath = 'test-uploads';
1122
+ this.keepOriginalNames = true;
1123
+ this.uploading = signal(false, ...(ngDevMode ? [{ debugName: "uploading" }] : []));
1124
+ this.status = signal(null, ...(ngDevMode ? [{ debugName: "status" }] : []));
1125
+ this.message = signal('', ...(ngDevMode ? [{ debugName: "message" }] : []));
1126
+ this.uploadedFileUrls = signal([], ...(ngDevMode ? [{ debugName: "uploadedFileUrls" }] : []));
1127
+ this.totalSize = signal(0, ...(ngDevMode ? [{ debugName: "totalSize" }] : []));
1128
+ this.totalSizePercent = signal(0, ...(ngDevMode ? [{ debugName: "totalSizePercent" }] : []));
1129
+ }
1130
+ async onUpload(event) {
1131
+ console.log('Upload event:', event);
1132
+ const files = event.files;
1133
+ if (!files || files.length === 0)
1134
+ return;
1135
+ this.uploading.set(true);
1136
+ this.status.set(null);
1137
+ this.message.set('Uploading...');
1138
+ try {
1139
+ // Group files by upload path to use multi-file upload where possible
1140
+ const groupedFiles = {};
1141
+ files.forEach(file => {
1142
+ let uploadPath = this.storagePath;
1143
+ if (file.webkitRelativePath) {
1144
+ const relativeDir = file.webkitRelativePath.substring(0, file.webkitRelativePath.lastIndexOf('/'));
1145
+ if (relativeDir) {
1146
+ uploadPath = `${this.storagePath}/${relativeDir}`;
1147
+ }
1148
+ }
1149
+ if (!groupedFiles[uploadPath]) {
1150
+ groupedFiles[uploadPath] = [];
1151
+ }
1152
+ groupedFiles[uploadPath].push(file);
1153
+ });
1154
+ const uploadPromises = Object.entries(groupedFiles).map(([path, pathFiles]) => {
1155
+ return this.storageService.uploadMultipleFiles(pathFiles, path, null, this.keepOriginalNames);
1156
+ });
1157
+ const results = await Promise.all(uploadPromises);
1158
+ const flattenedResults = results.flat().filter(result => result && result.url);
1159
+ const urls = flattenedResults.map(result => result.url);
1160
+ if (urls.length > 0) {
1161
+ this.status.set('success');
1162
+ this.message.set(`${urls.length} file(s) uploaded successfully!`);
1163
+ this.uploadedFileUrls.update(current => [...current, ...urls]);
1164
+ this.onUploadFinish.emit(flattenedResults);
1165
+ }
1166
+ else {
1167
+ throw new Error('Upload failed: No files were uploaded');
1168
+ }
1169
+ }
1170
+ catch (error) {
1171
+ console.error('Upload component error:', error);
1172
+ this.status.set('error');
1173
+ this.message.set(error.message || 'Error uploading files');
1174
+ }
1175
+ finally {
1176
+ this.uploading.set(false);
1177
+ }
1178
+ }
1179
+ onSelect(event) {
1180
+ console.log('Select event:', event);
1181
+ this.totalSize.set(0);
1182
+ event.currentFiles.forEach((file) => {
1183
+ this.totalSize.update(total => total + file.size);
1184
+ });
1185
+ this.totalSizePercent.set(Math.min((this.totalSize() / 10000000) * 100, 100)); // 10MB limit
1186
+ }
1187
+ onRemove(event) {
1188
+ this.totalSize.update(total => total - event.file.size);
1189
+ this.totalSizePercent.set(Math.min((this.totalSize() / 10000000) * 100, 100)); // 10MB limit
1190
+ }
1191
+ onClear() {
1192
+ this.totalSize.set(0);
1193
+ this.totalSizePercent.set(0);
1194
+ }
1195
+ choose(event, callback) {
1196
+ callback();
1197
+ }
1198
+ onFolderSelect(event) {
1199
+ const files = event.target.files;
1200
+ if (files && files.length > 0) {
1201
+ const fileList = Array.from(files);
1202
+ // Generate object URLs for preview
1203
+ fileList.forEach(file => {
1204
+ file.objectURL = URL.createObjectURL(file);
1205
+ });
1206
+ if (this.fileUpload) {
1207
+ this.fileUpload.files = [...this.fileUpload.files, ...fileList];
1208
+ // Let's also update our total size and UI signals
1209
+ this.onSelect({ currentFiles: this.fileUpload.files });
1210
+ }
1211
+ // Reset input value so same folder can be selected again
1212
+ event.target.value = '';
1213
+ }
1214
+ }
1215
+ formatSize(bytes) {
1216
+ if (bytes === 0)
1217
+ return '0 B';
1218
+ const k = 1024;
1219
+ const dm = 2;
1220
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
1221
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
1222
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
1223
+ }
1224
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: BackendUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1225
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: BackendUploadComponent, isStandalone: true, selector: "dc-backend-upload", inputs: { storagePath: "storagePath", keepOriginalNames: "keepOriginalNames" }, outputs: { onUploadFinish: "onUploadFinish" }, providers: [
1226
+ { provide: STORAGE_PROVIDER_TYPE, useValue: 'BACKEND' },
1227
+ UniversalStorageService
1228
+ ], viewQueries: [{ propertyName: "fileUpload", first: true, predicate: ["fu"], descendants: true }], ngImport: i0, template: "<div class=\"card p-4\">\n <p-toast />\n \n <p-fileupload \n #fu\n name=\"file\" \n [customUpload]=\"true\" \n (uploadHandler)=\"onUpload($event)\"\n (onSelect)=\"onSelect($event)\"\n (onRemove)=\"onRemove($event)\"\n (onClear)=\"onClear()\"\n [multiple]=\"true\" \n [maxFileSize]=\"10000000\" \n mode=\"advanced\">\n \n <ng-template #header let-files let-chooseCallback=\"chooseCallback\" let-clearCallback=\"clearCallback\" let-uploadCallback=\"uploadCallback\">\n <div class=\"flex flex-wrap justify-between items-center flex-1 gap-4\">\n <div class=\"flex gap-2\">\n <p-button (onClick)=\"choose($event, chooseCallback)\" icon=\"pi pi-plus\" [rounded]=\"true\" [outlined]=\"true\" label=\"Choose\" />\n <input #folderInput type=\"file\" webkitdirectory directory multiple style=\"display: none\" (change)=\"onFolderSelect($event)\">\n <p-button (onClick)=\"folderInput.click()\" icon=\"pi pi-folder-open\" [rounded]=\"true\" [outlined]=\"true\" label=\"Upload Folder\" severity=\"secondary\" />\n <p-button (onClick)=\"uploadCallback()\" icon=\"pi pi-cloud-upload\" [rounded]=\"true\" [outlined]=\"true\" severity=\"success\" [disabled]=\"!files || files.length === 0\" label=\"Upload\" />\n <p-button (onClick)=\"clearCallback()\" icon=\"pi pi-times\" [rounded]=\"true\" [outlined]=\"true\" severity=\"danger\" [disabled]=\"!files || files.length === 0\" label=\"Clear\" />\n </div>\n <div class=\"flex items-center gap-3 ml-auto\">\n <p-progressbar [value]=\"totalSizePercent()\" [showValue]=\"false\" class=\"w-full md:w-20rem h-1\">\n </p-progressbar>\n <span class=\"whitespace-nowrap text-sm text-secondary\">{{ formatSize(totalSize()) }} / 10MB</span>\n </div>\n </div>\n </ng-template>\n\n <ng-template #content let-files let-uploadedFiles=\"uploadedFiles\" let-removeFileCallback=\"removeFileCallback\" let-removeUploadedFileCallback=\"removeUploadedFileCallback\">\n <div class=\"flex flex-col gap-4 pt-4\">\n @if (files?.length > 0) {\n <div>\n <h5 class=\"mb-3 text-lg font-medium\">Pending Uploads</h5>\n <div class=\"flex flex-wrap gap-4\">\n @for (file of files; track file.name; let i = $index) {\n <div class=\"p-4 border rounded-lg border-surface-200 dark:border-surface-700 flex flex-col items-center gap-3 bg-surface-50 dark:bg-surface-900 w-48\">\n <div class=\"w-full h-24 flex items-center justify-center bg-surface-100 dark:bg-surface-800 rounded\">\n @if (file.objectURL) {\n <img role=\"presentation\" [alt]=\"file.name\" [src]=\"file.objectURL\" class=\"max-w-full max-h-full object-contain\" />\n } @else {\n <i class=\"pi pi-file text-4xl text-surface-400\"></i>\n }\n </div>\n <span class=\"font-semibold text-sm truncate w-full text-center\" [title]=\"file.webkitRelativePath || file.name\">\n {{ file.webkitRelativePath || file.name }}\n </span>\n <div class=\"text-xs text-secondary\">{{ formatSize(file.size) }}</div>\n <p-badge value=\"Pending\" severity=\"warn\" />\n <p-button icon=\"pi pi-times\" (onClick)=\"removeFileCallback($event, i)\" [outlined]=\"true\" [rounded]=\"true\" severity=\"danger\" size=\"small\" />\n </div>\n }\n </div>\n </div>\n }\n\n @if (uploadedFileUrls().length > 0) {\n <div class=\"mt-4\">\n <h5 class=\"mb-3 text-lg font-medium text-green-600\">Completed Uploads</h5>\n <div class=\"flex flex-wrap gap-4\">\n @for (url of uploadedFileUrls(); track url; let i = $index) {\n <div class=\"p-4 border rounded-lg border-green-200 dark:border-green-800 flex flex-col items-center gap-3 bg-green-50 dark:bg-green-900/20 w-48\">\n <div class=\"w-full h-24 flex items-center justify-center bg-surface-100 dark:bg-surface-800 rounded\">\n @if (url.toLowerCase().endsWith('.png') || url.toLowerCase().endsWith('.jpg') || url.toLowerCase().endsWith('.jpeg') || url.toLowerCase().endsWith('.webp')) {\n <img [src]=\"url\" class=\"max-w-full max-h-full object-contain\" />\n } @else {\n <i class=\"pi pi-check-circle text-4xl text-green-500\"></i>\n }\n </div>\n <span class=\"font-semibold text-sm truncate w-full text-center\">Uploaded File {{ i + 1 }}</span>\n <p-badge value=\"Completed\" severity=\"success\" />\n <a [href]=\"url\" target=\"_blank\" class=\"text-xs text-primary underline\">View File</a>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #empty>\n <div class=\"flex items-center justify-center flex-col py-8 border-2 border-dashed border-surface-300 dark:border-surface-600 rounded-xl bg-surface-50 dark:bg-surface-900/50\">\n <i class=\"pi pi-cloud-upload text-5xl text-surface-400 mb-4\"></i>\n <p class=\"text-surface-600 dark:text-surface-400 font-medium\">Drag and drop files here to upload</p>\n <p class=\"text-surface-500 dark:text-surface-500 text-sm\">Any file type up to 10MB</p>\n </div>\n </ng-template>\n </p-fileupload>\n\n @if (status()) {\n <div class=\"mt-4 p-3 rounded-lg flex items-center gap-3\" [ngClass]=\"status() === 'success' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'\">\n <i [class]=\"status() === 'success' ? 'pi pi-check-circle' : 'pi pi-exclamation-circle'\"></i>\n <span>{{ message() }}</span>\n </div>\n }\n</div>\n", styles: [":host{display:block;margin:1rem 0}.upload-container{padding:1rem;border:1px dashed #ccc;border-radius:8px}.status-message{margin-top:1rem;padding:.5rem;border-radius:4px}.status-message.success{background-color:#d4edda;color:#155724}.status-message.error{background-color:#f8d7da;color:#721c24}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i2$1.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i3$1.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "motionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: i4$1.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i5$1.Badge, selector: "p-badge", inputs: ["styleClass", "badgeSize", "size", "severity", "value", "badgeDisabled"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }] }); }
1229
+ }
1230
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: BackendUploadComponent, decorators: [{
1231
+ type: Component,
1232
+ args: [{ selector: 'dc-backend-upload', standalone: true, imports: [CommonModule, FileUploadModule, ToastModule, ProgressBarModule, BadgeModule, ButtonModule], providers: [
1233
+ { provide: STORAGE_PROVIDER_TYPE, useValue: 'BACKEND' },
1234
+ UniversalStorageService
1235
+ ], template: "<div class=\"card p-4\">\n <p-toast />\n \n <p-fileupload \n #fu\n name=\"file\" \n [customUpload]=\"true\" \n (uploadHandler)=\"onUpload($event)\"\n (onSelect)=\"onSelect($event)\"\n (onRemove)=\"onRemove($event)\"\n (onClear)=\"onClear()\"\n [multiple]=\"true\" \n [maxFileSize]=\"10000000\" \n mode=\"advanced\">\n \n <ng-template #header let-files let-chooseCallback=\"chooseCallback\" let-clearCallback=\"clearCallback\" let-uploadCallback=\"uploadCallback\">\n <div class=\"flex flex-wrap justify-between items-center flex-1 gap-4\">\n <div class=\"flex gap-2\">\n <p-button (onClick)=\"choose($event, chooseCallback)\" icon=\"pi pi-plus\" [rounded]=\"true\" [outlined]=\"true\" label=\"Choose\" />\n <input #folderInput type=\"file\" webkitdirectory directory multiple style=\"display: none\" (change)=\"onFolderSelect($event)\">\n <p-button (onClick)=\"folderInput.click()\" icon=\"pi pi-folder-open\" [rounded]=\"true\" [outlined]=\"true\" label=\"Upload Folder\" severity=\"secondary\" />\n <p-button (onClick)=\"uploadCallback()\" icon=\"pi pi-cloud-upload\" [rounded]=\"true\" [outlined]=\"true\" severity=\"success\" [disabled]=\"!files || files.length === 0\" label=\"Upload\" />\n <p-button (onClick)=\"clearCallback()\" icon=\"pi pi-times\" [rounded]=\"true\" [outlined]=\"true\" severity=\"danger\" [disabled]=\"!files || files.length === 0\" label=\"Clear\" />\n </div>\n <div class=\"flex items-center gap-3 ml-auto\">\n <p-progressbar [value]=\"totalSizePercent()\" [showValue]=\"false\" class=\"w-full md:w-20rem h-1\">\n </p-progressbar>\n <span class=\"whitespace-nowrap text-sm text-secondary\">{{ formatSize(totalSize()) }} / 10MB</span>\n </div>\n </div>\n </ng-template>\n\n <ng-template #content let-files let-uploadedFiles=\"uploadedFiles\" let-removeFileCallback=\"removeFileCallback\" let-removeUploadedFileCallback=\"removeUploadedFileCallback\">\n <div class=\"flex flex-col gap-4 pt-4\">\n @if (files?.length > 0) {\n <div>\n <h5 class=\"mb-3 text-lg font-medium\">Pending Uploads</h5>\n <div class=\"flex flex-wrap gap-4\">\n @for (file of files; track file.name; let i = $index) {\n <div class=\"p-4 border rounded-lg border-surface-200 dark:border-surface-700 flex flex-col items-center gap-3 bg-surface-50 dark:bg-surface-900 w-48\">\n <div class=\"w-full h-24 flex items-center justify-center bg-surface-100 dark:bg-surface-800 rounded\">\n @if (file.objectURL) {\n <img role=\"presentation\" [alt]=\"file.name\" [src]=\"file.objectURL\" class=\"max-w-full max-h-full object-contain\" />\n } @else {\n <i class=\"pi pi-file text-4xl text-surface-400\"></i>\n }\n </div>\n <span class=\"font-semibold text-sm truncate w-full text-center\" [title]=\"file.webkitRelativePath || file.name\">\n {{ file.webkitRelativePath || file.name }}\n </span>\n <div class=\"text-xs text-secondary\">{{ formatSize(file.size) }}</div>\n <p-badge value=\"Pending\" severity=\"warn\" />\n <p-button icon=\"pi pi-times\" (onClick)=\"removeFileCallback($event, i)\" [outlined]=\"true\" [rounded]=\"true\" severity=\"danger\" size=\"small\" />\n </div>\n }\n </div>\n </div>\n }\n\n @if (uploadedFileUrls().length > 0) {\n <div class=\"mt-4\">\n <h5 class=\"mb-3 text-lg font-medium text-green-600\">Completed Uploads</h5>\n <div class=\"flex flex-wrap gap-4\">\n @for (url of uploadedFileUrls(); track url; let i = $index) {\n <div class=\"p-4 border rounded-lg border-green-200 dark:border-green-800 flex flex-col items-center gap-3 bg-green-50 dark:bg-green-900/20 w-48\">\n <div class=\"w-full h-24 flex items-center justify-center bg-surface-100 dark:bg-surface-800 rounded\">\n @if (url.toLowerCase().endsWith('.png') || url.toLowerCase().endsWith('.jpg') || url.toLowerCase().endsWith('.jpeg') || url.toLowerCase().endsWith('.webp')) {\n <img [src]=\"url\" class=\"max-w-full max-h-full object-contain\" />\n } @else {\n <i class=\"pi pi-check-circle text-4xl text-green-500\"></i>\n }\n </div>\n <span class=\"font-semibold text-sm truncate w-full text-center\">Uploaded File {{ i + 1 }}</span>\n <p-badge value=\"Completed\" severity=\"success\" />\n <a [href]=\"url\" target=\"_blank\" class=\"text-xs text-primary underline\">View File</a>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #empty>\n <div class=\"flex items-center justify-center flex-col py-8 border-2 border-dashed border-surface-300 dark:border-surface-600 rounded-xl bg-surface-50 dark:bg-surface-900/50\">\n <i class=\"pi pi-cloud-upload text-5xl text-surface-400 mb-4\"></i>\n <p class=\"text-surface-600 dark:text-surface-400 font-medium\">Drag and drop files here to upload</p>\n <p class=\"text-surface-500 dark:text-surface-500 text-sm\">Any file type up to 10MB</p>\n </div>\n </ng-template>\n </p-fileupload>\n\n @if (status()) {\n <div class=\"mt-4 p-3 rounded-lg flex items-center gap-3\" [ngClass]=\"status() === 'success' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'\">\n <i [class]=\"status() === 'success' ? 'pi pi-check-circle' : 'pi pi-exclamation-circle'\"></i>\n <span>{{ message() }}</span>\n </div>\n }\n</div>\n", styles: [":host{display:block;margin:1rem 0}.upload-container{padding:1rem;border:1px dashed #ccc;border-radius:8px}.status-message{margin-top:1rem;padding:.5rem;border-radius:4px}.status-message.success{background-color:#d4edda;color:#155724}.status-message.error{background-color:#f8d7da;color:#721c24}\n"] }]
1236
+ }], propDecorators: { fileUpload: [{
1237
+ type: ViewChild,
1238
+ args: ['fu']
1239
+ }], onUploadFinish: [{
1240
+ type: Output
1241
+ }], storagePath: [{
1242
+ type: Input
1243
+ }], keepOriginalNames: [{
1244
+ type: Input
1245
+ }] } });
1246
+
949
1247
  class AssetsLoaderComponent {
950
1248
  constructor() {
951
1249
  this.assets = input.required(...(ngDevMode ? [{ debugName: "assets" }] : []));
@@ -1063,13 +1361,13 @@ class AssetsLoaderComponent {
1063
1361
  clearInterval(this.reverseInterval);
1064
1362
  }
1065
1363
  }
1066
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AssetsLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1067
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: AssetsLoaderComponent, isStandalone: true, selector: "assets-loader", inputs: { assets: { classPropertyName: "assets", publicName: "assets", isSignal: true, isRequired: true, transformFunction: null }, storagePath: { classPropertyName: "storagePath", publicName: "storagePath", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { assetsChange: "assetsChange", assetUpdate: "assetUpdate", onFileSelected: "onFileSelected" }, ngImport: i0, template: "<div class=\"assets-container\">\n <div class=\"assets-card\">\n <p-message severity=\"info\">\n <div class=\"upload-buttons\">\n <div>\n <dc-cropper-modal\n id=\"cropperCardImage\"\n #cropperCardImage\n [buttonLabel]=\"assets()?.image?.url ? 'Cambiar imagen' : 'Cargar una imagen'\"\n [imgStorageSettings]=\"imageStorageSettings()\"\n [currentStorage]=\"assets()?.image\"\n (imageUploaded)=\"onImageUploaded($event, 'image')\"\n (onFileSelected)=\"onFileSelected.emit($event)\"></dc-cropper-modal>\n </div>\n\n <dc-simple-uploader\n [buttonLabel]=\"assets()?.motion?.url ? 'Cambiar video principal' : 'Agregar video principal'\"\n (fileUploaded)=\"onMotionUploaded($event)\"\n [storagePath]=\"storagePath() + '/motions/file'\"\n [accept]=\"'video/*'\"></dc-simple-uploader>\n\n <dc-simple-uploader\n [buttonLabel]=\"'Agregar Movimientos'\"\n (fileUploaded)=\"onMotionAdded($event)\"\n [storagePath]=\"storagePath() + '/motions/file'\"\n [accept]=\"'video/*'\"></dc-simple-uploader>\n\n <dc-cropper-modal\n #cropperBanner\n id=\"cropperBanner\"\n [buttonLabel]=\"assets()?.banner?.url ? 'Cambiar el banner' : 'Cargar un banner'\"\n [imgStorageSettings]=\"bannerImgSettings()\"\n [currentStorage]=\"assets()?.banner\"\n (imageUploaded)=\"onImageUploaded($event, 'banner')\"></dc-cropper-modal>\n\n <dc-cropper-modal\n id=\"cropperStickers\"\n #cropperStickers\n [buttonLabel]=\"'Agregar sticker'\"\n [imgStorageSettings]=\"stickerStorageSettings()\"\n (imageUploaded)=\"onImageUploaded($event, 'sticker')\"></dc-cropper-modal>\n </div>\n </p-message>\n <!-- Banner -->\n\n <div class=\"preview-container\">\n <img [src]=\"assets()?.banner?.url || 'assets/defaults/images/default_banner.webp'\" class=\"main-banner-image-card\" />\n <div class=\"main-image-card\">\n <img [src]=\"assets()?.image?.url || 'assets/defaults/images/default_2_3.webp'\" />\n </div>\n\n <div class=\"motion-container\">\n <video #videoPlayer class=\"main-motion-card\" [src]=\"assets()?.motion?.url\" (ended)=\"onVideoEnded(videoPlayer)\" autoplay muted playsinline></video>\n @if(assets()?.motion?.url){\n <p-button class=\"remove-main-motion-button\" (click)=\"removeMainMotion()\" [rounded]=\"true\" [text]=\"true\" icon=\"pi pi-trash\" severity=\"danger\"></p-button>\n }\n </div>\n </div>\n\n <div class=\"stickers-container\">\n @for (sticker of assets()?.stickers; track sticker.url) {\n <div class=\"sticker-wrapper\">\n <img width=\"100\" [src]=\"sticker.url\" alt=\"\" />\n <p-button (click)=\"removeSticker(sticker)\" class=\"remove-sticker\" icon=\"pi pi-times\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" />\n </div>\n }\n </div>\n\n <div class=\"motions-container\">\n @for (motion of assets()?.motions; track motion.url) {\n <div class=\"motion-wrapper\">\n <video width=\"150\" [src]=\"motion.url\" controls playsinline preload=\"none\"></video>\n <p-button (click)=\"removeMotion(motion)\" class=\"remove-motion-button\" icon=\"pi pi-trash\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\"></p-button>\n @if(motion.metadata?.moodState){\n <p-tag style=\"position: absolute; top: 4px; left: 4px\" severity=\"secondary\" [value]=\"motion.metadata?.moodState\" />\n } @if(motion.metadata?.event){\n <p-tag style=\"position: absolute; top: 4px; left: 4px\" severity=\"warn\" [value]=\"motion.metadata?.event\" />\n }\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [".main-image-card{max-width:220px;display:block;border-radius:8px;position:absolute;bottom:-100px;left:20px;transform:none;z-index:1;box-shadow:0 4px 8px #0003;overflow:hidden}@media (max-width: 1300px){.main-image-card{max-width:170px}}@media (max-width: 768px){.main-image-card{max-width:130px}}.main-motion-card{max-width:100%;display:block;border-radius:8px}.main-banner-image-card{display:block;width:100%;max-height:400px;object-fit:cover;border-radius:8px}.remove-sticker{position:absolute;top:5px;right:5px}.assets-container{position:relative;min-height:60px}.assets-card{border:1px dashed rgba(12,19,142,.1215686275);padding:4px;border-radius:15px}.upload-buttons{display:flex;gap:10px}.preview-container{position:relative;margin-bottom:100px}.stickers-container{display:flex;flex-wrap:wrap;gap:10px}.sticker-wrapper{position:relative}.motion-container{position:absolute;bottom:-100px;right:20px;z-index:1;box-shadow:0 4px 8px #0003;max-width:220px;border-radius:8px;overflow:hidden}@media (max-width: 1300px){.motion-container{max-width:170px}}@media (max-width: 768px){.motion-container{max-width:130px}}.remove-main-motion-button{position:absolute;top:10px;right:10px;z-index:2}.motions-container{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px}.motion-wrapper{position:relative;width:150px;border-radius:8px;overflow:hidden;box-shadow:0 2px 4px #0000001a}.motion-wrapper video{min-height:220px;display:block;background-color:#f0f0f0}.remove-motion-button{position:absolute;top:5px;right:5px;z-index:2}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "component", type: SimpleUploaderComponent, selector: "dc-simple-uploader", inputs: ["storagePath", "buttonLabel", "accept", "disabled", "metadata"], outputs: ["fileUploaded", "uploadError"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i5.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i3$1.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }] }); }
1364
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AssetsLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1365
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: AssetsLoaderComponent, isStandalone: true, selector: "assets-loader", inputs: { assets: { classPropertyName: "assets", publicName: "assets", isSignal: true, isRequired: true, transformFunction: null }, storagePath: { classPropertyName: "storagePath", publicName: "storagePath", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { assetsChange: "assetsChange", assetUpdate: "assetUpdate", onFileSelected: "onFileSelected" }, ngImport: i0, template: "<div class=\"assets-container\">\n <div class=\"assets-card\">\n <p-message severity=\"info\">\n <div class=\"upload-buttons\">\n <div>\n <dc-cropper-modal\n id=\"cropperCardImage\"\n #cropperCardImage\n [buttonLabel]=\"assets()?.image?.url ? 'Cambiar imagen' : 'Cargar una imagen'\"\n [imgStorageSettings]=\"imageStorageSettings()\"\n [currentStorage]=\"assets()?.image\"\n (imageUploaded)=\"onImageUploaded($event, 'image')\"\n (onFileSelected)=\"onFileSelected.emit($event)\"></dc-cropper-modal>\n </div>\n\n <dc-simple-uploader\n [buttonLabel]=\"assets()?.motion?.url ? 'Cambiar video principal' : 'Agregar video principal'\"\n (fileUploaded)=\"onMotionUploaded($event)\"\n [storagePath]=\"storagePath() + '/motions/file'\"\n [accept]=\"'video/*'\"></dc-simple-uploader>\n\n <dc-simple-uploader\n [buttonLabel]=\"'Agregar Movimientos'\"\n (fileUploaded)=\"onMotionAdded($event)\"\n [storagePath]=\"storagePath() + '/motions/file'\"\n [accept]=\"'video/*'\"></dc-simple-uploader>\n\n <dc-cropper-modal\n #cropperBanner\n id=\"cropperBanner\"\n [buttonLabel]=\"assets()?.banner?.url ? 'Cambiar el banner' : 'Cargar un banner'\"\n [imgStorageSettings]=\"bannerImgSettings()\"\n [currentStorage]=\"assets()?.banner\"\n (imageUploaded)=\"onImageUploaded($event, 'banner')\"></dc-cropper-modal>\n\n <dc-cropper-modal\n id=\"cropperStickers\"\n #cropperStickers\n [buttonLabel]=\"'Agregar sticker'\"\n [imgStorageSettings]=\"stickerStorageSettings()\"\n (imageUploaded)=\"onImageUploaded($event, 'sticker')\"></dc-cropper-modal>\n </div>\n </p-message>\n <!-- Banner -->\n\n <div class=\"preview-container\">\n <img [src]=\"assets()?.banner?.url || 'defaults/images/default_banner.webp'\" class=\"main-banner-image-card\" />\n <div class=\"main-image-card\">\n <img [src]=\"assets()?.image?.url || 'defaults/images/default_2_3.webp'\" />\n </div>\n\n <div class=\"motion-container\">\n <video #videoPlayer class=\"main-motion-card\" [src]=\"assets()?.motion?.url\" (ended)=\"onVideoEnded(videoPlayer)\" autoplay muted playsinline></video>\n @if(assets()?.motion?.url){\n <p-button class=\"remove-main-motion-button\" (click)=\"removeMainMotion()\" [rounded]=\"true\" [text]=\"true\" icon=\"pi pi-trash\" severity=\"danger\"></p-button>\n }\n </div>\n </div>\n\n <div class=\"stickers-container\">\n @for (sticker of assets()?.stickers; track sticker.url) {\n <div class=\"sticker-wrapper\">\n <img width=\"100\" [src]=\"sticker.url\" alt=\"\" />\n <p-button (click)=\"removeSticker(sticker)\" class=\"remove-sticker\" icon=\"pi pi-times\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" />\n </div>\n }\n </div>\n\n <div class=\"motions-container\">\n @for (motion of assets()?.motions; track motion.url) {\n <div class=\"motion-wrapper\">\n <video width=\"150\" [src]=\"motion.url\" controls playsinline preload=\"none\"></video>\n <p-button (click)=\"removeMotion(motion)\" class=\"remove-motion-button\" icon=\"pi pi-trash\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\"></p-button>\n @if(motion.metadata?.moodState){\n <p-tag style=\"position: absolute; top: 4px; left: 4px\" severity=\"secondary\" [value]=\"motion.metadata?.moodState\" />\n } @if(motion.metadata?.event){\n <p-tag style=\"position: absolute; top: 4px; left: 4px\" severity=\"warn\" [value]=\"motion.metadata?.event\" />\n }\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [".main-image-card{max-width:220px;display:block;border-radius:8px;position:absolute;bottom:-100px;left:20px;transform:none;z-index:1;box-shadow:0 4px 8px #0003;overflow:hidden}@media(max-width:1300px){.main-image-card{max-width:170px}}@media(max-width:768px){.main-image-card{max-width:130px}}.main-motion-card{max-width:100%;display:block;border-radius:8px}.main-banner-image-card{display:block;width:100%;max-height:400px;object-fit:cover;border-radius:8px}.remove-sticker{position:absolute;top:5px;right:5px}.assets-container{position:relative;min-height:60px}.assets-card{border:1px dashed rgba(12,19,142,.1215686275);padding:4px;border-radius:15px}.upload-buttons{display:flex;gap:10px}.preview-container{position:relative;margin-bottom:100px}.stickers-container{display:flex;flex-wrap:wrap;gap:10px}.sticker-wrapper{position:relative}.motion-container{position:absolute;bottom:-100px;right:20px;z-index:1;box-shadow:0 4px 8px #0003;max-width:220px;border-radius:8px;overflow:hidden}@media(max-width:1300px){.motion-container{max-width:170px}}@media(max-width:768px){.motion-container{max-width:130px}}.remove-main-motion-button{position:absolute;top:10px;right:10px;z-index:2}.motions-container{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px}.motion-wrapper{position:relative;width:150px;border-radius:8px;overflow:hidden;box-shadow:0 2px 4px #0000001a}.motion-wrapper video{min-height:220px;display:block;background-color:#f0f0f0}.remove-motion-button{position:absolute;top:5px;right:5px;z-index:2}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "component", type: SimpleUploaderComponent, selector: "dc-simple-uploader", inputs: ["storagePath", "buttonLabel", "accept", "disabled", "metadata"], outputs: ["fileUploaded", "uploadError"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i6.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant", "motionOptions"], outputs: ["onClose"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i3$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }] }); }
1068
1366
  }
1069
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: AssetsLoaderComponent, decorators: [{
1367
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AssetsLoaderComponent, decorators: [{
1070
1368
  type: Component,
1071
- args: [{ selector: 'assets-loader', standalone: true, imports: [CommonModule, CropperComponentModal, SimpleUploaderComponent, ButtonModule, MessageModule, TagModule], template: "<div class=\"assets-container\">\n <div class=\"assets-card\">\n <p-message severity=\"info\">\n <div class=\"upload-buttons\">\n <div>\n <dc-cropper-modal\n id=\"cropperCardImage\"\n #cropperCardImage\n [buttonLabel]=\"assets()?.image?.url ? 'Cambiar imagen' : 'Cargar una imagen'\"\n [imgStorageSettings]=\"imageStorageSettings()\"\n [currentStorage]=\"assets()?.image\"\n (imageUploaded)=\"onImageUploaded($event, 'image')\"\n (onFileSelected)=\"onFileSelected.emit($event)\"></dc-cropper-modal>\n </div>\n\n <dc-simple-uploader\n [buttonLabel]=\"assets()?.motion?.url ? 'Cambiar video principal' : 'Agregar video principal'\"\n (fileUploaded)=\"onMotionUploaded($event)\"\n [storagePath]=\"storagePath() + '/motions/file'\"\n [accept]=\"'video/*'\"></dc-simple-uploader>\n\n <dc-simple-uploader\n [buttonLabel]=\"'Agregar Movimientos'\"\n (fileUploaded)=\"onMotionAdded($event)\"\n [storagePath]=\"storagePath() + '/motions/file'\"\n [accept]=\"'video/*'\"></dc-simple-uploader>\n\n <dc-cropper-modal\n #cropperBanner\n id=\"cropperBanner\"\n [buttonLabel]=\"assets()?.banner?.url ? 'Cambiar el banner' : 'Cargar un banner'\"\n [imgStorageSettings]=\"bannerImgSettings()\"\n [currentStorage]=\"assets()?.banner\"\n (imageUploaded)=\"onImageUploaded($event, 'banner')\"></dc-cropper-modal>\n\n <dc-cropper-modal\n id=\"cropperStickers\"\n #cropperStickers\n [buttonLabel]=\"'Agregar sticker'\"\n [imgStorageSettings]=\"stickerStorageSettings()\"\n (imageUploaded)=\"onImageUploaded($event, 'sticker')\"></dc-cropper-modal>\n </div>\n </p-message>\n <!-- Banner -->\n\n <div class=\"preview-container\">\n <img [src]=\"assets()?.banner?.url || 'assets/defaults/images/default_banner.webp'\" class=\"main-banner-image-card\" />\n <div class=\"main-image-card\">\n <img [src]=\"assets()?.image?.url || 'assets/defaults/images/default_2_3.webp'\" />\n </div>\n\n <div class=\"motion-container\">\n <video #videoPlayer class=\"main-motion-card\" [src]=\"assets()?.motion?.url\" (ended)=\"onVideoEnded(videoPlayer)\" autoplay muted playsinline></video>\n @if(assets()?.motion?.url){\n <p-button class=\"remove-main-motion-button\" (click)=\"removeMainMotion()\" [rounded]=\"true\" [text]=\"true\" icon=\"pi pi-trash\" severity=\"danger\"></p-button>\n }\n </div>\n </div>\n\n <div class=\"stickers-container\">\n @for (sticker of assets()?.stickers; track sticker.url) {\n <div class=\"sticker-wrapper\">\n <img width=\"100\" [src]=\"sticker.url\" alt=\"\" />\n <p-button (click)=\"removeSticker(sticker)\" class=\"remove-sticker\" icon=\"pi pi-times\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" />\n </div>\n }\n </div>\n\n <div class=\"motions-container\">\n @for (motion of assets()?.motions; track motion.url) {\n <div class=\"motion-wrapper\">\n <video width=\"150\" [src]=\"motion.url\" controls playsinline preload=\"none\"></video>\n <p-button (click)=\"removeMotion(motion)\" class=\"remove-motion-button\" icon=\"pi pi-trash\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\"></p-button>\n @if(motion.metadata?.moodState){\n <p-tag style=\"position: absolute; top: 4px; left: 4px\" severity=\"secondary\" [value]=\"motion.metadata?.moodState\" />\n } @if(motion.metadata?.event){\n <p-tag style=\"position: absolute; top: 4px; left: 4px\" severity=\"warn\" [value]=\"motion.metadata?.event\" />\n }\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [".main-image-card{max-width:220px;display:block;border-radius:8px;position:absolute;bottom:-100px;left:20px;transform:none;z-index:1;box-shadow:0 4px 8px #0003;overflow:hidden}@media (max-width: 1300px){.main-image-card{max-width:170px}}@media (max-width: 768px){.main-image-card{max-width:130px}}.main-motion-card{max-width:100%;display:block;border-radius:8px}.main-banner-image-card{display:block;width:100%;max-height:400px;object-fit:cover;border-radius:8px}.remove-sticker{position:absolute;top:5px;right:5px}.assets-container{position:relative;min-height:60px}.assets-card{border:1px dashed rgba(12,19,142,.1215686275);padding:4px;border-radius:15px}.upload-buttons{display:flex;gap:10px}.preview-container{position:relative;margin-bottom:100px}.stickers-container{display:flex;flex-wrap:wrap;gap:10px}.sticker-wrapper{position:relative}.motion-container{position:absolute;bottom:-100px;right:20px;z-index:1;box-shadow:0 4px 8px #0003;max-width:220px;border-radius:8px;overflow:hidden}@media (max-width: 1300px){.motion-container{max-width:170px}}@media (max-width: 768px){.motion-container{max-width:130px}}.remove-main-motion-button{position:absolute;top:10px;right:10px;z-index:2}.motions-container{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px}.motion-wrapper{position:relative;width:150px;border-radius:8px;overflow:hidden;box-shadow:0 2px 4px #0000001a}.motion-wrapper video{min-height:220px;display:block;background-color:#f0f0f0}.remove-motion-button{position:absolute;top:5px;right:5px;z-index:2}\n"] }]
1072
- }] });
1369
+ args: [{ selector: 'assets-loader', standalone: true, imports: [CommonModule, CropperComponentModal, SimpleUploaderComponent, ButtonModule, MessageModule, TagModule], template: "<div class=\"assets-container\">\n <div class=\"assets-card\">\n <p-message severity=\"info\">\n <div class=\"upload-buttons\">\n <div>\n <dc-cropper-modal\n id=\"cropperCardImage\"\n #cropperCardImage\n [buttonLabel]=\"assets()?.image?.url ? 'Cambiar imagen' : 'Cargar una imagen'\"\n [imgStorageSettings]=\"imageStorageSettings()\"\n [currentStorage]=\"assets()?.image\"\n (imageUploaded)=\"onImageUploaded($event, 'image')\"\n (onFileSelected)=\"onFileSelected.emit($event)\"></dc-cropper-modal>\n </div>\n\n <dc-simple-uploader\n [buttonLabel]=\"assets()?.motion?.url ? 'Cambiar video principal' : 'Agregar video principal'\"\n (fileUploaded)=\"onMotionUploaded($event)\"\n [storagePath]=\"storagePath() + '/motions/file'\"\n [accept]=\"'video/*'\"></dc-simple-uploader>\n\n <dc-simple-uploader\n [buttonLabel]=\"'Agregar Movimientos'\"\n (fileUploaded)=\"onMotionAdded($event)\"\n [storagePath]=\"storagePath() + '/motions/file'\"\n [accept]=\"'video/*'\"></dc-simple-uploader>\n\n <dc-cropper-modal\n #cropperBanner\n id=\"cropperBanner\"\n [buttonLabel]=\"assets()?.banner?.url ? 'Cambiar el banner' : 'Cargar un banner'\"\n [imgStorageSettings]=\"bannerImgSettings()\"\n [currentStorage]=\"assets()?.banner\"\n (imageUploaded)=\"onImageUploaded($event, 'banner')\"></dc-cropper-modal>\n\n <dc-cropper-modal\n id=\"cropperStickers\"\n #cropperStickers\n [buttonLabel]=\"'Agregar sticker'\"\n [imgStorageSettings]=\"stickerStorageSettings()\"\n (imageUploaded)=\"onImageUploaded($event, 'sticker')\"></dc-cropper-modal>\n </div>\n </p-message>\n <!-- Banner -->\n\n <div class=\"preview-container\">\n <img [src]=\"assets()?.banner?.url || 'defaults/images/default_banner.webp'\" class=\"main-banner-image-card\" />\n <div class=\"main-image-card\">\n <img [src]=\"assets()?.image?.url || 'defaults/images/default_2_3.webp'\" />\n </div>\n\n <div class=\"motion-container\">\n <video #videoPlayer class=\"main-motion-card\" [src]=\"assets()?.motion?.url\" (ended)=\"onVideoEnded(videoPlayer)\" autoplay muted playsinline></video>\n @if(assets()?.motion?.url){\n <p-button class=\"remove-main-motion-button\" (click)=\"removeMainMotion()\" [rounded]=\"true\" [text]=\"true\" icon=\"pi pi-trash\" severity=\"danger\"></p-button>\n }\n </div>\n </div>\n\n <div class=\"stickers-container\">\n @for (sticker of assets()?.stickers; track sticker.url) {\n <div class=\"sticker-wrapper\">\n <img width=\"100\" [src]=\"sticker.url\" alt=\"\" />\n <p-button (click)=\"removeSticker(sticker)\" class=\"remove-sticker\" icon=\"pi pi-times\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" />\n </div>\n }\n </div>\n\n <div class=\"motions-container\">\n @for (motion of assets()?.motions; track motion.url) {\n <div class=\"motion-wrapper\">\n <video width=\"150\" [src]=\"motion.url\" controls playsinline preload=\"none\"></video>\n <p-button (click)=\"removeMotion(motion)\" class=\"remove-motion-button\" icon=\"pi pi-trash\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\"></p-button>\n @if(motion.metadata?.moodState){\n <p-tag style=\"position: absolute; top: 4px; left: 4px\" severity=\"secondary\" [value]=\"motion.metadata?.moodState\" />\n } @if(motion.metadata?.event){\n <p-tag style=\"position: absolute; top: 4px; left: 4px\" severity=\"warn\" [value]=\"motion.metadata?.event\" />\n }\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [".main-image-card{max-width:220px;display:block;border-radius:8px;position:absolute;bottom:-100px;left:20px;transform:none;z-index:1;box-shadow:0 4px 8px #0003;overflow:hidden}@media(max-width:1300px){.main-image-card{max-width:170px}}@media(max-width:768px){.main-image-card{max-width:130px}}.main-motion-card{max-width:100%;display:block;border-radius:8px}.main-banner-image-card{display:block;width:100%;max-height:400px;object-fit:cover;border-radius:8px}.remove-sticker{position:absolute;top:5px;right:5px}.assets-container{position:relative;min-height:60px}.assets-card{border:1px dashed rgba(12,19,142,.1215686275);padding:4px;border-radius:15px}.upload-buttons{display:flex;gap:10px}.preview-container{position:relative;margin-bottom:100px}.stickers-container{display:flex;flex-wrap:wrap;gap:10px}.sticker-wrapper{position:relative}.motion-container{position:absolute;bottom:-100px;right:20px;z-index:1;box-shadow:0 4px 8px #0003;max-width:220px;border-radius:8px;overflow:hidden}@media(max-width:1300px){.motion-container{max-width:170px}}@media(max-width:768px){.motion-container{max-width:130px}}.remove-main-motion-button{position:absolute;top:10px;right:10px;z-index:2}.motions-container{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px}.motion-wrapper{position:relative;width:150px;border-radius:8px;overflow:hidden;box-shadow:0 2px 4px #0000001a}.motion-wrapper video{min-height:220px;display:block;background-color:#f0f0f0}.remove-motion-button{position:absolute;top:5px;right:5px;z-index:2}\n"] }]
1370
+ }], propDecorators: { assets: [{ type: i0.Input, args: [{ isSignal: true, alias: "assets", required: true }] }], storagePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "storagePath", required: true }] }], assetsChange: [{ type: i0.Output, args: ["assetsChange"] }], assetUpdate: [{ type: i0.Output, args: ["assetUpdate"] }], onFileSelected: [{ type: i0.Output, args: ["onFileSelected"] }] } });
1073
1371
 
1074
1372
  /*
1075
1373
  * Public API Surface of storage-uploader
@@ -1079,5 +1377,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
1079
1377
  * Generated bundle index. Do not edit.
1080
1378
  */
1081
1379
 
1082
- export { AllAspectRatioOptions, AspectRatio, AspectRatioOptions, AspectType, AssetsLoaderComponent, CropperComponent, CropperComponentModal, DCFilesCacheService, DEFAULT_SETTINGS, ImageStoragePreviewComponent, MultiImagesStorageService, MultiObjectStorageService, ResolutionType, SafeHtmlPipe, SimpleUploaderComponent, extractBucket, extractPath };
1380
+ export { AllAspectRatioOptions, AspectRatio, AspectRatioOptions, AspectType, AssetsLoaderComponent, BackendUploadComponent, CropperComponent, CropperComponentModal, DCFilesCacheService, DEFAULT_SETTINGS, ImageStoragePreviewComponent, MultiImagesStorageService, MultiObjectStorageService, ResolutionType, STORAGE_PROVIDER_TYPE, SafeHtmlPipe, SimpleUploaderComponent, UniversalStorageService, extractBucket, extractPath };
1083
1381
  //# sourceMappingURL=dataclouder-ngx-cloud-storage.mjs.map