cloud-ide-element 1.0.93 → 1.0.96

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.
@@ -2600,6 +2600,7 @@ class ICoreCyfmSave {
2600
2600
  cyfm_file_status_sygmt;
2601
2601
  cyfm_group_id; // Group ID for multiple file uploads
2602
2602
  cyfm_isactive;
2603
+ cyfm_ismultiple;
2603
2604
  cyfm_file_base64 = "";
2604
2605
  cyfm_temp_unique_id = "";
2605
2606
  constructor(init) {
@@ -2719,6 +2720,7 @@ class CideEleFileManagerService {
2719
2720
  cyfm_file_status_sygmt: uploadOptions?.fileStatus || 'file_manager_file_status_active',
2720
2721
  cyfm_group_id: uploadOptions?.groupId, // Group ID for multiple file uploads
2721
2722
  cyfm_isactive: true,
2723
+ cyfm_ismultiple: uploadOptions?.isMultiple || false,
2722
2724
  cyfm_file_base64: base64Data,
2723
2725
  cyfm_temp_unique_id: fileId
2724
2726
  };
@@ -2945,6 +2947,22 @@ class CideEleFileManagerService {
2945
2947
  getFetchedFilesByGroupId(groupId) {
2946
2948
  return this._fetchedFiles().get(groupId) || [];
2947
2949
  }
2950
+ /**
2951
+ * Signal to trigger floating uploader visibility
2952
+ */
2953
+ _showFloatingUploader = signal(false, ...(ngDevMode ? [{ debugName: "_showFloatingUploader" }] : []));
2954
+ showFloatingUploader = this._showFloatingUploader.asReadonly();
2955
+ /**
2956
+ * Trigger floating uploader to show
2957
+ */
2958
+ triggerFloatingUploaderShow() {
2959
+ console.log('🎬 [FileManagerService] Triggering floating uploader to show');
2960
+ this._showFloatingUploader.set(true);
2961
+ // Reset after a short delay to allow components to react
2962
+ setTimeout(() => {
2963
+ this._showFloatingUploader.set(false);
2964
+ }, 100);
2965
+ }
2948
2966
  /**
2949
2967
  * Get all files (active uploads + fetched files) for a group ID
2950
2968
  * @param groupId The group ID to get files for
@@ -3281,8 +3299,16 @@ class CideEleFloatingFileUploaderComponent {
3281
3299
  failedUploads = computed(() => Array.from(this.activeUploads().values()).filter(upload => upload.stage === 'error'), ...(ngDevMode ? [{ debugName: "failedUploads" }] : []));
3282
3300
  // Animation states
3283
3301
  isAnimating = signal(false, ...(ngDevMode ? [{ debugName: "isAnimating" }] : []));
3302
+ // Drag functionality
3303
+ isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
3304
+ position = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "position" }] : []));
3305
+ dragOffset = { x: 0, y: 0 };
3306
+ // File drag and drop functionality
3307
+ isDragOver = signal(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : []));
3284
3308
  constructor() {
3285
3309
  console.log('🚀 [FloatingFileUploader] Component initialized');
3310
+ // Initialize default position
3311
+ this.initializePosition();
3286
3312
  // Set up effect to show/hide floating uploader based on service state
3287
3313
  effect(() => {
3288
3314
  const hasActiveUploads = this.hasActiveUploads();
@@ -3300,6 +3326,14 @@ class CideEleFloatingFileUploaderComponent {
3300
3326
  this.showWithAnimation();
3301
3327
  }
3302
3328
  });
3329
+ // Set up effect to listen for manual show trigger from service
3330
+ effect(() => {
3331
+ const shouldShow = this.fileManagerService.showFloatingUploader();
3332
+ if (shouldShow && !this.isVisible()) {
3333
+ console.log('👁️ [FloatingFileUploader] Showing floating uploader due to service trigger');
3334
+ this.showWithAnimation();
3335
+ }
3336
+ });
3303
3337
  }
3304
3338
  ngOnInit() {
3305
3339
  // Set up drag and drop listeners
@@ -3614,13 +3648,20 @@ class CideEleFloatingFileUploaderComponent {
3614
3648
  .subscribe({
3615
3649
  next: (files) => {
3616
3650
  console.log('✅ [FloatingFileUploader] Files fetched and stored:', files.length);
3651
+ // Force show the uploader after files are loaded
3652
+ this.showWithAnimation();
3617
3653
  },
3618
3654
  error: (error) => {
3619
3655
  console.error('❌ [FloatingFileUploader] Failed to fetch files:', error);
3656
+ // Still show the uploader even if fetch fails
3657
+ this.showWithAnimation();
3620
3658
  }
3621
3659
  });
3622
3660
  }
3623
- this.showWithAnimation();
3661
+ else {
3662
+ // Show immediately if no group ID
3663
+ this.showWithAnimation();
3664
+ }
3624
3665
  }
3625
3666
  /**
3626
3667
  * Check if there are any uploads for the current group
@@ -3635,15 +3676,154 @@ class CideEleFloatingFileUploaderComponent {
3635
3676
  // Note: This would need to be enhanced based on how group IDs are stored in the file manager service
3636
3677
  return this.hasUploads();
3637
3678
  }
3679
+ /**
3680
+ * Handle drag over event for file drop
3681
+ */
3682
+ onDragOver(event) {
3683
+ event.preventDefault();
3684
+ event.stopPropagation();
3685
+ this.isDragOver.set(true);
3686
+ }
3687
+ /**
3688
+ * Handle drag leave event for file drop
3689
+ */
3690
+ onDragLeave(event) {
3691
+ event.preventDefault();
3692
+ event.stopPropagation();
3693
+ this.isDragOver.set(false);
3694
+ }
3695
+ /**
3696
+ * Handle drop event for file drop
3697
+ */
3698
+ onDrop(event) {
3699
+ event.preventDefault();
3700
+ event.stopPropagation();
3701
+ this.isDragOver.set(false);
3702
+ const files = event.dataTransfer?.files;
3703
+ if (files && files.length > 0) {
3704
+ this.handleFileSelection(Array.from(files));
3705
+ }
3706
+ }
3707
+ /**
3708
+ * Trigger file input click
3709
+ */
3710
+ triggerFileInput() {
3711
+ const fileInput = document.querySelector('input[type="file"]');
3712
+ if (fileInput) {
3713
+ fileInput.click();
3714
+ }
3715
+ }
3716
+ /**
3717
+ * Handle file input change
3718
+ */
3719
+ onFileInputChange(event) {
3720
+ const input = event.target;
3721
+ if (input.files && input.files.length > 0) {
3722
+ this.handleFileSelection(Array.from(input.files));
3723
+ input.value = ''; // Reset input
3724
+ }
3725
+ }
3726
+ /**
3727
+ * Handle file selection from drag/drop or file input
3728
+ */
3729
+ handleFileSelection(files) {
3730
+ console.log('📁 [FloatingFileUploader] Files selected:', files.map(f => f.name));
3731
+ const groupId = this.currentGroupId() || this.generateGroupId();
3732
+ this.currentGroupId.set(groupId);
3733
+ // Upload files using the file manager service
3734
+ files.forEach(file => {
3735
+ this.fileManagerService.uploadFile(file, {
3736
+ groupId: groupId,
3737
+ isMultiple: true,
3738
+ userId: this.currentUserId()
3739
+ });
3740
+ });
3741
+ }
3742
+ /**
3743
+ * Generate a unique group ID
3744
+ */
3745
+ generateGroupId() {
3746
+ return `group_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
3747
+ }
3748
+ /**
3749
+ * Start dragging the uploader
3750
+ */
3751
+ startDrag(event) {
3752
+ event.preventDefault();
3753
+ const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
3754
+ const clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;
3755
+ const currentPos = this.position();
3756
+ this.dragOffset = {
3757
+ x: clientX - currentPos.x,
3758
+ y: clientY - currentPos.y
3759
+ };
3760
+ this.isDragging.set(true);
3761
+ // Add event listeners for drag and end
3762
+ const moveHandler = (e) => this.onDrag(e);
3763
+ const endHandler = () => this.endDrag(moveHandler, endHandler);
3764
+ document.addEventListener('mousemove', moveHandler);
3765
+ document.addEventListener('mouseup', endHandler);
3766
+ document.addEventListener('touchmove', moveHandler);
3767
+ document.addEventListener('touchend', endHandler);
3768
+ // Prevent text selection during drag
3769
+ document.body.style.userSelect = 'none';
3770
+ }
3771
+ /**
3772
+ * Handle dragging movement
3773
+ */
3774
+ onDrag(event) {
3775
+ if (!this.isDragging())
3776
+ return;
3777
+ event.preventDefault();
3778
+ const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
3779
+ const clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;
3780
+ const newX = clientX - this.dragOffset.x;
3781
+ const newY = clientY - this.dragOffset.y;
3782
+ // Constrain to viewport bounds
3783
+ const viewportWidth = window.innerWidth;
3784
+ const viewportHeight = window.innerHeight;
3785
+ const uploaderWidth = 320; // From CSS
3786
+ const uploaderHeight = 500; // Max height from CSS
3787
+ const constrainedX = Math.max(0, Math.min(newX, viewportWidth - uploaderWidth));
3788
+ const constrainedY = Math.max(0, Math.min(newY, viewportHeight - uploaderHeight));
3789
+ this.position.set({ x: constrainedX, y: constrainedY });
3790
+ }
3791
+ /**
3792
+ * End dragging
3793
+ */
3794
+ endDrag(moveHandler, endHandler) {
3795
+ this.isDragging.set(false);
3796
+ // Remove event listeners
3797
+ document.removeEventListener('mousemove', moveHandler);
3798
+ document.removeEventListener('mouseup', endHandler);
3799
+ document.removeEventListener('touchmove', moveHandler);
3800
+ document.removeEventListener('touchend', endHandler);
3801
+ // Restore text selection
3802
+ document.body.style.userSelect = '';
3803
+ }
3804
+ /**
3805
+ * Initialize default position
3806
+ */
3807
+ initializePosition() {
3808
+ // Set initial position to bottom-right corner
3809
+ const viewportWidth = window.innerWidth;
3810
+ const viewportHeight = window.innerHeight;
3811
+ const uploaderWidth = 320;
3812
+ const uploaderHeight = 500;
3813
+ this.position.set({
3814
+ x: viewportWidth - uploaderWidth - 20,
3815
+ y: viewportHeight - uploaderHeight - 20
3816
+ });
3817
+ }
3638
3818
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingFileUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3639
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFloatingFileUploaderComponent, isStandalone: true, selector: "cide-ele-floating-file-uploader", ngImport: i0, template: "<!-- Floating File Uploader Container -->\n@if (isVisible()) {\n<div class=\"floating-uploader\" \n [class.minimized]=\"isMinimized()\" \n [class.animating]=\"isAnimating()\">\n\n <!-- Header -->\n <div class=\"uploader-header\">\n <div class=\"header-left\">\n <div class=\"upload-icon\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n </div>\n <div class=\"upload-info\">\n <div class=\"upload-title\">File Upload</div>\n <div class=\"upload-summary\">{{ getUploadSummary() }}</div>\n </div>\n </div>\n \n <div class=\"header-actions\">\n <button class=\"action-btn minimize-btn\" (click)=\"toggleMinimize()\" [title]=\"isMinimized() ? 'Expand' : 'Minimize'\">\n <cide-ele-icon size=\"xs\">{{ isMinimized() ? 'expand_more' : 'expand_less' }}</cide-ele-icon>\n </button>\n <button class=\"action-btn close-btn\" (click)=\"close()\" title=\"Close\">\n <cide-ele-icon size=\"xs\">close</cide-ele-icon>\n </button>\n </div>\n </div>\n\n <!-- Content (hidden when minimized) -->\n @if (!isMinimized()) {\n <div class=\"uploader-content\">\n \n <!-- Overall Progress Bar - Fixed at top -->\n @if (uploadQueue().length > 0 || activeUploads().size > 0) {\n <div class=\"overall-progress sticky-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"getOverallProgress()\"></div>\n </div>\n <div class=\"progress-text\">{{ getOverallProgress() }}%</div>\n </div>\n }\n\n <!-- Upload Queue - Show files from service state -->\n @if (getAllFiles().length > 0) {\n <div class=\"upload-queue\">\n <!-- Show all files from service state -->\n @for (file of getAllFiles(); track file.fileId) {\n <div class=\"upload-item\" [class]=\"getStatusClass(file.stage)\">\n <div class=\"file-info\">\n <cide-ele-icon class=\"status-icon\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"file-details\">\n <div class=\"file-name\">{{ file.fileName }}</div>\n <div class=\"file-status\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"text-yellow-600\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"text-yellow-600\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"text-blue-600\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"text-green-600\">Completed</span>\n }\n @case ('error') {\n <span class=\"text-red-600\">Failed</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (only for uploading files) -->\n @if (file.stage === 'uploading' && file.percentage !== undefined) {\n <div class=\"file-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"progress-text\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"upload-actions\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('reading') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('uploading') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('complete') {\n <button class=\"action-btn success-btn\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"action-btn retry-btn\" title=\"Retry\">\n <cide-ele-icon size=\"xs\">refresh</cide-ele-icon>\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- No uploads message when manually opened -->\n <div class=\"no-uploads-message\">\n <div class=\"message-content\">\n <cide-ele-icon size=\"md\" class=\"message-icon\">cloud_upload</cide-ele-icon>\n <div class=\"message-text\">\n <h4>No active uploads</h4>\n <p>Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n }\n</div>\n}\n", styles: [".floating-uploader{position:fixed;bottom:20px;right:20px;width:320px;max-height:500px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000001f;border:1px solid rgba(0,0,0,.08);z-index:1000;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1);transform:translateY(0);opacity:1}.floating-uploader.animating{transition:all .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.minimized .uploader-content{display:none}.floating-uploader.minimized .uploader-footer{border-top:none}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f626}.floating-uploader .uploader-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-header .header-left{display:flex;align-items:center;gap:8px}.floating-uploader .uploader-header .header-left .upload-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;border-radius:6px;color:#fff}.floating-uploader .uploader-header .header-left .upload-info .upload-title{font-size:14px;font-weight:600;color:#1e293b;margin:0}.floating-uploader .uploader-header .header-left .upload-info .upload-summary{font-size:12px;color:#64748b;margin:0}.floating-uploader .uploader-header .header-actions{display:flex;gap:4px}.floating-uploader .uploader-header .header-actions .action-btn{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:background-color .2s;color:#64748b}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#e2e8f0;color:#1e293b}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content{max-height:400px;overflow-y:auto}.floating-uploader .uploader-content .overall-progress{padding:12px 16px;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-content .overall-progress.sticky-progress{position:sticky;top:0;background:#fff;z-index:10;box-shadow:0 2px 4px #0000000d}.floating-uploader .uploader-content .overall-progress .progress-bar{width:100%;height:4px;background:#e2e8f0;border-radius:2px;overflow:hidden;margin-bottom:4px}.floating-uploader .uploader-content .overall-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .overall-progress .progress-text{font-size:12px;color:#64748b;text-align:center;display:block}.floating-uploader .uploader-content .upload-queue .upload-item{display:flex;align-items:center;padding:8px 16px;border-bottom:1px solid #f1f5f9;transition:background-color .2s}.floating-uploader .uploader-content .upload-queue .upload-item:last-child{border-bottom:none}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#f0f9ff}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#f0fdf4}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#fef2f2}.floating-uploader .uploader-content .upload-queue .upload-item .file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .status-icon{flex-shrink:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details{min-width:0;flex:1}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{font-size:13px;font-weight:500;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status{font-size:11px;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status span{font-weight:500}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress{display:flex;align-items:center;gap:8px;margin:0 8px;min-width:80px}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{flex:1;height:3px;background:#e2e8f0;border-radius:2px;overflow:hidden}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text{font-size:10px;color:#64748b;min-width:24px;text-align:right}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions{display:flex;gap:4px}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:all .2s;color:#64748b}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#e2e8f0}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#f0f9ff;color:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#16a34a}.floating-uploader .uploader-content .hidden-uploader{display:none}.floating-uploader .uploader-footer{padding:8px 16px;background:#f8fafc;border-top:1px solid #e2e8f0}.floating-uploader .uploader-footer .footer-stats{display:flex;gap:12px;font-size:11px}.floating-uploader .uploader-footer .footer-stats .stat{display:flex;align-items:center;gap:4px;color:#64748b}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#3b82f6}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#16a34a}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#dc2626}@media (max-width: 640px){.floating-uploader{bottom:10px;right:10px;left:10px;width:auto;max-width:none}}@media (prefers-color-scheme: dark){.floating-uploader{background:#1e293b;border-color:#334155;box-shadow:0 8px 32px #0000004d}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f633}.floating-uploader .uploader-header{background:#334155;border-bottom-color:#475569}.floating-uploader .uploader-header .header-left .upload-icon{background:#3b82f6}.floating-uploader .uploader-header .header-left .upload-info .upload-title{color:#f1f5f9}.floating-uploader .uploader-header .header-left .upload-info .upload-summary,.floating-uploader .uploader-header .header-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#475569;color:#f1f5f9}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .overall-progress{border-bottom-color:#475569}.floating-uploader .uploader-content .overall-progress.sticky-progress{background:#1e293b;box-shadow:0 2px 4px #0003}.floating-uploader .uploader-content .overall-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .overall-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .overall-progress .progress-text{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item{border-bottom-color:#334155}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#1e3a8a}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#14532d}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#7f1d1d}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{color:#f1f5f9}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text,.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#1e3a8a;color:#60a5fa}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#4ade80}.floating-uploader .uploader-footer{background:#334155;border-top-color:#475569}.floating-uploader .uploader-footer .footer-stats .stat{color:#94a3b8}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#60a5fa}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#4ade80}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#fca5a5}}@keyframes slideInUp{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes slideOutDown{0%{transform:translateY(0);opacity:1}to{transform:translateY(100%);opacity:0}}.floating-uploader.animating{animation:slideInUp .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.animating.hiding{animation:slideOutDown .3s cubic-bezier(.4,0,.2,1)}.no-uploads-message{padding:2rem;text-align:center;color:#6b7280}.no-uploads-message .message-content{display:flex;flex-direction:column;align-items:center;gap:1rem}.no-uploads-message .message-content .message-icon{color:#9ca3af;opacity:.7}.no-uploads-message .message-content .message-text h4{margin:0 0 .5rem;font-size:1.1rem;font-weight:600;color:#374151}.no-uploads-message .message-content .message-text p{margin:0;font-size:.9rem;color:#6b7280}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
3819
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFloatingFileUploaderComponent, isStandalone: true, selector: "cide-ele-floating-file-uploader", ngImport: i0, template: "<!-- Floating File Uploader Container -->\n@if (isVisible()) {\n<div class=\"floating-uploader\" \n [class.minimized]=\"isMinimized()\" \n [class.animating]=\"isAnimating()\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\">\n\n <!-- Header (Draggable) -->\n <div class=\"uploader-header draggable-header\"\n (mousedown)=\"startDrag($event)\"\n (touchstart)=\"startDrag($event)\">\n <div class=\"header-left\">\n <div class=\"upload-icon\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n </div>\n <div class=\"upload-info\">\n <div class=\"upload-title\">File Upload</div>\n <div class=\"upload-summary\">{{ getUploadSummary() }}</div>\n </div>\n </div>\n \n <div class=\"header-actions\">\n <button class=\"action-btn minimize-btn\" (click)=\"toggleMinimize()\" [title]=\"isMinimized() ? 'Expand' : 'Minimize'\">\n <cide-ele-icon size=\"xs\">{{ isMinimized() ? 'expand_more' : 'expand_less' }}</cide-ele-icon>\n </button>\n <button class=\"action-btn close-btn\" (click)=\"close()\" title=\"Close\">\n <cide-ele-icon size=\"xs\">close</cide-ele-icon>\n </button>\n </div>\n </div>\n\n <!-- Content (hidden when minimized) -->\n @if (!isMinimized()) {\n <div class=\"uploader-content\">\n \n <!-- Drag and Drop Zone -->\n <div class=\"upload-zone\" \n [class.drag-over]=\"isDragOver()\" \n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" \n (drop)=\"onDrop($event)\" \n (click)=\"triggerFileInput()\">\n \n <!-- Hidden file input -->\n <input #fileInput \n type=\"file\" \n [multiple]=\"true\" \n [accept]=\"'*/*'\" \n (change)=\"onFileInputChange($event)\" \n style=\"display: none;\">\n \n <div class=\"upload-zone-content\">\n <cide-ele-icon class=\"upload-icon\" size=\"md\">cloud_upload</cide-ele-icon>\n \n <div class=\"upload-text\">\n <div class=\"upload-title\">\n {{ isDragOver() ? 'Drop files here' : 'Add More Files' }}\n </div>\n <div class=\"upload-subtitle\">\n {{ isDragOver() ? 'Release to upload' : 'Drag and drop files or click to browse' }}\n </div>\n </div>\n \n <button type=\"button\" \n class=\"upload-browse-btn\"\n (click)=\"triggerFileInput(); $event.stopPropagation()\">\n <cide-ele-icon size=\"xs\">add</cide-ele-icon>\n Choose Files\n </button>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (getAllFiles().length > 0) {\n <div class=\"upload-queue\">\n <!-- Show all files from service state -->\n @for (file of getAllFiles(); track file.fileId) {\n <div class=\"upload-item\" [class]=\"getStatusClass(file.stage)\">\n <div class=\"file-info\">\n <cide-ele-icon class=\"status-icon\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"file-details\">\n <div class=\"file-name\">{{ file.fileName }}</div>\n <div class=\"file-status\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"text-yellow-600\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"text-yellow-600\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"text-blue-600\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"text-green-600\">Completed</span>\n }\n @case ('error') {\n <span class=\"text-red-600\">Failed</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (only for uploading files) -->\n @if (file.stage === 'uploading' && file.percentage !== undefined) {\n <div class=\"file-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"progress-text\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"upload-actions\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('reading') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('uploading') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('complete') {\n <button class=\"action-btn success-btn\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"action-btn retry-btn\" title=\"Retry\">\n <cide-ele-icon size=\"xs\">refresh</cide-ele-icon>\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- No uploads message when manually opened -->\n <div class=\"no-uploads-message\">\n <div class=\"message-content\">\n <cide-ele-icon size=\"md\" class=\"message-icon\">cloud_upload</cide-ele-icon>\n <div class=\"message-text\">\n <h4>No active uploads</h4>\n <p>Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n }\n</div>\n}\n", styles: [".floating-uploader{position:fixed;width:320px;max-height:500px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000001f;border:1px solid rgba(0,0,0,.08);z-index:1000;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1);transform:translateY(0);opacity:1}.floating-uploader.animating{transition:all .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.minimized .uploader-content{display:none}.floating-uploader.minimized .uploader-footer{border-top:none}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f626}.floating-uploader .uploader-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-header.draggable-header{cursor:move;-webkit-user-select:none;user-select:none}.floating-uploader .uploader-header.draggable-header:hover{background:#f1f5f9}.floating-uploader .uploader-header.draggable-header:active{background:#e2e8f0;cursor:grabbing}.floating-uploader .uploader-header .header-left{display:flex;align-items:center;gap:8px}.floating-uploader .uploader-header .header-left .upload-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;border-radius:6px;color:#fff}.floating-uploader .uploader-header .header-left .upload-info .upload-title{font-size:14px;font-weight:600;color:#1e293b;margin:0}.floating-uploader .uploader-header .header-left .upload-info .upload-summary{font-size:12px;color:#64748b;margin:0}.floating-uploader .uploader-header .header-actions{display:flex;gap:4px}.floating-uploader .uploader-header .header-actions .action-btn{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:background-color .2s;color:#64748b}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#e2e8f0;color:#1e293b}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content{max-height:400px;overflow-y:auto}.floating-uploader .uploader-content .upload-zone{margin:12px 16px;padding:20px;border:2px dashed #d1d5db;border-radius:8px;background:#f9fafb;cursor:pointer;transition:all .2s ease;text-align:center}.floating-uploader .uploader-content .upload-zone:hover{border-color:#3b82f6;background:#f0f9ff}.floating-uploader .uploader-content .upload-zone.drag-over{border-color:#3b82f6;background:#dbeafe;transform:scale(1.02)}.floating-uploader .uploader-content .upload-zone .upload-zone-content{display:flex;flex-direction:column;align-items:center;gap:8px}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-icon{color:#6b7280;transition:color .2s ease}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-text .upload-title{font-size:14px;font-weight:600;color:#374151;margin:0}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-text .upload-subtitle{font-size:12px;color:#6b7280;margin:0}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-browse-btn{display:flex;align-items:center;gap:4px;padding:6px 12px;background:#3b82f6;color:#fff;border:none;border-radius:6px;font-size:12px;font-weight:500;cursor:pointer;transition:background-color .2s ease}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-browse-btn:hover{background:#2563eb}.floating-uploader .uploader-content .upload-zone:hover .upload-zone-content .upload-icon{color:#3b82f6}.floating-uploader .uploader-content .upload-zone.drag-over .upload-zone-content .upload-icon{color:#1d4ed8}.floating-uploader .uploader-content .upload-queue .upload-item{display:flex;align-items:center;padding:8px 16px;border-bottom:1px solid #f1f5f9;transition:background-color .2s}.floating-uploader .uploader-content .upload-queue .upload-item:last-child{border-bottom:none}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#f0f9ff}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#f0fdf4}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#fef2f2}.floating-uploader .uploader-content .upload-queue .upload-item .file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .status-icon{flex-shrink:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details{min-width:0;flex:1}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{font-size:13px;font-weight:500;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status{font-size:11px;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status span{font-weight:500}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress{display:flex;align-items:center;gap:8px;margin:0 8px;min-width:80px}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{flex:1;height:3px;background:#e2e8f0;border-radius:2px;overflow:hidden}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text{font-size:10px;color:#64748b;min-width:24px;text-align:right}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions{display:flex;gap:4px}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:all .2s;color:#64748b}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#e2e8f0}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#f0f9ff;color:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#16a34a}.floating-uploader .uploader-content .hidden-uploader{display:none}.floating-uploader .uploader-footer{padding:8px 16px;background:#f8fafc;border-top:1px solid #e2e8f0}.floating-uploader .uploader-footer .footer-stats{display:flex;gap:12px;font-size:11px}.floating-uploader .uploader-footer .footer-stats .stat{display:flex;align-items:center;gap:4px;color:#64748b}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#3b82f6}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#16a34a}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#dc2626}@media (max-width: 640px){.floating-uploader{bottom:10px;right:10px;left:10px;width:auto;max-width:none}}@media (prefers-color-scheme: dark){.floating-uploader{background:#1e293b;border-color:#334155;box-shadow:0 8px 32px #0000004d}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f633}.floating-uploader .uploader-header{background:#334155;border-bottom-color:#475569}.floating-uploader .uploader-header.draggable-header:hover{background:#475569}.floating-uploader .uploader-header.draggable-header:active{background:#64748b}.floating-uploader .uploader-header .header-left .upload-icon{background:#3b82f6}.floating-uploader .uploader-header .header-left .upload-info .upload-title{color:#f1f5f9}.floating-uploader .uploader-header .header-left .upload-info .upload-summary,.floating-uploader .uploader-header .header-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#475569;color:#f1f5f9}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .upload-zone{border-color:#475569;background:#334155}.floating-uploader .uploader-content .upload-zone:hover{border-color:#3b82f6;background:#1e3a8a}.floating-uploader .uploader-content .upload-zone.drag-over{border-color:#60a5fa;background:#1e40af}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-icon{color:#94a3b8}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-text .upload-title{color:#f1f5f9}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-text .upload-subtitle{color:#94a3b8}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-browse-btn{background:#3b82f6;color:#fff}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-browse-btn:hover{background:#2563eb}.floating-uploader .uploader-content .upload-zone:hover .upload-zone-content .upload-icon{color:#60a5fa}.floating-uploader .uploader-content .upload-zone.drag-over .upload-zone-content .upload-icon{color:#93c5fd}.floating-uploader .uploader-content .upload-queue .upload-item{border-bottom-color:#334155}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#1e3a8a}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#14532d}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#7f1d1d}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{color:#f1f5f9}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text,.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#1e3a8a;color:#60a5fa}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#4ade80}.floating-uploader .uploader-footer{background:#334155;border-top-color:#475569}.floating-uploader .uploader-footer .footer-stats .stat{color:#94a3b8}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#60a5fa}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#4ade80}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#fca5a5}}@keyframes slideInUp{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes slideOutDown{0%{transform:translateY(0);opacity:1}to{transform:translateY(100%);opacity:0}}.floating-uploader.animating{animation:slideInUp .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.animating.hiding{animation:slideOutDown .3s cubic-bezier(.4,0,.2,1)}.no-uploads-message{padding:2rem;text-align:center;color:#6b7280}.no-uploads-message .message-content{display:flex;flex-direction:column;align-items:center;gap:1rem}.no-uploads-message .message-content .message-icon{color:#9ca3af;opacity:.7}.no-uploads-message .message-content .message-text h4{margin:0 0 .5rem;font-size:1.1rem;font-weight:600;color:#374151}.no-uploads-message .message-content .message-text p{margin:0;font-size:.9rem;color:#6b7280}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
3640
3820
  }
3641
3821
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingFileUploaderComponent, decorators: [{
3642
3822
  type: Component,
3643
3823
  args: [{ selector: 'cide-ele-floating-file-uploader', standalone: true, imports: [
3644
3824
  CommonModule,
3645
3825
  CideIconComponent
3646
- ], template: "<!-- Floating File Uploader Container -->\n@if (isVisible()) {\n<div class=\"floating-uploader\" \n [class.minimized]=\"isMinimized()\" \n [class.animating]=\"isAnimating()\">\n\n <!-- Header -->\n <div class=\"uploader-header\">\n <div class=\"header-left\">\n <div class=\"upload-icon\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n </div>\n <div class=\"upload-info\">\n <div class=\"upload-title\">File Upload</div>\n <div class=\"upload-summary\">{{ getUploadSummary() }}</div>\n </div>\n </div>\n \n <div class=\"header-actions\">\n <button class=\"action-btn minimize-btn\" (click)=\"toggleMinimize()\" [title]=\"isMinimized() ? 'Expand' : 'Minimize'\">\n <cide-ele-icon size=\"xs\">{{ isMinimized() ? 'expand_more' : 'expand_less' }}</cide-ele-icon>\n </button>\n <button class=\"action-btn close-btn\" (click)=\"close()\" title=\"Close\">\n <cide-ele-icon size=\"xs\">close</cide-ele-icon>\n </button>\n </div>\n </div>\n\n <!-- Content (hidden when minimized) -->\n @if (!isMinimized()) {\n <div class=\"uploader-content\">\n \n <!-- Overall Progress Bar - Fixed at top -->\n @if (uploadQueue().length > 0 || activeUploads().size > 0) {\n <div class=\"overall-progress sticky-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"getOverallProgress()\"></div>\n </div>\n <div class=\"progress-text\">{{ getOverallProgress() }}%</div>\n </div>\n }\n\n <!-- Upload Queue - Show files from service state -->\n @if (getAllFiles().length > 0) {\n <div class=\"upload-queue\">\n <!-- Show all files from service state -->\n @for (file of getAllFiles(); track file.fileId) {\n <div class=\"upload-item\" [class]=\"getStatusClass(file.stage)\">\n <div class=\"file-info\">\n <cide-ele-icon class=\"status-icon\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"file-details\">\n <div class=\"file-name\">{{ file.fileName }}</div>\n <div class=\"file-status\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"text-yellow-600\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"text-yellow-600\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"text-blue-600\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"text-green-600\">Completed</span>\n }\n @case ('error') {\n <span class=\"text-red-600\">Failed</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (only for uploading files) -->\n @if (file.stage === 'uploading' && file.percentage !== undefined) {\n <div class=\"file-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"progress-text\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"upload-actions\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('reading') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('uploading') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('complete') {\n <button class=\"action-btn success-btn\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"action-btn retry-btn\" title=\"Retry\">\n <cide-ele-icon size=\"xs\">refresh</cide-ele-icon>\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- No uploads message when manually opened -->\n <div class=\"no-uploads-message\">\n <div class=\"message-content\">\n <cide-ele-icon size=\"md\" class=\"message-icon\">cloud_upload</cide-ele-icon>\n <div class=\"message-text\">\n <h4>No active uploads</h4>\n <p>Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n }\n</div>\n}\n", styles: [".floating-uploader{position:fixed;bottom:20px;right:20px;width:320px;max-height:500px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000001f;border:1px solid rgba(0,0,0,.08);z-index:1000;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1);transform:translateY(0);opacity:1}.floating-uploader.animating{transition:all .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.minimized .uploader-content{display:none}.floating-uploader.minimized .uploader-footer{border-top:none}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f626}.floating-uploader .uploader-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-header .header-left{display:flex;align-items:center;gap:8px}.floating-uploader .uploader-header .header-left .upload-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;border-radius:6px;color:#fff}.floating-uploader .uploader-header .header-left .upload-info .upload-title{font-size:14px;font-weight:600;color:#1e293b;margin:0}.floating-uploader .uploader-header .header-left .upload-info .upload-summary{font-size:12px;color:#64748b;margin:0}.floating-uploader .uploader-header .header-actions{display:flex;gap:4px}.floating-uploader .uploader-header .header-actions .action-btn{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:background-color .2s;color:#64748b}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#e2e8f0;color:#1e293b}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content{max-height:400px;overflow-y:auto}.floating-uploader .uploader-content .overall-progress{padding:12px 16px;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-content .overall-progress.sticky-progress{position:sticky;top:0;background:#fff;z-index:10;box-shadow:0 2px 4px #0000000d}.floating-uploader .uploader-content .overall-progress .progress-bar{width:100%;height:4px;background:#e2e8f0;border-radius:2px;overflow:hidden;margin-bottom:4px}.floating-uploader .uploader-content .overall-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .overall-progress .progress-text{font-size:12px;color:#64748b;text-align:center;display:block}.floating-uploader .uploader-content .upload-queue .upload-item{display:flex;align-items:center;padding:8px 16px;border-bottom:1px solid #f1f5f9;transition:background-color .2s}.floating-uploader .uploader-content .upload-queue .upload-item:last-child{border-bottom:none}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#f0f9ff}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#f0fdf4}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#fef2f2}.floating-uploader .uploader-content .upload-queue .upload-item .file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .status-icon{flex-shrink:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details{min-width:0;flex:1}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{font-size:13px;font-weight:500;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status{font-size:11px;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status span{font-weight:500}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress{display:flex;align-items:center;gap:8px;margin:0 8px;min-width:80px}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{flex:1;height:3px;background:#e2e8f0;border-radius:2px;overflow:hidden}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text{font-size:10px;color:#64748b;min-width:24px;text-align:right}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions{display:flex;gap:4px}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:all .2s;color:#64748b}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#e2e8f0}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#f0f9ff;color:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#16a34a}.floating-uploader .uploader-content .hidden-uploader{display:none}.floating-uploader .uploader-footer{padding:8px 16px;background:#f8fafc;border-top:1px solid #e2e8f0}.floating-uploader .uploader-footer .footer-stats{display:flex;gap:12px;font-size:11px}.floating-uploader .uploader-footer .footer-stats .stat{display:flex;align-items:center;gap:4px;color:#64748b}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#3b82f6}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#16a34a}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#dc2626}@media (max-width: 640px){.floating-uploader{bottom:10px;right:10px;left:10px;width:auto;max-width:none}}@media (prefers-color-scheme: dark){.floating-uploader{background:#1e293b;border-color:#334155;box-shadow:0 8px 32px #0000004d}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f633}.floating-uploader .uploader-header{background:#334155;border-bottom-color:#475569}.floating-uploader .uploader-header .header-left .upload-icon{background:#3b82f6}.floating-uploader .uploader-header .header-left .upload-info .upload-title{color:#f1f5f9}.floating-uploader .uploader-header .header-left .upload-info .upload-summary,.floating-uploader .uploader-header .header-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#475569;color:#f1f5f9}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .overall-progress{border-bottom-color:#475569}.floating-uploader .uploader-content .overall-progress.sticky-progress{background:#1e293b;box-shadow:0 2px 4px #0003}.floating-uploader .uploader-content .overall-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .overall-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .overall-progress .progress-text{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item{border-bottom-color:#334155}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#1e3a8a}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#14532d}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#7f1d1d}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{color:#f1f5f9}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text,.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#1e3a8a;color:#60a5fa}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#4ade80}.floating-uploader .uploader-footer{background:#334155;border-top-color:#475569}.floating-uploader .uploader-footer .footer-stats .stat{color:#94a3b8}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#60a5fa}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#4ade80}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#fca5a5}}@keyframes slideInUp{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes slideOutDown{0%{transform:translateY(0);opacity:1}to{transform:translateY(100%);opacity:0}}.floating-uploader.animating{animation:slideInUp .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.animating.hiding{animation:slideOutDown .3s cubic-bezier(.4,0,.2,1)}.no-uploads-message{padding:2rem;text-align:center;color:#6b7280}.no-uploads-message .message-content{display:flex;flex-direction:column;align-items:center;gap:1rem}.no-uploads-message .message-content .message-icon{color:#9ca3af;opacity:.7}.no-uploads-message .message-content .message-text h4{margin:0 0 .5rem;font-size:1.1rem;font-weight:600;color:#374151}.no-uploads-message .message-content .message-text p{margin:0;font-size:.9rem;color:#6b7280}\n"] }]
3826
+ ], template: "<!-- Floating File Uploader Container -->\n@if (isVisible()) {\n<div class=\"floating-uploader\" \n [class.minimized]=\"isMinimized()\" \n [class.animating]=\"isAnimating()\"\n [style.left.px]=\"position().x\"\n [style.top.px]=\"position().y\">\n\n <!-- Header (Draggable) -->\n <div class=\"uploader-header draggable-header\"\n (mousedown)=\"startDrag($event)\"\n (touchstart)=\"startDrag($event)\">\n <div class=\"header-left\">\n <div class=\"upload-icon\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n </div>\n <div class=\"upload-info\">\n <div class=\"upload-title\">File Upload</div>\n <div class=\"upload-summary\">{{ getUploadSummary() }}</div>\n </div>\n </div>\n \n <div class=\"header-actions\">\n <button class=\"action-btn minimize-btn\" (click)=\"toggleMinimize()\" [title]=\"isMinimized() ? 'Expand' : 'Minimize'\">\n <cide-ele-icon size=\"xs\">{{ isMinimized() ? 'expand_more' : 'expand_less' }}</cide-ele-icon>\n </button>\n <button class=\"action-btn close-btn\" (click)=\"close()\" title=\"Close\">\n <cide-ele-icon size=\"xs\">close</cide-ele-icon>\n </button>\n </div>\n </div>\n\n <!-- Content (hidden when minimized) -->\n @if (!isMinimized()) {\n <div class=\"uploader-content\">\n \n <!-- Drag and Drop Zone -->\n <div class=\"upload-zone\" \n [class.drag-over]=\"isDragOver()\" \n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" \n (drop)=\"onDrop($event)\" \n (click)=\"triggerFileInput()\">\n \n <!-- Hidden file input -->\n <input #fileInput \n type=\"file\" \n [multiple]=\"true\" \n [accept]=\"'*/*'\" \n (change)=\"onFileInputChange($event)\" \n style=\"display: none;\">\n \n <div class=\"upload-zone-content\">\n <cide-ele-icon class=\"upload-icon\" size=\"md\">cloud_upload</cide-ele-icon>\n \n <div class=\"upload-text\">\n <div class=\"upload-title\">\n {{ isDragOver() ? 'Drop files here' : 'Add More Files' }}\n </div>\n <div class=\"upload-subtitle\">\n {{ isDragOver() ? 'Release to upload' : 'Drag and drop files or click to browse' }}\n </div>\n </div>\n \n <button type=\"button\" \n class=\"upload-browse-btn\"\n (click)=\"triggerFileInput(); $event.stopPropagation()\">\n <cide-ele-icon size=\"xs\">add</cide-ele-icon>\n Choose Files\n </button>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (getAllFiles().length > 0) {\n <div class=\"upload-queue\">\n <!-- Show all files from service state -->\n @for (file of getAllFiles(); track file.fileId) {\n <div class=\"upload-item\" [class]=\"getStatusClass(file.stage)\">\n <div class=\"file-info\">\n <cide-ele-icon class=\"status-icon\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"file-details\">\n <div class=\"file-name\">{{ file.fileName }}</div>\n <div class=\"file-status\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"text-yellow-600\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"text-yellow-600\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"text-blue-600\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"text-green-600\">Completed</span>\n }\n @case ('error') {\n <span class=\"text-red-600\">Failed</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (only for uploading files) -->\n @if (file.stage === 'uploading' && file.percentage !== undefined) {\n <div class=\"file-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"progress-text\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"upload-actions\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('reading') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('uploading') {\n <button class=\"action-btn cancel-btn\" (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('complete') {\n <button class=\"action-btn success-btn\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"action-btn retry-btn\" title=\"Retry\">\n <cide-ele-icon size=\"xs\">refresh</cide-ele-icon>\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- No uploads message when manually opened -->\n <div class=\"no-uploads-message\">\n <div class=\"message-content\">\n <cide-ele-icon size=\"md\" class=\"message-icon\">cloud_upload</cide-ele-icon>\n <div class=\"message-text\">\n <h4>No active uploads</h4>\n <p>Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n }\n</div>\n}\n", styles: [".floating-uploader{position:fixed;width:320px;max-height:500px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000001f;border:1px solid rgba(0,0,0,.08);z-index:1000;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1);transform:translateY(0);opacity:1}.floating-uploader.animating{transition:all .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.minimized .uploader-content{display:none}.floating-uploader.minimized .uploader-footer{border-top:none}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f626}.floating-uploader .uploader-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-header.draggable-header{cursor:move;-webkit-user-select:none;user-select:none}.floating-uploader .uploader-header.draggable-header:hover{background:#f1f5f9}.floating-uploader .uploader-header.draggable-header:active{background:#e2e8f0;cursor:grabbing}.floating-uploader .uploader-header .header-left{display:flex;align-items:center;gap:8px}.floating-uploader .uploader-header .header-left .upload-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;border-radius:6px;color:#fff}.floating-uploader .uploader-header .header-left .upload-info .upload-title{font-size:14px;font-weight:600;color:#1e293b;margin:0}.floating-uploader .uploader-header .header-left .upload-info .upload-summary{font-size:12px;color:#64748b;margin:0}.floating-uploader .uploader-header .header-actions{display:flex;gap:4px}.floating-uploader .uploader-header .header-actions .action-btn{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:background-color .2s;color:#64748b}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#e2e8f0;color:#1e293b}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content{max-height:400px;overflow-y:auto}.floating-uploader .uploader-content .upload-zone{margin:12px 16px;padding:20px;border:2px dashed #d1d5db;border-radius:8px;background:#f9fafb;cursor:pointer;transition:all .2s ease;text-align:center}.floating-uploader .uploader-content .upload-zone:hover{border-color:#3b82f6;background:#f0f9ff}.floating-uploader .uploader-content .upload-zone.drag-over{border-color:#3b82f6;background:#dbeafe;transform:scale(1.02)}.floating-uploader .uploader-content .upload-zone .upload-zone-content{display:flex;flex-direction:column;align-items:center;gap:8px}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-icon{color:#6b7280;transition:color .2s ease}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-text .upload-title{font-size:14px;font-weight:600;color:#374151;margin:0}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-text .upload-subtitle{font-size:12px;color:#6b7280;margin:0}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-browse-btn{display:flex;align-items:center;gap:4px;padding:6px 12px;background:#3b82f6;color:#fff;border:none;border-radius:6px;font-size:12px;font-weight:500;cursor:pointer;transition:background-color .2s ease}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-browse-btn:hover{background:#2563eb}.floating-uploader .uploader-content .upload-zone:hover .upload-zone-content .upload-icon{color:#3b82f6}.floating-uploader .uploader-content .upload-zone.drag-over .upload-zone-content .upload-icon{color:#1d4ed8}.floating-uploader .uploader-content .upload-queue .upload-item{display:flex;align-items:center;padding:8px 16px;border-bottom:1px solid #f1f5f9;transition:background-color .2s}.floating-uploader .uploader-content .upload-queue .upload-item:last-child{border-bottom:none}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#f0f9ff}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#f0fdf4}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#fef2f2}.floating-uploader .uploader-content .upload-queue .upload-item .file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .status-icon{flex-shrink:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details{min-width:0;flex:1}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{font-size:13px;font-weight:500;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status{font-size:11px;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status span{font-weight:500}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress{display:flex;align-items:center;gap:8px;margin:0 8px;min-width:80px}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{flex:1;height:3px;background:#e2e8f0;border-radius:2px;overflow:hidden}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text{font-size:10px;color:#64748b;min-width:24px;text-align:right}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions{display:flex;gap:4px}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:all .2s;color:#64748b}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#e2e8f0}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#f0f9ff;color:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#16a34a}.floating-uploader .uploader-content .hidden-uploader{display:none}.floating-uploader .uploader-footer{padding:8px 16px;background:#f8fafc;border-top:1px solid #e2e8f0}.floating-uploader .uploader-footer .footer-stats{display:flex;gap:12px;font-size:11px}.floating-uploader .uploader-footer .footer-stats .stat{display:flex;align-items:center;gap:4px;color:#64748b}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#3b82f6}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#16a34a}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#dc2626}@media (max-width: 640px){.floating-uploader{bottom:10px;right:10px;left:10px;width:auto;max-width:none}}@media (prefers-color-scheme: dark){.floating-uploader{background:#1e293b;border-color:#334155;box-shadow:0 8px 32px #0000004d}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f633}.floating-uploader .uploader-header{background:#334155;border-bottom-color:#475569}.floating-uploader .uploader-header.draggable-header:hover{background:#475569}.floating-uploader .uploader-header.draggable-header:active{background:#64748b}.floating-uploader .uploader-header .header-left .upload-icon{background:#3b82f6}.floating-uploader .uploader-header .header-left .upload-info .upload-title{color:#f1f5f9}.floating-uploader .uploader-header .header-left .upload-info .upload-summary,.floating-uploader .uploader-header .header-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#475569;color:#f1f5f9}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .upload-zone{border-color:#475569;background:#334155}.floating-uploader .uploader-content .upload-zone:hover{border-color:#3b82f6;background:#1e3a8a}.floating-uploader .uploader-content .upload-zone.drag-over{border-color:#60a5fa;background:#1e40af}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-icon{color:#94a3b8}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-text .upload-title{color:#f1f5f9}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-text .upload-subtitle{color:#94a3b8}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-browse-btn{background:#3b82f6;color:#fff}.floating-uploader .uploader-content .upload-zone .upload-zone-content .upload-browse-btn:hover{background:#2563eb}.floating-uploader .uploader-content .upload-zone:hover .upload-zone-content .upload-icon{color:#60a5fa}.floating-uploader .uploader-content .upload-zone.drag-over .upload-zone-content .upload-icon{color:#93c5fd}.floating-uploader .uploader-content .upload-queue .upload-item{border-bottom-color:#334155}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#1e3a8a}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#14532d}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#7f1d1d}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{color:#f1f5f9}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text,.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#1e3a8a;color:#60a5fa}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#4ade80}.floating-uploader .uploader-footer{background:#334155;border-top-color:#475569}.floating-uploader .uploader-footer .footer-stats .stat{color:#94a3b8}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#60a5fa}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#4ade80}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#fca5a5}}@keyframes slideInUp{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes slideOutDown{0%{transform:translateY(0);opacity:1}to{transform:translateY(100%);opacity:0}}.floating-uploader.animating{animation:slideInUp .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.animating.hiding{animation:slideOutDown .3s cubic-bezier(.4,0,.2,1)}.no-uploads-message{padding:2rem;text-align:center;color:#6b7280}.no-uploads-message .message-content{display:flex;flex-direction:column;align-items:center;gap:1rem}.no-uploads-message .message-content .message-icon{color:#9ca3af;opacity:.7}.no-uploads-message .message-content .message-text h4{margin:0 0 .5rem;font-size:1.1rem;font-weight:600;color:#374151}.no-uploads-message .message-content .message-text p{margin:0;font-size:.9rem;color:#6b7280}\n"] }]
3647
3827
  }], ctorParameters: () => [] });
3648
3828
 
3649
3829
  class CideEleFileInputComponent {
@@ -4097,7 +4277,8 @@ class CideEleFileInputComponent {
4097
4277
  // IMPORTANT: All files use the SAME group ID that was generated before starting uploads
4098
4278
  const uploadDataWithGroupId = {
4099
4279
  ...this.uploadDataSignal(),
4100
- groupId: groupId
4280
+ groupId: groupId,
4281
+ isMultiple: true
4101
4282
  };
4102
4283
  files.forEach((file, index) => {
4103
4284
  console.log(`📤 [FileInput] Uploading file ${index + 1}/${totalFiles}: "${file.name}" with group ID: ${groupId}`);
@@ -4345,8 +4526,36 @@ class CideEleFileInputComponent {
4345
4526
  * This can be called to show the floating uploader even when no files are selected
4346
4527
  */
4347
4528
  showUploader() {
4348
- if (this.floatingUploader && this.showFloatingUploaderSignal()) {
4349
- console.log('👁️ [FileInput] Manually showing floating uploader');
4529
+ console.log('👁️ [FileInput] Manually showing floating uploader');
4530
+ if (!this.showFloatingUploaderSignal()) {
4531
+ console.log('⚠️ [FileInput] Floating uploader is disabled');
4532
+ return;
4533
+ }
4534
+ const groupId = this.groupId();
4535
+ if (groupId) {
4536
+ // Fetch files for the group and trigger floating uploader to show
4537
+ this.fileManagerService.fetchAndStoreFilesByGroupId(groupId)
4538
+ .pipe(takeUntilDestroyed(this.destroyRef))
4539
+ .subscribe({
4540
+ next: (files) => {
4541
+ console.log('✅ [FileInput] Files fetched for floating uploader:', files.length);
4542
+ // Trigger the floating uploader to show via service
4543
+ this.fileManagerService.triggerFloatingUploaderShow();
4544
+ },
4545
+ error: (error) => {
4546
+ console.error('❌ [FileInput] Failed to fetch files for floating uploader:', error);
4547
+ // Still trigger show even if fetch fails
4548
+ this.fileManagerService.triggerFloatingUploaderShow();
4549
+ }
4550
+ });
4551
+ }
4552
+ else {
4553
+ // No group ID, just trigger show
4554
+ this.fileManagerService.triggerFloatingUploaderShow();
4555
+ }
4556
+ // Fallback to direct component access if available
4557
+ if (this.floatingUploader) {
4558
+ console.log('👁️ [FileInput] Using direct component access as fallback');
4350
4559
  this.floatingUploader.showUploader(this.floatingUploaderGroupIdSignal());
4351
4560
  }
4352
4561
  }
@@ -4591,7 +4800,7 @@ class CideEleFileInputComponent {
4591
4800
  useExisting: CideEleFileInputComponent,
4592
4801
  multi: true
4593
4802
  }
4594
- ], usesOnChanges: true, ngImport: i0, template: "<div class=\"cide-file-input\">\n <!-- Label (shown when not in preview box mode or when preview box mode but no label override) -->\n @if (labelSignal() && !isPreviewBoxMode()) {\n <label class=\"cide-file-input-label\" [attr.for]=\"'cide-file-input-' + id()\">\n {{ labelSignal() }}@if (requiredSignal()) {<span class=\"cide-file-input-required\"> *</span>}\n </label>\n }\n \n <!-- Preview Box Mode -->\n @if (isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview-box-container\">\n <!-- Hidden file input -->\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-hidden\"\n />\n \n <!-- Preview Box -->\n <div \n class=\"cide-file-input-preview-box\"\n [class.cide-file-input-preview-box-disabled]=\"disabledSignal()\"\n [class.cide-file-input-preview-box-has-image]=\"hasImages()\"\n [class.cide-file-input-preview-box-drag-over]=\"isDragOver()\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\"\n (click)=\"triggerFileSelect()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [attr.title]=\"disabledSignal() ? 'File selection disabled' : placeholderTextSignal()\">\n \n <!-- No Image State -->\n @if (!hasImages()) {\n <div class=\"cide-file-input-preview-box-placeholder\">\n <div class=\"cide-file-input-preview-box-icon\">\n <cide-ele-icon>{{ isDragOver() ? '\uD83D\uDCC1' : placeholderIconSignal() }}</cide-ele-icon>\n </div>\n <div class=\"cide-file-input-preview-box-text\">\n {{ isDragOver() ? 'Drop files here...' : placeholderTextSignal() }}\n </div>\n </div>\n }\n \n <!-- Image Preview State -->\n @if (hasImages()) {\n <div class=\"cide-file-input-preview-box-content\">\n <img \n [src]=\"previewUrls()[0]\" \n [alt]=\"fileNames()[0] || 'Preview image'\"\n class=\"cide-file-input-preview-box-image\">\n <div class=\"cide-file-input-preview-box-overlay\">\n <div class=\"cide-file-input-preview-box-overlay-text\">Click to change</div>\n </div>\n @if (!disabledSignal()) {\n <button \n type=\"button\" \n class=\"cide-file-input-preview-box-remove\"\n (click)=\"clearFiles(); $event.stopPropagation()\"\n title=\"Remove image\">\n \u00D7\n </button>\n }\n </div>\n }\n </div>\n \n <!-- File name display for preview box mode -->\n @if (hasImages() && fileNames().length && showFileNameSignal()) {\n <div class=\"cide-file-input-preview-box-filename\">\n {{ fileNames()[0] }}\n </div>\n }\n </div>\n }\n\n <!-- Standard Mode -->\n @if (!isPreviewBoxMode()) {\n <div \n class=\"cide-file-input-wrapper\"\n [class.cide-file-input-drag-over]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-element\"\n />\n @if (hasFiles()) {\n <button type=\"button\" class=\"cide-file-input-clear\" (click)=\"clearFiles()\">\n Clear\n </button>\n }\n </div>\n @if (hasFiles() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-files\">\n @if (multipleSignal() && fileNames().length > 1) {\n <!-- Show file count for multiple files -->\n <div class=\"cide-file-input-multiple-count\">\n {{ fileNames().length }} files selected\n </div>\n } @else {\n <!-- Show individual file names for single file or when only one file selected -->\n @for (name of fileNames(); track name) {\n <span>{{ name }}</span>\n }\n }\n <!-- Angular 20: Display file size using new computed values -->\n @if (totalFileSize() > 0) {\n <div class=\"cide-file-input-size\">\n Total size: {{ fileSizeInMB() }} MB\n </div>\n }\n </div>\n }\n }\n \n <!-- Image Preview Section (only for standard mode) -->\n @if (isImagePreviewAvailable() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview\">\n <div class=\"cide-file-input-preview-label\">Preview:</div>\n <div class=\"cide-file-input-preview-container\">\n @for (previewUrl of previewUrls(); track previewUrl; let i = $index) {\n <div \n class=\"cide-file-input-preview-item\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\">\n <button \n type=\"button\" \n class=\"cide-file-input-preview-remove\"\n (click)=\"removePreview(i)\"\n title=\"Remove image\">\n \u00D7\n </button>\n <img \n [src]=\"previewUrl\" \n [alt]=\"fileNames()[i] || 'Preview image'\"\n class=\"cide-file-input-preview-image\"\n loading=\"lazy\">\n <div class=\"cide-file-input-preview-filename\">{{ fileNames()[i] }}</div>\n </div>\n }\n </div>\n </div>\n }\n \n <!-- Upload Status and Show Files Button -->\n @if (showFloatingUploaderSignal() && (getUploadCount() > 0 || hasActiveUploads() || hasEverUploaded())) {\n <div class=\"cide-file-input-upload-status\">\n <div class=\"cide-file-input-upload-count\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n <span class=\"upload-count-text\">\n @if (hasActiveUploads()) {\n {{ getActiveUploadCount() }} uploading\n } @else if (getUploadCount() > 0) {\n {{ getUploadCount() }} completed\n } @else if (hasEverUploaded()) {\n View uploads\n }\n </span>\n </div>\n <button \n type=\"button\" \n class=\"cide-file-input-show-files-btn\"\n (click)=\"showFloatingUploaderDialog()\"\n title=\"View upload progress and history\">\n <cide-ele-icon size=\"sm\">visibility</cide-ele-icon>\n Show Files\n </button>\n </div>\n }\n \n @if (errorTextSignal()) {\n <div class=\"cide-file-input-error\">{{ errorTextSignal() }}</div>\n }\n @if (helperTextSignal() && !errorTextSignal()) {\n <div class=\"cide-file-input-helper\">{{ helperTextSignal() }}</div>\n }\n</div> ", styles: [".cide-file-input{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-label{font-weight:500;margin-bottom:.25rem}.cide-file-input-required{color:#d32f2f;font-weight:700}.cide-file-input-wrapper{display:flex;align-items:center;gap:.5rem;border:2px dashed transparent;border-radius:.5rem;padding:.5rem;transition:all .2s ease-in-out}.cide-file-input-wrapper.cide-file-input-drag-over{border-color:#3b82f6;background-color:#eff6ff;transform:scale(1.02)}.cide-file-input-element{flex:1}.cide-file-input-clear{background:none;border:none;color:#d32f2f;cursor:pointer;font-size:.9rem}.cide-file-input-files{font-size:.95rem;color:#333;margin-top:.25rem}.cide-file-input-multiple-count{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;background-color:#f0f9ff;border:1px solid #0ea5e9;border-radius:.5rem;color:#0369a1;font-weight:500;font-size:.9rem}.cide-file-input-size{margin-top:.5rem;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;font-size:.75rem;color:#4b5563;font-weight:500}.cide-file-input-error{color:#d32f2f;font-size:.9rem}.cide-file-input-helper{color:#666;font-size:.9rem}.cide-file-input-preview{margin-top:.75rem;padding:.75rem;background-color:#f8f9fa;border:1px solid #e1e5e9;border-radius:.375rem}.cide-file-input-preview-label{font-weight:500;margin-bottom:.5rem;color:#374151;font-size:.875rem}.cide-file-input-preview-container{display:flex;flex-wrap:wrap;gap:.75rem}.cide-file-input-preview-item{position:relative;display:flex;flex-direction:column;border:1px solid #d1d5db;border-radius:.5rem;overflow:hidden;background-color:#fff;box-shadow:0 1px 3px #0000001a;transition:box-shadow .2s ease-in-out}.cide-file-input-preview-item:hover{box-shadow:0 4px 6px -1px #0000001a}.cide-file-input-preview-image{width:100%;height:calc(100% - 2rem);object-fit:cover;object-position:center;background-color:#f3f4f6}.cide-file-input-preview-filename{padding:.375rem .5rem;background-color:#f9fafbf2;border-top:1px solid #e5e7eb;font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:2rem;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-remove{position:absolute;top:.25rem;right:.25rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;transition:all .2s ease-in-out}.cide-file-input-preview-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-hidden{display:none}.cide-file-input-preview-box-container{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-preview-box{position:relative;border:2px dashed #d1d5db;border-radius:.5rem;cursor:pointer;background-color:#f9fafb;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:all .2s ease-in-out}.cide-file-input-preview-box:hover{border-color:#3b82f6;background-color:#eff6ff}.cide-file-input-preview-box.cide-file-input-preview-box-disabled{cursor:not-allowed;opacity:.6;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-disabled:hover{border-color:#d1d5db;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image{border-style:solid;border-color:#e5e7eb;padding:0}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover{border-color:#3b82f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover .cide-file-input-preview-box-overlay{opacity:1}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over{border-color:#3b82f6!important;background-color:#eff6ff!important;transform:scale(1.02);box-shadow:0 0 0 4px #3b82f61a}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-icon{color:#3b82f6;transform:scale(1.1)}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-text{color:#3b82f6;font-weight:600}.cide-file-input-preview-box-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1rem;text-align:center}.cide-file-input-preview-box-icon{font-size:2rem;color:#6b7280}.cide-file-input-preview-box-text{font-size:.875rem;color:#6b7280;font-weight:500}.cide-file-input-preview-box-content{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-box-image{width:100%;height:100%;object-fit:cover;object-position:center}.cide-file-input-preview-box-overlay{position:absolute;inset:0;background-color:#0009;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out}.cide-file-input-preview-box-overlay-text{color:#fff;font-size:.875rem;font-weight:500;text-align:center}.cide-file-input-preview-box-remove{position:absolute;top:.375rem;right:.375rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:20;transition:all .2s ease-in-out}.cide-file-input-preview-box-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-box-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-preview-box-filename{font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;margin-top:.25rem}@media (max-width: 640px){.cide-file-input-preview-container{justify-content:center}.cide-file-input-preview-item{min-width:120px;max-width:150px}.cide-file-input-preview-box-icon{font-size:1.5rem}.cide-file-input-preview-box-text{font-size:.75rem}}.cide-file-input-upload-status{display:flex;align-items:center;justify-content:space-between;padding:.5rem .75rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:.375rem;margin-top:.5rem;gap:.75rem}.cide-file-input-upload-status .cide-file-input-upload-count{display:flex;align-items:center;gap:.5rem;color:#64748b;font-size:.875rem;font-weight:500}.cide-file-input-upload-status .cide-file-input-upload-count .upload-count-text{color:#1e293b}.cide-file-input-upload-status .cide-file-input-show-files-btn{display:flex;align-items:center;gap:.25rem;padding:.375rem .5rem;background:#3b82f6;color:#fff;border:none;border-radius:.25rem;font-size:.75rem;font-weight:500;cursor:pointer;transition:all .2s ease;min-width:auto;white-space:nowrap}.cide-file-input-upload-status .cide-file-input-show-files-btn:hover{background:#2563eb;transform:translateY(-1px);box-shadow:0 2px 4px #3b82f633}.cide-file-input-upload-status .cide-file-input-show-files-btn:active{transform:translateY(0);box-shadow:0 1px 2px #3b82f61a}@media (prefers-color-scheme: dark){.cide-file-input-upload-status{background:#1e293b;border-color:#334155}.cide-file-input-upload-status .cide-file-input-upload-count{color:#94a3b8}.cide-file-input-upload-status .cide-file-input-upload-count .upload-count-text{color:#f1f5f9}.cide-file-input-upload-status .cide-file-input-show-files-btn{background:#3b82f6}.cide-file-input-upload-status .cide-file-input-show-files-btn:hover{background:#2563eb}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
4803
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"cide-file-input\">\n <!-- Label (shown when not in preview box mode or when preview box mode but no label override) -->\n @if (labelSignal() && !isPreviewBoxMode()) {\n <label class=\"cide-file-input-label\" [attr.for]=\"'cide-file-input-' + id()\">\n {{ labelSignal() }}@if (requiredSignal()) {<span class=\"cide-file-input-required\"> *</span>}\n </label>\n }\n \n <!-- Preview Box Mode -->\n @if (isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview-box-container\">\n <!-- Hidden file input -->\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-hidden\"\n />\n \n <!-- Preview Box -->\n <div \n class=\"cide-file-input-preview-box\"\n [class.cide-file-input-preview-box-disabled]=\"disabledSignal()\"\n [class.cide-file-input-preview-box-has-image]=\"hasImages()\"\n [class.cide-file-input-preview-box-drag-over]=\"isDragOver()\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\"\n (click)=\"triggerFileSelect()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [attr.title]=\"disabledSignal() ? 'File selection disabled' : placeholderTextSignal()\">\n \n <!-- No Image State -->\n @if (!hasImages()) {\n <div class=\"cide-file-input-preview-box-placeholder\">\n <div class=\"cide-file-input-preview-box-icon\">\n <cide-ele-icon>{{ isDragOver() ? '\uD83D\uDCC1' : placeholderIconSignal() }}</cide-ele-icon>\n </div>\n <div class=\"cide-file-input-preview-box-text\">\n {{ isDragOver() ? 'Drop files here...' : placeholderTextSignal() }}\n </div>\n </div>\n }\n \n <!-- Image Preview State -->\n @if (hasImages()) {\n <div class=\"cide-file-input-preview-box-content\">\n <img \n [src]=\"previewUrls()[0]\" \n [alt]=\"fileNames()[0] || 'Preview image'\"\n class=\"cide-file-input-preview-box-image\">\n <div class=\"cide-file-input-preview-box-overlay\">\n <div class=\"cide-file-input-preview-box-overlay-text\">Click to change</div>\n </div>\n @if (!disabledSignal()) {\n <button \n type=\"button\" \n class=\"cide-file-input-preview-box-remove\"\n (click)=\"clearFiles(); $event.stopPropagation()\"\n title=\"Remove image\">\n \u00D7\n </button>\n }\n </div>\n }\n </div>\n \n <!-- File name display for preview box mode -->\n @if (hasImages() && fileNames().length && showFileNameSignal()) {\n <div class=\"cide-file-input-preview-box-filename\">\n {{ fileNames()[0] }}\n </div>\n }\n </div>\n }\n\n <!-- Standard Mode -->\n @if (!isPreviewBoxMode()) {\n <div \n class=\"cide-file-input-wrapper\"\n [class.cide-file-input-drag-over]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-element\"\n />\n @if (hasFiles()) {\n <button type=\"button\" class=\"cide-file-input-clear\" (click)=\"clearFiles()\">\n Clear\n </button>\n }\n </div>\n @if (hasFiles() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-files\">\n @if (multipleSignal() && fileNames().length > 1) {\n <!-- Show file count for multiple files -->\n <div class=\"cide-file-input-multiple-count\">\n {{ fileNames().length }} files selected\n </div>\n } @else {\n <!-- Show individual file names for single file or when only one file selected -->\n @for (name of fileNames(); track name) {\n <span>{{ name }}</span>\n }\n }\n <!-- Angular 20: Display file size using new computed values -->\n @if (totalFileSize() > 0) {\n <div class=\"cide-file-input-size\">\n Total size: {{ fileSizeInMB() }} MB\n </div>\n }\n </div>\n }\n }\n \n <!-- Image Preview Section (only for standard mode) -->\n @if (isImagePreviewAvailable() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview\">\n <div class=\"cide-file-input-preview-label\">Preview:</div>\n <div class=\"cide-file-input-preview-container\">\n @for (previewUrl of previewUrls(); track previewUrl; let i = $index) {\n <div \n class=\"cide-file-input-preview-item\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\">\n <button \n type=\"button\" \n class=\"cide-file-input-preview-remove\"\n (click)=\"removePreview(i)\"\n title=\"Remove image\">\n \u00D7\n </button>\n <img \n [src]=\"previewUrl\" \n [alt]=\"fileNames()[i] || 'Preview image'\"\n class=\"cide-file-input-preview-image\"\n loading=\"lazy\">\n <div class=\"cide-file-input-preview-filename\">{{ fileNames()[i] }}</div>\n </div>\n }\n </div>\n </div>\n }\n \n <!-- Upload Status and Show Files Button (only for multiple file inputs) -->\n @if (multiple && showFloatingUploaderSignal() && (getUploadCount() > 0 || hasActiveUploads() || hasEverUploaded())) {\n <div class=\"cide-file-input-upload-status\">\n <div class=\"cide-file-input-upload-count\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n <span class=\"upload-count-text\">\n @if (hasActiveUploads()) {\n {{ getActiveUploadCount() }} uploading\n } @else if (getUploadCount() > 0) {\n {{ getUploadCount() }} completed\n } @else if (hasEverUploaded()) {\n View uploads\n }\n </span>\n </div>\n <button \n type=\"button\" \n class=\"cide-file-input-show-files-icon\"\n (click)=\"showFloatingUploaderDialog()\"\n title=\"View upload progress and history\">\n <cide-ele-icon size=\"sm\">visibility</cide-ele-icon>\n </button>\n </div>\n }\n \n @if (errorTextSignal()) {\n <div class=\"cide-file-input-error\">{{ errorTextSignal() }}</div>\n }\n @if (helperTextSignal() && !errorTextSignal()) {\n <div class=\"cide-file-input-helper\">{{ helperTextSignal() }}</div>\n }\n</div> ", styles: [".cide-file-input{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-label{font-weight:500;margin-bottom:.25rem}.cide-file-input-required{color:#d32f2f;font-weight:700}.cide-file-input-wrapper{display:flex;align-items:center;gap:.5rem;border:2px dashed transparent;border-radius:.5rem;padding:.5rem;transition:all .2s ease-in-out}.cide-file-input-wrapper.cide-file-input-drag-over{border-color:#3b82f6;background-color:#eff6ff;transform:scale(1.02)}.cide-file-input-element{flex:1}.cide-file-input-clear{background:none;border:none;color:#d32f2f;cursor:pointer;font-size:.9rem}.cide-file-input-files{font-size:.95rem;color:#333;margin-top:.25rem}.cide-file-input-multiple-count{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;background-color:#f0f9ff;border:1px solid #0ea5e9;border-radius:.5rem;color:#0369a1;font-weight:500;font-size:.9rem}.cide-file-input-size{margin-top:.5rem;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;font-size:.75rem;color:#4b5563;font-weight:500}.cide-file-input-error{color:#d32f2f;font-size:.9rem}.cide-file-input-helper{color:#666;font-size:.9rem}.cide-file-input-preview{margin-top:.75rem;padding:.75rem;background-color:#f8f9fa;border:1px solid #e1e5e9;border-radius:.375rem}.cide-file-input-preview-label{font-weight:500;margin-bottom:.5rem;color:#374151;font-size:.875rem}.cide-file-input-preview-container{display:flex;flex-wrap:wrap;gap:.75rem}.cide-file-input-preview-item{position:relative;display:flex;flex-direction:column;border:1px solid #d1d5db;border-radius:.5rem;overflow:hidden;background-color:#fff;box-shadow:0 1px 3px #0000001a;transition:box-shadow .2s ease-in-out}.cide-file-input-preview-item:hover{box-shadow:0 4px 6px -1px #0000001a}.cide-file-input-preview-image{width:100%;height:calc(100% - 2rem);object-fit:cover;object-position:center;background-color:#f3f4f6}.cide-file-input-preview-filename{padding:.375rem .5rem;background-color:#f9fafbf2;border-top:1px solid #e5e7eb;font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:2rem;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-remove{position:absolute;top:.25rem;right:.25rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;transition:all .2s ease-in-out}.cide-file-input-preview-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-hidden{display:none}.cide-file-input-preview-box-container{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-preview-box{position:relative;border:2px dashed #d1d5db;border-radius:.5rem;cursor:pointer;background-color:#f9fafb;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:all .2s ease-in-out}.cide-file-input-preview-box:hover{border-color:#3b82f6;background-color:#eff6ff}.cide-file-input-preview-box.cide-file-input-preview-box-disabled{cursor:not-allowed;opacity:.6;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-disabled:hover{border-color:#d1d5db;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image{border-style:solid;border-color:#e5e7eb;padding:0}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover{border-color:#3b82f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover .cide-file-input-preview-box-overlay{opacity:1}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over{border-color:#3b82f6!important;background-color:#eff6ff!important;transform:scale(1.02);box-shadow:0 0 0 4px #3b82f61a}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-icon{color:#3b82f6;transform:scale(1.1)}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-text{color:#3b82f6;font-weight:600}.cide-file-input-preview-box-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1rem;text-align:center}.cide-file-input-preview-box-icon{font-size:2rem;color:#6b7280}.cide-file-input-preview-box-text{font-size:.875rem;color:#6b7280;font-weight:500}.cide-file-input-preview-box-content{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-box-image{width:100%;height:100%;object-fit:cover;object-position:center}.cide-file-input-preview-box-overlay{position:absolute;inset:0;background-color:#0009;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out}.cide-file-input-preview-box-overlay-text{color:#fff;font-size:.875rem;font-weight:500;text-align:center}.cide-file-input-preview-box-remove{position:absolute;top:.375rem;right:.375rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:20;transition:all .2s ease-in-out}.cide-file-input-preview-box-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-box-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-preview-box-filename{font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;margin-top:.25rem}@media (max-width: 640px){.cide-file-input-preview-container{justify-content:center}.cide-file-input-preview-item{min-width:120px;max-width:150px}.cide-file-input-preview-box-icon{font-size:1.5rem}.cide-file-input-preview-box-text{font-size:.75rem}}.cide-file-input-upload-status{display:flex;align-items:center;justify-content:space-between;padding:.5rem .75rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:.375rem;margin-top:.5rem;gap:.75rem}.cide-file-input-upload-status .cide-file-input-upload-count{display:flex;align-items:center;gap:.5rem;color:#64748b;font-size:.875rem;font-weight:500}.cide-file-input-upload-status .cide-file-input-upload-count .upload-count-text{color:#1e293b}.cide-file-input-upload-status .cide-file-input-show-files-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;background:transparent;color:#6b7280;border:none;border-radius:.25rem;cursor:pointer;transition:all .2s ease}.cide-file-input-upload-status .cide-file-input-show-files-icon:hover{background:#f3f4f6;color:#3b82f6}.cide-file-input-upload-status .cide-file-input-show-files-icon:active{background:#e5e7eb}@media (prefers-color-scheme: dark){.cide-file-input-upload-status{background:#1e293b;border-color:#334155}.cide-file-input-upload-status .cide-file-input-upload-count{color:#94a3b8}.cide-file-input-upload-status .cide-file-input-upload-count .upload-count-text{color:#f1f5f9}.cide-file-input-upload-status .cide-file-input-show-files-icon{color:#94a3b8}.cide-file-input-upload-status .cide-file-input-show-files-icon:hover{background:#374151;color:#60a5fa}.cide-file-input-upload-status .cide-file-input-show-files-icon:active{background:#4b5563}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
4595
4804
  }
4596
4805
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFileInputComponent, decorators: [{
4597
4806
  type: Component,
@@ -4606,7 +4815,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
4606
4815
  useExisting: CideEleFileInputComponent,
4607
4816
  multi: true
4608
4817
  }
4609
- ], template: "<div class=\"cide-file-input\">\n <!-- Label (shown when not in preview box mode or when preview box mode but no label override) -->\n @if (labelSignal() && !isPreviewBoxMode()) {\n <label class=\"cide-file-input-label\" [attr.for]=\"'cide-file-input-' + id()\">\n {{ labelSignal() }}@if (requiredSignal()) {<span class=\"cide-file-input-required\"> *</span>}\n </label>\n }\n \n <!-- Preview Box Mode -->\n @if (isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview-box-container\">\n <!-- Hidden file input -->\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-hidden\"\n />\n \n <!-- Preview Box -->\n <div \n class=\"cide-file-input-preview-box\"\n [class.cide-file-input-preview-box-disabled]=\"disabledSignal()\"\n [class.cide-file-input-preview-box-has-image]=\"hasImages()\"\n [class.cide-file-input-preview-box-drag-over]=\"isDragOver()\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\"\n (click)=\"triggerFileSelect()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [attr.title]=\"disabledSignal() ? 'File selection disabled' : placeholderTextSignal()\">\n \n <!-- No Image State -->\n @if (!hasImages()) {\n <div class=\"cide-file-input-preview-box-placeholder\">\n <div class=\"cide-file-input-preview-box-icon\">\n <cide-ele-icon>{{ isDragOver() ? '\uD83D\uDCC1' : placeholderIconSignal() }}</cide-ele-icon>\n </div>\n <div class=\"cide-file-input-preview-box-text\">\n {{ isDragOver() ? 'Drop files here...' : placeholderTextSignal() }}\n </div>\n </div>\n }\n \n <!-- Image Preview State -->\n @if (hasImages()) {\n <div class=\"cide-file-input-preview-box-content\">\n <img \n [src]=\"previewUrls()[0]\" \n [alt]=\"fileNames()[0] || 'Preview image'\"\n class=\"cide-file-input-preview-box-image\">\n <div class=\"cide-file-input-preview-box-overlay\">\n <div class=\"cide-file-input-preview-box-overlay-text\">Click to change</div>\n </div>\n @if (!disabledSignal()) {\n <button \n type=\"button\" \n class=\"cide-file-input-preview-box-remove\"\n (click)=\"clearFiles(); $event.stopPropagation()\"\n title=\"Remove image\">\n \u00D7\n </button>\n }\n </div>\n }\n </div>\n \n <!-- File name display for preview box mode -->\n @if (hasImages() && fileNames().length && showFileNameSignal()) {\n <div class=\"cide-file-input-preview-box-filename\">\n {{ fileNames()[0] }}\n </div>\n }\n </div>\n }\n\n <!-- Standard Mode -->\n @if (!isPreviewBoxMode()) {\n <div \n class=\"cide-file-input-wrapper\"\n [class.cide-file-input-drag-over]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-element\"\n />\n @if (hasFiles()) {\n <button type=\"button\" class=\"cide-file-input-clear\" (click)=\"clearFiles()\">\n Clear\n </button>\n }\n </div>\n @if (hasFiles() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-files\">\n @if (multipleSignal() && fileNames().length > 1) {\n <!-- Show file count for multiple files -->\n <div class=\"cide-file-input-multiple-count\">\n {{ fileNames().length }} files selected\n </div>\n } @else {\n <!-- Show individual file names for single file or when only one file selected -->\n @for (name of fileNames(); track name) {\n <span>{{ name }}</span>\n }\n }\n <!-- Angular 20: Display file size using new computed values -->\n @if (totalFileSize() > 0) {\n <div class=\"cide-file-input-size\">\n Total size: {{ fileSizeInMB() }} MB\n </div>\n }\n </div>\n }\n }\n \n <!-- Image Preview Section (only for standard mode) -->\n @if (isImagePreviewAvailable() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview\">\n <div class=\"cide-file-input-preview-label\">Preview:</div>\n <div class=\"cide-file-input-preview-container\">\n @for (previewUrl of previewUrls(); track previewUrl; let i = $index) {\n <div \n class=\"cide-file-input-preview-item\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\">\n <button \n type=\"button\" \n class=\"cide-file-input-preview-remove\"\n (click)=\"removePreview(i)\"\n title=\"Remove image\">\n \u00D7\n </button>\n <img \n [src]=\"previewUrl\" \n [alt]=\"fileNames()[i] || 'Preview image'\"\n class=\"cide-file-input-preview-image\"\n loading=\"lazy\">\n <div class=\"cide-file-input-preview-filename\">{{ fileNames()[i] }}</div>\n </div>\n }\n </div>\n </div>\n }\n \n <!-- Upload Status and Show Files Button -->\n @if (showFloatingUploaderSignal() && (getUploadCount() > 0 || hasActiveUploads() || hasEverUploaded())) {\n <div class=\"cide-file-input-upload-status\">\n <div class=\"cide-file-input-upload-count\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n <span class=\"upload-count-text\">\n @if (hasActiveUploads()) {\n {{ getActiveUploadCount() }} uploading\n } @else if (getUploadCount() > 0) {\n {{ getUploadCount() }} completed\n } @else if (hasEverUploaded()) {\n View uploads\n }\n </span>\n </div>\n <button \n type=\"button\" \n class=\"cide-file-input-show-files-btn\"\n (click)=\"showFloatingUploaderDialog()\"\n title=\"View upload progress and history\">\n <cide-ele-icon size=\"sm\">visibility</cide-ele-icon>\n Show Files\n </button>\n </div>\n }\n \n @if (errorTextSignal()) {\n <div class=\"cide-file-input-error\">{{ errorTextSignal() }}</div>\n }\n @if (helperTextSignal() && !errorTextSignal()) {\n <div class=\"cide-file-input-helper\">{{ helperTextSignal() }}</div>\n }\n</div> ", styles: [".cide-file-input{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-label{font-weight:500;margin-bottom:.25rem}.cide-file-input-required{color:#d32f2f;font-weight:700}.cide-file-input-wrapper{display:flex;align-items:center;gap:.5rem;border:2px dashed transparent;border-radius:.5rem;padding:.5rem;transition:all .2s ease-in-out}.cide-file-input-wrapper.cide-file-input-drag-over{border-color:#3b82f6;background-color:#eff6ff;transform:scale(1.02)}.cide-file-input-element{flex:1}.cide-file-input-clear{background:none;border:none;color:#d32f2f;cursor:pointer;font-size:.9rem}.cide-file-input-files{font-size:.95rem;color:#333;margin-top:.25rem}.cide-file-input-multiple-count{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;background-color:#f0f9ff;border:1px solid #0ea5e9;border-radius:.5rem;color:#0369a1;font-weight:500;font-size:.9rem}.cide-file-input-size{margin-top:.5rem;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;font-size:.75rem;color:#4b5563;font-weight:500}.cide-file-input-error{color:#d32f2f;font-size:.9rem}.cide-file-input-helper{color:#666;font-size:.9rem}.cide-file-input-preview{margin-top:.75rem;padding:.75rem;background-color:#f8f9fa;border:1px solid #e1e5e9;border-radius:.375rem}.cide-file-input-preview-label{font-weight:500;margin-bottom:.5rem;color:#374151;font-size:.875rem}.cide-file-input-preview-container{display:flex;flex-wrap:wrap;gap:.75rem}.cide-file-input-preview-item{position:relative;display:flex;flex-direction:column;border:1px solid #d1d5db;border-radius:.5rem;overflow:hidden;background-color:#fff;box-shadow:0 1px 3px #0000001a;transition:box-shadow .2s ease-in-out}.cide-file-input-preview-item:hover{box-shadow:0 4px 6px -1px #0000001a}.cide-file-input-preview-image{width:100%;height:calc(100% - 2rem);object-fit:cover;object-position:center;background-color:#f3f4f6}.cide-file-input-preview-filename{padding:.375rem .5rem;background-color:#f9fafbf2;border-top:1px solid #e5e7eb;font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:2rem;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-remove{position:absolute;top:.25rem;right:.25rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;transition:all .2s ease-in-out}.cide-file-input-preview-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-hidden{display:none}.cide-file-input-preview-box-container{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-preview-box{position:relative;border:2px dashed #d1d5db;border-radius:.5rem;cursor:pointer;background-color:#f9fafb;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:all .2s ease-in-out}.cide-file-input-preview-box:hover{border-color:#3b82f6;background-color:#eff6ff}.cide-file-input-preview-box.cide-file-input-preview-box-disabled{cursor:not-allowed;opacity:.6;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-disabled:hover{border-color:#d1d5db;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image{border-style:solid;border-color:#e5e7eb;padding:0}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover{border-color:#3b82f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover .cide-file-input-preview-box-overlay{opacity:1}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over{border-color:#3b82f6!important;background-color:#eff6ff!important;transform:scale(1.02);box-shadow:0 0 0 4px #3b82f61a}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-icon{color:#3b82f6;transform:scale(1.1)}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-text{color:#3b82f6;font-weight:600}.cide-file-input-preview-box-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1rem;text-align:center}.cide-file-input-preview-box-icon{font-size:2rem;color:#6b7280}.cide-file-input-preview-box-text{font-size:.875rem;color:#6b7280;font-weight:500}.cide-file-input-preview-box-content{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-box-image{width:100%;height:100%;object-fit:cover;object-position:center}.cide-file-input-preview-box-overlay{position:absolute;inset:0;background-color:#0009;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out}.cide-file-input-preview-box-overlay-text{color:#fff;font-size:.875rem;font-weight:500;text-align:center}.cide-file-input-preview-box-remove{position:absolute;top:.375rem;right:.375rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:20;transition:all .2s ease-in-out}.cide-file-input-preview-box-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-box-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-preview-box-filename{font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;margin-top:.25rem}@media (max-width: 640px){.cide-file-input-preview-container{justify-content:center}.cide-file-input-preview-item{min-width:120px;max-width:150px}.cide-file-input-preview-box-icon{font-size:1.5rem}.cide-file-input-preview-box-text{font-size:.75rem}}.cide-file-input-upload-status{display:flex;align-items:center;justify-content:space-between;padding:.5rem .75rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:.375rem;margin-top:.5rem;gap:.75rem}.cide-file-input-upload-status .cide-file-input-upload-count{display:flex;align-items:center;gap:.5rem;color:#64748b;font-size:.875rem;font-weight:500}.cide-file-input-upload-status .cide-file-input-upload-count .upload-count-text{color:#1e293b}.cide-file-input-upload-status .cide-file-input-show-files-btn{display:flex;align-items:center;gap:.25rem;padding:.375rem .5rem;background:#3b82f6;color:#fff;border:none;border-radius:.25rem;font-size:.75rem;font-weight:500;cursor:pointer;transition:all .2s ease;min-width:auto;white-space:nowrap}.cide-file-input-upload-status .cide-file-input-show-files-btn:hover{background:#2563eb;transform:translateY(-1px);box-shadow:0 2px 4px #3b82f633}.cide-file-input-upload-status .cide-file-input-show-files-btn:active{transform:translateY(0);box-shadow:0 1px 2px #3b82f61a}@media (prefers-color-scheme: dark){.cide-file-input-upload-status{background:#1e293b;border-color:#334155}.cide-file-input-upload-status .cide-file-input-upload-count{color:#94a3b8}.cide-file-input-upload-status .cide-file-input-upload-count .upload-count-text{color:#f1f5f9}.cide-file-input-upload-status .cide-file-input-show-files-btn{background:#3b82f6}.cide-file-input-upload-status .cide-file-input-show-files-btn:hover{background:#2563eb}}\n"] }]
4818
+ ], template: "<div class=\"cide-file-input\">\n <!-- Label (shown when not in preview box mode or when preview box mode but no label override) -->\n @if (labelSignal() && !isPreviewBoxMode()) {\n <label class=\"cide-file-input-label\" [attr.for]=\"'cide-file-input-' + id()\">\n {{ labelSignal() }}@if (requiredSignal()) {<span class=\"cide-file-input-required\"> *</span>}\n </label>\n }\n \n <!-- Preview Box Mode -->\n @if (isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview-box-container\">\n <!-- Hidden file input -->\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-hidden\"\n />\n \n <!-- Preview Box -->\n <div \n class=\"cide-file-input-preview-box\"\n [class.cide-file-input-preview-box-disabled]=\"disabledSignal()\"\n [class.cide-file-input-preview-box-has-image]=\"hasImages()\"\n [class.cide-file-input-preview-box-drag-over]=\"isDragOver()\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\"\n (click)=\"triggerFileSelect()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [attr.title]=\"disabledSignal() ? 'File selection disabled' : placeholderTextSignal()\">\n \n <!-- No Image State -->\n @if (!hasImages()) {\n <div class=\"cide-file-input-preview-box-placeholder\">\n <div class=\"cide-file-input-preview-box-icon\">\n <cide-ele-icon>{{ isDragOver() ? '\uD83D\uDCC1' : placeholderIconSignal() }}</cide-ele-icon>\n </div>\n <div class=\"cide-file-input-preview-box-text\">\n {{ isDragOver() ? 'Drop files here...' : placeholderTextSignal() }}\n </div>\n </div>\n }\n \n <!-- Image Preview State -->\n @if (hasImages()) {\n <div class=\"cide-file-input-preview-box-content\">\n <img \n [src]=\"previewUrls()[0]\" \n [alt]=\"fileNames()[0] || 'Preview image'\"\n class=\"cide-file-input-preview-box-image\">\n <div class=\"cide-file-input-preview-box-overlay\">\n <div class=\"cide-file-input-preview-box-overlay-text\">Click to change</div>\n </div>\n @if (!disabledSignal()) {\n <button \n type=\"button\" \n class=\"cide-file-input-preview-box-remove\"\n (click)=\"clearFiles(); $event.stopPropagation()\"\n title=\"Remove image\">\n \u00D7\n </button>\n }\n </div>\n }\n </div>\n \n <!-- File name display for preview box mode -->\n @if (hasImages() && fileNames().length && showFileNameSignal()) {\n <div class=\"cide-file-input-preview-box-filename\">\n {{ fileNames()[0] }}\n </div>\n }\n </div>\n }\n\n <!-- Standard Mode -->\n @if (!isPreviewBoxMode()) {\n <div \n class=\"cide-file-input-wrapper\"\n [class.cide-file-input-drag-over]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-element\"\n />\n @if (hasFiles()) {\n <button type=\"button\" class=\"cide-file-input-clear\" (click)=\"clearFiles()\">\n Clear\n </button>\n }\n </div>\n @if (hasFiles() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-files\">\n @if (multipleSignal() && fileNames().length > 1) {\n <!-- Show file count for multiple files -->\n <div class=\"cide-file-input-multiple-count\">\n {{ fileNames().length }} files selected\n </div>\n } @else {\n <!-- Show individual file names for single file or when only one file selected -->\n @for (name of fileNames(); track name) {\n <span>{{ name }}</span>\n }\n }\n <!-- Angular 20: Display file size using new computed values -->\n @if (totalFileSize() > 0) {\n <div class=\"cide-file-input-size\">\n Total size: {{ fileSizeInMB() }} MB\n </div>\n }\n </div>\n }\n }\n \n <!-- Image Preview Section (only for standard mode) -->\n @if (isImagePreviewAvailable() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview\">\n <div class=\"cide-file-input-preview-label\">Preview:</div>\n <div class=\"cide-file-input-preview-container\">\n @for (previewUrl of previewUrls(); track previewUrl; let i = $index) {\n <div \n class=\"cide-file-input-preview-item\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\">\n <button \n type=\"button\" \n class=\"cide-file-input-preview-remove\"\n (click)=\"removePreview(i)\"\n title=\"Remove image\">\n \u00D7\n </button>\n <img \n [src]=\"previewUrl\" \n [alt]=\"fileNames()[i] || 'Preview image'\"\n class=\"cide-file-input-preview-image\"\n loading=\"lazy\">\n <div class=\"cide-file-input-preview-filename\">{{ fileNames()[i] }}</div>\n </div>\n }\n </div>\n </div>\n }\n \n <!-- Upload Status and Show Files Button (only for multiple file inputs) -->\n @if (multiple && showFloatingUploaderSignal() && (getUploadCount() > 0 || hasActiveUploads() || hasEverUploaded())) {\n <div class=\"cide-file-input-upload-status\">\n <div class=\"cide-file-input-upload-count\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n <span class=\"upload-count-text\">\n @if (hasActiveUploads()) {\n {{ getActiveUploadCount() }} uploading\n } @else if (getUploadCount() > 0) {\n {{ getUploadCount() }} completed\n } @else if (hasEverUploaded()) {\n View uploads\n }\n </span>\n </div>\n <button \n type=\"button\" \n class=\"cide-file-input-show-files-icon\"\n (click)=\"showFloatingUploaderDialog()\"\n title=\"View upload progress and history\">\n <cide-ele-icon size=\"sm\">visibility</cide-ele-icon>\n </button>\n </div>\n }\n \n @if (errorTextSignal()) {\n <div class=\"cide-file-input-error\">{{ errorTextSignal() }}</div>\n }\n @if (helperTextSignal() && !errorTextSignal()) {\n <div class=\"cide-file-input-helper\">{{ helperTextSignal() }}</div>\n }\n</div> ", styles: [".cide-file-input{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-label{font-weight:500;margin-bottom:.25rem}.cide-file-input-required{color:#d32f2f;font-weight:700}.cide-file-input-wrapper{display:flex;align-items:center;gap:.5rem;border:2px dashed transparent;border-radius:.5rem;padding:.5rem;transition:all .2s ease-in-out}.cide-file-input-wrapper.cide-file-input-drag-over{border-color:#3b82f6;background-color:#eff6ff;transform:scale(1.02)}.cide-file-input-element{flex:1}.cide-file-input-clear{background:none;border:none;color:#d32f2f;cursor:pointer;font-size:.9rem}.cide-file-input-files{font-size:.95rem;color:#333;margin-top:.25rem}.cide-file-input-multiple-count{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;background-color:#f0f9ff;border:1px solid #0ea5e9;border-radius:.5rem;color:#0369a1;font-weight:500;font-size:.9rem}.cide-file-input-size{margin-top:.5rem;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;font-size:.75rem;color:#4b5563;font-weight:500}.cide-file-input-error{color:#d32f2f;font-size:.9rem}.cide-file-input-helper{color:#666;font-size:.9rem}.cide-file-input-preview{margin-top:.75rem;padding:.75rem;background-color:#f8f9fa;border:1px solid #e1e5e9;border-radius:.375rem}.cide-file-input-preview-label{font-weight:500;margin-bottom:.5rem;color:#374151;font-size:.875rem}.cide-file-input-preview-container{display:flex;flex-wrap:wrap;gap:.75rem}.cide-file-input-preview-item{position:relative;display:flex;flex-direction:column;border:1px solid #d1d5db;border-radius:.5rem;overflow:hidden;background-color:#fff;box-shadow:0 1px 3px #0000001a;transition:box-shadow .2s ease-in-out}.cide-file-input-preview-item:hover{box-shadow:0 4px 6px -1px #0000001a}.cide-file-input-preview-image{width:100%;height:calc(100% - 2rem);object-fit:cover;object-position:center;background-color:#f3f4f6}.cide-file-input-preview-filename{padding:.375rem .5rem;background-color:#f9fafbf2;border-top:1px solid #e5e7eb;font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:2rem;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-remove{position:absolute;top:.25rem;right:.25rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;transition:all .2s ease-in-out}.cide-file-input-preview-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-hidden{display:none}.cide-file-input-preview-box-container{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-preview-box{position:relative;border:2px dashed #d1d5db;border-radius:.5rem;cursor:pointer;background-color:#f9fafb;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:all .2s ease-in-out}.cide-file-input-preview-box:hover{border-color:#3b82f6;background-color:#eff6ff}.cide-file-input-preview-box.cide-file-input-preview-box-disabled{cursor:not-allowed;opacity:.6;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-disabled:hover{border-color:#d1d5db;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image{border-style:solid;border-color:#e5e7eb;padding:0}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover{border-color:#3b82f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover .cide-file-input-preview-box-overlay{opacity:1}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over{border-color:#3b82f6!important;background-color:#eff6ff!important;transform:scale(1.02);box-shadow:0 0 0 4px #3b82f61a}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-icon{color:#3b82f6;transform:scale(1.1)}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-text{color:#3b82f6;font-weight:600}.cide-file-input-preview-box-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1rem;text-align:center}.cide-file-input-preview-box-icon{font-size:2rem;color:#6b7280}.cide-file-input-preview-box-text{font-size:.875rem;color:#6b7280;font-weight:500}.cide-file-input-preview-box-content{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-box-image{width:100%;height:100%;object-fit:cover;object-position:center}.cide-file-input-preview-box-overlay{position:absolute;inset:0;background-color:#0009;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out}.cide-file-input-preview-box-overlay-text{color:#fff;font-size:.875rem;font-weight:500;text-align:center}.cide-file-input-preview-box-remove{position:absolute;top:.375rem;right:.375rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:20;transition:all .2s ease-in-out}.cide-file-input-preview-box-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-box-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-preview-box-filename{font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;margin-top:.25rem}@media (max-width: 640px){.cide-file-input-preview-container{justify-content:center}.cide-file-input-preview-item{min-width:120px;max-width:150px}.cide-file-input-preview-box-icon{font-size:1.5rem}.cide-file-input-preview-box-text{font-size:.75rem}}.cide-file-input-upload-status{display:flex;align-items:center;justify-content:space-between;padding:.5rem .75rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:.375rem;margin-top:.5rem;gap:.75rem}.cide-file-input-upload-status .cide-file-input-upload-count{display:flex;align-items:center;gap:.5rem;color:#64748b;font-size:.875rem;font-weight:500}.cide-file-input-upload-status .cide-file-input-upload-count .upload-count-text{color:#1e293b}.cide-file-input-upload-status .cide-file-input-show-files-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;background:transparent;color:#6b7280;border:none;border-radius:.25rem;cursor:pointer;transition:all .2s ease}.cide-file-input-upload-status .cide-file-input-show-files-icon:hover{background:#f3f4f6;color:#3b82f6}.cide-file-input-upload-status .cide-file-input-show-files-icon:active{background:#e5e7eb}@media (prefers-color-scheme: dark){.cide-file-input-upload-status{background:#1e293b;border-color:#334155}.cide-file-input-upload-status .cide-file-input-upload-count{color:#94a3b8}.cide-file-input-upload-status .cide-file-input-upload-count .upload-count-text{color:#f1f5f9}.cide-file-input-upload-status .cide-file-input-show-files-icon{color:#94a3b8}.cide-file-input-upload-status .cide-file-input-show-files-icon:hover{background:#374151;color:#60a5fa}.cide-file-input-upload-status .cide-file-input-show-files-icon:active{background:#4b5563}}\n"] }]
4610
4819
  }], ctorParameters: () => [], propDecorators: { label: [{
4611
4820
  type: Input
4612
4821
  }], accept: [{
@@ -4653,488 +4862,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
4653
4862
  type: Output
4654
4863
  }] } });
4655
4864
 
4656
- class CideEleGlobalFileUploaderComponent {
4657
- // Dependency injection
4658
- destroyRef = inject(DestroyRef);
4659
- fileService = inject(CideEleFileManagerService);
4660
- // Input properties
4661
- userId = '';
4662
- multiple = true;
4663
- accept = '';
4664
- maxFileSize = 10; // MB
4665
- allowedTypes = [];
4666
- // Output events
4667
- uploadComplete = new EventEmitter();
4668
- uploadError = new EventEmitter();
4669
- uploadCancelled = new EventEmitter();
4670
- allUploadsComplete = new EventEmitter();
4671
- // Signals for reactive state management
4672
- isDragOver = signal(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : []));
4673
- isUploading = signal(false, ...(ngDevMode ? [{ debugName: "isUploading" }] : []));
4674
- uploadQueue = signal([], ...(ngDevMode ? [{ debugName: "uploadQueue" }] : []));
4675
- currentGroupId = signal(null, ...(ngDevMode ? [{ debugName: "currentGroupId" }] : []));
4676
- // Computed values
4677
- hasUploads = computed(() => this.uploadQueue().length > 0, ...(ngDevMode ? [{ debugName: "hasUploads" }] : []));
4678
- pendingUploads = computed(() => this.uploadQueue().filter(upload => upload.status === 'pending'), ...(ngDevMode ? [{ debugName: "pendingUploads" }] : []));
4679
- activeUploads = computed(() => this.uploadQueue().filter(upload => upload.status === 'uploading'), ...(ngDevMode ? [{ debugName: "activeUploads" }] : []));
4680
- completedUploads = computed(() => this.uploadQueue().filter(upload => upload.status === 'completed'), ...(ngDevMode ? [{ debugName: "completedUploads" }] : []));
4681
- failedUploads = computed(() => this.uploadQueue().filter(upload => upload.status === 'error'), ...(ngDevMode ? [{ debugName: "failedUploads" }] : []));
4682
- constructor() {
4683
- console.log('🚀 [GlobalFileUploader] Component initialized');
4684
- }
4685
- /**
4686
- * Handle drag over event
4687
- */
4688
- onDragOver(event) {
4689
- event.preventDefault();
4690
- event.stopPropagation();
4691
- this.isDragOver.set(true);
4692
- }
4693
- /**
4694
- * Handle drag leave event
4695
- */
4696
- onDragLeave(event) {
4697
- event.preventDefault();
4698
- event.stopPropagation();
4699
- this.isDragOver.set(false);
4700
- }
4701
- /**
4702
- * Handle drop event
4703
- */
4704
- onDrop(event) {
4705
- event.preventDefault();
4706
- event.stopPropagation();
4707
- this.isDragOver.set(false);
4708
- const files = event.dataTransfer?.files;
4709
- if (files && files.length > 0) {
4710
- this.addFilesToQueue(Array.from(files));
4711
- }
4712
- }
4713
- /**
4714
- * Handle file input change
4715
- */
4716
- onFileInputChange(event) {
4717
- const target = event.target;
4718
- const files = target.files;
4719
- if (files && files.length > 0) {
4720
- this.addFilesToQueue(Array.from(files));
4721
- }
4722
- // Reset input value to allow selecting the same file again
4723
- target.value = '';
4724
- }
4725
- /**
4726
- * Add files to upload queue
4727
- */
4728
- addFilesToQueue(files) {
4729
- // Validate files
4730
- const validFiles = files.filter(file => this.validateFile(file));
4731
- if (validFiles.length === 0) {
4732
- console.warn('⚠️ [GlobalFileUploader] No valid files to upload');
4733
- return;
4734
- }
4735
- const newUploads = validFiles.map(file => ({
4736
- fileId: this.generateFileId(file),
4737
- fileName: file.name,
4738
- progress: 0,
4739
- status: 'pending',
4740
- file: file
4741
- }));
4742
- this.uploadQueue.update(queue => [...queue, ...newUploads]);
4743
- this.processUploadQueue();
4744
- }
4745
- /**
4746
- * Validate file
4747
- */
4748
- validateFile(file) {
4749
- // Check file size
4750
- const maxSizeBytes = this.maxFileSize * 1024 * 1024;
4751
- if (file.size > maxSizeBytes) {
4752
- console.warn(`⚠️ [GlobalFileUploader] File ${file.name} exceeds size limit`);
4753
- return false;
4754
- }
4755
- // Check file type
4756
- if (this.allowedTypes.length > 0 && !this.allowedTypes.includes(file.type)) {
4757
- console.warn(`⚠️ [GlobalFileUploader] File type ${file.type} not allowed`);
4758
- return false;
4759
- }
4760
- return true;
4761
- }
4762
- /**
4763
- * Process upload queue
4764
- */
4765
- processUploadQueue() {
4766
- const pendingUploads = this.uploadQueue().filter(upload => upload.status === 'pending');
4767
- if (pendingUploads.length > 0 && !this.isUploading()) {
4768
- this.isUploading.set(true);
4769
- if (this.multiple && pendingUploads.length > 1) {
4770
- // Multiple file upload with group ID
4771
- this.uploadMultipleFiles(pendingUploads);
4772
- }
4773
- else {
4774
- // Single file upload
4775
- this.uploadNextFile();
4776
- }
4777
- }
4778
- }
4779
- /**
4780
- * Upload multiple files with group ID
4781
- */
4782
- uploadMultipleFiles(uploads) {
4783
- console.log('📤 [GlobalFileUploader] Starting multiple file upload for:', uploads.length, 'files');
4784
- // Generate group ID first
4785
- this.fileService.generateObjectId()
4786
- .pipe(takeUntilDestroyed(this.destroyRef))
4787
- .subscribe({
4788
- next: (response) => {
4789
- const groupId = response.data?.objectId;
4790
- console.log('🆔 [GlobalFileUploader] Generated group ID:', groupId);
4791
- this.currentGroupId.set(groupId || null);
4792
- if (groupId) {
4793
- // Upload all files with the same group ID
4794
- this.uploadFilesWithGroupId(uploads, groupId);
4795
- }
4796
- else {
4797
- console.error('❌ [GlobalFileUploader] No group ID received');
4798
- this.handleUploadError('Failed to generate group ID', uploads[0]?.fileId);
4799
- }
4800
- },
4801
- error: (error) => {
4802
- console.error('❌ [GlobalFileUploader] Failed to generate group ID:', error);
4803
- this.handleUploadError('Failed to generate group ID', uploads[0]?.fileId);
4804
- }
4805
- });
4806
- }
4807
- /**
4808
- * Upload files with group ID
4809
- */
4810
- uploadFilesWithGroupId(uploads, groupId) {
4811
- let completedCount = 0;
4812
- let failedCount = 0;
4813
- const totalFiles = uploads.length;
4814
- const uploadedFiles = [];
4815
- uploads.forEach((upload, index) => {
4816
- // Update status to uploading
4817
- this.updateUploadStatus(upload.fileId, 'uploading', 0);
4818
- const uploadRequest = {
4819
- file: upload.file,
4820
- userId: this.userId,
4821
- groupId: groupId,
4822
- tags: [],
4823
- permissions: ['read', 'write']
4824
- };
4825
- this.fileService.uploadFile(upload.file, this.convertToFileUploadOptions(uploadRequest), (progress) => {
4826
- // Use the original fileId for progress updates during upload
4827
- this.updateUploadProgress(upload.fileId, progress);
4828
- })
4829
- .pipe(takeUntilDestroyed(this.destroyRef))
4830
- .subscribe({
4831
- next: (response) => {
4832
- completedCount++;
4833
- console.log(`✅ [GlobalFileUploader] File ${index + 1}/${totalFiles} uploaded successfully`);
4834
- // Find the upload item by cyfm_temp_unique_id from response
4835
- const responseFile = response?.data?.core_file_manager?.[0];
4836
- const tempUniqueId = responseFile?.cyfm_temp_unique_id;
4837
- console.log('🔍 [GlobalFileUploader] Response tempUniqueId:', tempUniqueId);
4838
- console.log('🔍 [GlobalFileUploader] Original upload fileId:', upload.fileId);
4839
- // Use the tempUniqueId to find and update the correct upload item
4840
- if (tempUniqueId) {
4841
- this.updateUploadStatusByTempId(tempUniqueId, 'completed', 100, undefined, response);
4842
- }
4843
- else {
4844
- // Fallback to original fileId
4845
- this.updateUploadStatus(upload.fileId, 'completed', 100, undefined, response);
4846
- }
4847
- this.uploadComplete.emit({
4848
- fileId: tempUniqueId || upload.fileId,
4849
- fileName: upload.fileName,
4850
- progress: 100,
4851
- status: 'completed',
4852
- uploadedFile: response
4853
- });
4854
- if (responseFile) {
4855
- uploadedFiles.push(responseFile);
4856
- }
4857
- console.log('🔍 [GlobalFileUploader] Upload response received:', response);
4858
- console.log('🔍 [GlobalFileUploader] Response data structure:', response?.data);
4859
- // Check if all files are completed
4860
- if (completedCount + failedCount === totalFiles) {
4861
- this.handleMultipleUploadComplete(completedCount, failedCount, groupId, uploadedFiles);
4862
- }
4863
- },
4864
- error: (error) => {
4865
- failedCount++;
4866
- console.error(`❌ [GlobalFileUploader] File ${index + 1}/${totalFiles} upload failed:`, error);
4867
- this.updateUploadStatus(upload.fileId, 'error', 0, error.message || 'Upload failed');
4868
- this.uploadError.emit({
4869
- fileId: upload.fileId,
4870
- error: error.message || 'Upload failed'
4871
- });
4872
- // Check if all files are completed
4873
- if (completedCount + failedCount === totalFiles) {
4874
- this.handleMultipleUploadComplete(completedCount, failedCount, groupId, uploadedFiles);
4875
- }
4876
- }
4877
- });
4878
- });
4879
- }
4880
- /**
4881
- * Handle multiple upload completion
4882
- */
4883
- handleMultipleUploadComplete(completed, failed, groupId, uploadedFiles) {
4884
- console.log(`📊 [GlobalFileUploader] Multiple upload complete: ${completed}/${completed + failed} successful`);
4885
- this.isUploading.set(false);
4886
- if (completed > 0) {
4887
- this.allUploadsComplete.emit({
4888
- groupId: groupId,
4889
- uploadedFiles: uploadedFiles
4890
- });
4891
- }
4892
- }
4893
- /**
4894
- * Upload next file in queue (single file mode)
4895
- */
4896
- uploadNextFile() {
4897
- const pendingUpload = this.uploadQueue().find(upload => upload.status === 'pending');
4898
- if (!pendingUpload) {
4899
- this.isUploading.set(false);
4900
- return;
4901
- }
4902
- // Update status to uploading
4903
- this.updateUploadStatus(pendingUpload.fileId, 'uploading', 0);
4904
- const uploadRequest = {
4905
- file: pendingUpload.file,
4906
- userId: this.userId,
4907
- tags: [],
4908
- permissions: ['read', 'write']
4909
- };
4910
- this.fileService.uploadFile(pendingUpload.file, this.convertToFileUploadOptions(uploadRequest), (progress) => {
4911
- this.updateUploadProgress(pendingUpload.fileId, progress);
4912
- })
4913
- .pipe(takeUntilDestroyed(this.destroyRef))
4914
- .subscribe({
4915
- next: (response) => {
4916
- console.log('✅ [GlobalFileUploader] Single file upload successful:', response);
4917
- // Find the upload item by cyfm_temp_unique_id from response
4918
- const responseFile = response?.data?.core_file_manager?.[0];
4919
- const tempUniqueId = responseFile?.cyfm_temp_unique_id;
4920
- console.log('🔍 [GlobalFileUploader] Single upload - Response tempUniqueId:', tempUniqueId);
4921
- console.log('🔍 [GlobalFileUploader] Single upload - Original upload fileId:', pendingUpload.fileId);
4922
- // Use the tempUniqueId to find and update the correct upload item
4923
- if (tempUniqueId) {
4924
- this.updateUploadStatusByTempId(tempUniqueId, 'completed', 100, undefined, response);
4925
- }
4926
- else {
4927
- // Fallback to original fileId
4928
- this.updateUploadStatus(pendingUpload.fileId, 'completed', 100, undefined, response);
4929
- }
4930
- this.uploadComplete.emit({
4931
- fileId: tempUniqueId || pendingUpload.fileId,
4932
- fileName: pendingUpload.fileName,
4933
- progress: 100,
4934
- status: 'completed',
4935
- uploadedFile: response
4936
- });
4937
- // Process next file
4938
- setTimeout(() => this.uploadNextFile(), 500);
4939
- },
4940
- error: (error) => {
4941
- console.error('❌ [GlobalFileUploader] Upload error:', error);
4942
- this.updateUploadStatus(pendingUpload.fileId, 'error', 0, error.message || 'Upload failed');
4943
- this.uploadError.emit({
4944
- fileId: pendingUpload.fileId,
4945
- error: error.message || 'Upload failed'
4946
- });
4947
- // Process next file
4948
- setTimeout(() => this.uploadNextFile(), 500);
4949
- }
4950
- });
4951
- }
4952
- /**
4953
- * Update upload progress
4954
- */
4955
- updateUploadProgress(fileId, progress) {
4956
- this.uploadQueue.update(queue => queue.map(upload => upload.fileId === fileId
4957
- ? { ...upload, progress }
4958
- : upload));
4959
- }
4960
- /**
4961
- * Update upload status
4962
- */
4963
- updateUploadStatus(fileId, status, progress, error, uploadedFile) {
4964
- console.log('🔄 [GlobalFileUploader] Updating upload status:', { fileId, status, progress, error: !!error, uploadedFile: !!uploadedFile });
4965
- this.uploadQueue.update(queue => {
4966
- const updatedQueue = queue.map(upload => {
4967
- if (upload.fileId === fileId) {
4968
- console.log('🔄 [GlobalFileUploader] Found upload to update:', upload.fileName, 'from', upload.status, 'to', status);
4969
- return { ...upload, status, progress, error, uploadedFile };
4970
- }
4971
- return upload;
4972
- });
4973
- console.log('🔄 [GlobalFileUploader] Updated queue:', updatedQueue.map(u => ({ fileName: u.fileName, status: u.status })));
4974
- return updatedQueue;
4975
- });
4976
- }
4977
- /**
4978
- * Update upload status by cyfm_temp_unique_id
4979
- */
4980
- updateUploadStatusByTempId(tempUniqueId, status, progress, error, uploadedFile) {
4981
- console.log('🔄 [GlobalFileUploader] Updating upload status by tempId:', { tempUniqueId, status, progress, error: !!error, uploadedFile: !!uploadedFile });
4982
- this.uploadQueue.update(queue => {
4983
- const updatedQueue = queue.map(upload => {
4984
- // Check if this upload's fileId matches the tempUniqueId
4985
- if (upload.fileId === tempUniqueId) {
4986
- console.log('🔄 [GlobalFileUploader] Found upload by tempId to update:', upload.fileName, 'from', upload.status, 'to', status);
4987
- return { ...upload, status, progress, error, uploadedFile };
4988
- }
4989
- return upload;
4990
- });
4991
- console.log('🔄 [GlobalFileUploader] Updated queue by tempId:', updatedQueue.map(u => ({ fileName: u.fileName, status: u.status, fileId: u.fileId })));
4992
- return updatedQueue;
4993
- });
4994
- }
4995
- /**
4996
- * Handle upload error
4997
- */
4998
- handleUploadError(error, fileId) {
4999
- if (fileId) {
5000
- this.updateUploadStatus(fileId, 'error', 0, error);
5001
- this.uploadError.emit({ fileId, error });
5002
- }
5003
- this.isUploading.set(false);
5004
- }
5005
- /**
5006
- * Cancel upload
5007
- */
5008
- cancelUpload(fileId) {
5009
- this.updateUploadStatus(fileId, 'cancelled', 0);
5010
- this.uploadCancelled.emit(fileId);
5011
- // Remove from queue after a delay
5012
- setTimeout(() => {
5013
- this.uploadQueue.update(queue => queue.filter(upload => upload.fileId !== fileId));
5014
- }, 1000);
5015
- }
5016
- /**
5017
- * Retry upload
5018
- */
5019
- retryUpload(fileId) {
5020
- this.updateUploadStatus(fileId, 'pending', 0);
5021
- this.processUploadQueue();
5022
- }
5023
- /**
5024
- * Remove upload from queue
5025
- */
5026
- removeUpload(fileId) {
5027
- this.uploadQueue.update(queue => queue.filter(upload => upload.fileId !== fileId));
5028
- }
5029
- /**
5030
- * Clear completed uploads
5031
- */
5032
- clearCompleted() {
5033
- this.uploadQueue.update(queue => queue.filter(upload => upload.status !== 'completed'));
5034
- }
5035
- /**
5036
- * Clear all uploads
5037
- */
5038
- clearAll() {
5039
- this.uploadQueue.set([]);
5040
- this.currentGroupId.set(null);
5041
- }
5042
- /**
5043
- * Get status icon
5044
- */
5045
- getStatusIcon(status) {
5046
- switch (status) {
5047
- case 'pending': return 'schedule';
5048
- case 'uploading': return 'cloud_upload';
5049
- case 'completed': return 'check_circle';
5050
- case 'error': return 'error';
5051
- case 'cancelled': return 'cancel';
5052
- default: return 'help';
5053
- }
5054
- }
5055
- /**
5056
- * Get status class
5057
- */
5058
- getStatusClass(status) {
5059
- switch (status) {
5060
- case 'pending': return 'status-pending';
5061
- case 'uploading': return 'status-uploading';
5062
- case 'completed': return 'status-completed';
5063
- case 'error': return 'status-error';
5064
- case 'cancelled': return 'status-cancelled';
5065
- default: return 'status-unknown';
5066
- }
5067
- }
5068
- /**
5069
- * Get file size display
5070
- */
5071
- getFileSizeDisplay(file) {
5072
- const bytes = file.size;
5073
- if (bytes === 0)
5074
- return '0 Bytes';
5075
- const k = 1024;
5076
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
5077
- const i = Math.floor(Math.log(bytes) / Math.log(k));
5078
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
5079
- }
5080
- /**
5081
- * Generate unique file ID - this should match the service's generateFileId method
5082
- * The service uses: ${file.name}_${file.size}_${Date.now()}
5083
- */
5084
- generateFileId(file) {
5085
- return `${file.name}_${file.size}_${Date.now()}`;
5086
- }
5087
- /**
5088
- * Convert IFileUploadRequest to FileUploadOptions
5089
- */
5090
- convertToFileUploadOptions(request) {
5091
- return {
5092
- altText: request.altText,
5093
- userId: request.userId,
5094
- permissions: request.permissions,
5095
- tags: request.tags,
5096
- groupId: request.groupId
5097
- };
5098
- }
5099
- /**
5100
- * Trigger file input click
5101
- */
5102
- triggerFileInput() {
5103
- const fileInput = document.getElementById('global-file-input');
5104
- if (fileInput) {
5105
- fileInput.click();
5106
- }
5107
- }
5108
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleGlobalFileUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5109
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleGlobalFileUploaderComponent, isStandalone: true, selector: "cide-ele-global-file-uploader", inputs: { userId: "userId", multiple: "multiple", accept: "accept", maxFileSize: "maxFileSize", allowedTypes: "allowedTypes" }, outputs: { uploadComplete: "uploadComplete", uploadError: "uploadError", uploadCancelled: "uploadCancelled", allUploadsComplete: "allUploadsComplete" }, ngImport: i0, template: "<!-- Global File Uploader Component -->\r\n<div class=\"global-file-uploader\">\r\n\r\n <!-- Hidden file input -->\r\n <input id=\"global-file-input\" type=\"file\" [multiple]=\"multiple\" [accept]=\"accept\" \r\n (change)=\"onFileInputChange($event)\" style=\"display: none;\">\r\n\r\n <!-- Drag and Drop Zone -->\r\n <div class=\"upload-zone\" [class.drag-over]=\"isDragOver()\" (dragover)=\"onDragOver($event)\"\r\n (dragleave)=\"onDragLeave($event)\" (drop)=\"onDrop($event)\" (click)=\"triggerFileInput()\">\r\n\r\n <div class=\"upload-zone-content\">\r\n <cide-ele-icon name=\"cloud_upload\" class=\"upload-icon\" size=\"lg\">\r\n </cide-ele-icon>\r\n\r\n <h3 class=\"upload-title\">\r\n {{ isDragOver() ? 'Drop files here' : 'Upload Files' }}\r\n </h3>\r\n\r\n <p class=\"upload-subtitle\">\r\n {{ isDragOver() ? 'Release to upload' : 'Drag and drop files here or click to browse' }}\r\n </p>\r\n\r\n <button cideEleButton cideEleButton variant=\"outline\" size=\"sm\"\r\n (click)=\"triggerFileInput(); $event.stopPropagation()\">\r\n <cide-ele-icon name=\"add\" size=\"sm\"></cide-ele-icon>\r\n Choose Files\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Upload Queue -->\r\n @if (hasUploads()) {\r\n <div class=\"upload-queue\">\r\n <div class=\"queue-header\">\r\n <h4 class=\"queue-title\">Upload Queue</h4>\r\n <div class=\"queue-actions\">\r\n @if (completedUploads().length > 0) {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"clearCompleted()\">\r\n Clear Completed\r\n </button>\r\n }\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"clearAll()\">\r\n Clear All\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"queue-items\">\r\n @for (upload of uploadQueue(); track upload.fileId) {\r\n <div class=\"upload-item\" [class]=\"getStatusClass(upload.status)\">\r\n\r\n <!-- File Info -->\r\n <div class=\"file-info\">\r\n <cide-ele-icon class=\"status-icon\" size=\"sm\">\r\n {{getStatusIcon(upload.status)}}\r\n </cide-ele-icon>\r\n\r\n <div class=\"file-details\">\r\n <div class=\"file-name\">{{ upload.fileName }}</div>\r\n @if (upload.file) {\r\n <div class=\"file-size\">{{ getFileSizeDisplay(upload.file) }}</div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Progress Bar -->\r\n @if (upload.status === 'uploading') {\r\n <div class=\"progress-container\">\r\n <div class=\"progress-bar\">\r\n <div class=\"progress-fill\" [style.width.%]=\"upload.progress\">\r\n </div>\r\n </div>\r\n <span class=\"progress-text\">{{ upload.progress }}%</span>\r\n </div>\r\n }\r\n\r\n <!-- Status Text -->\r\n @if (upload.status !== 'uploading') {\r\n <div class=\"status-text\">\r\n @switch (upload.status) {\r\n @case ('pending') {\r\n <span class=\"text-yellow-600\">Waiting...</span>\r\n }\r\n @case ('completed') {\r\n <span class=\"text-green-600\">Uploaded successfully</span>\r\n }\r\n @case ('error') {\r\n <span class=\"text-red-600\">{{ upload.error || 'Upload failed' }}</span>\r\n }\r\n @case ('cancelled') {\r\n <span class=\"text-gray-600\">Cancelled</span>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Actions -->\r\n <div class=\"upload-actions\">\r\n @switch (upload.status) {\r\n @case ('pending') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"cancelUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"cancel\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n @case ('uploading') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"cancelUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"cancel\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n @case ('completed') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"removeUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"close\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n @case ('error') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"retryUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"refresh\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"removeUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"close\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n @case ('cancelled') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"removeUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"close\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Queue Summary -->\r\n <div class=\"queue-summary\">\r\n <div class=\"summary-stats\">\r\n <span class=\"stat\">\r\n <cide-ele-icon name=\"schedule\" size=\"xs\"></cide-ele-icon>\r\n {{ pendingUploads().length }} pending\r\n </span>\r\n <span class=\"stat\">\r\n <cide-ele-icon name=\"cloud_upload\" size=\"xs\"></cide-ele-icon>\r\n {{ activeUploads().length }} uploading\r\n </span>\r\n <span class=\"stat\">\r\n <cide-ele-icon name=\"check_circle\" size=\"xs\"></cide-ele-icon>\r\n {{ completedUploads().length }} completed\r\n </span>\r\n @if (failedUploads().length > 0) {\r\n <span class=\"stat error\">\r\n <cide-ele-icon name=\"error\" size=\"xs\"></cide-ele-icon>\r\n {{ failedUploads().length }} failed\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n", styles: [".global-file-uploader{@apply tw-w-full tw-max-w-2xl tw-mx-auto tw-p-4;}.global-file-uploader .upload-zone{@apply tw-border-2 tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-p-8 tw-text-center tw-cursor-pointer tw-transition-all tw-duration-200 tw-ease-in-out;@apply hover:tw-border-blue-400 hover:tw-bg-blue-50;}.global-file-uploader .upload-zone.drag-over{@apply tw-border-blue-500 tw-bg-blue-100 tw-scale-105;}.global-file-uploader .upload-zone .upload-zone-content{@apply tw-space-y-4;}.global-file-uploader .upload-zone .upload-zone-content .upload-icon{@apply tw-text-gray-400 tw-mx-auto;}.global-file-uploader .upload-zone .upload-zone-content .upload-title{@apply tw-text-xl tw-font-semibold tw-text-gray-700 tw-m-0;}.global-file-uploader .upload-zone .upload-zone-content .upload-subtitle{@apply tw-text-sm tw-text-gray-500 tw-m-0;}.global-file-uploader .upload-queue{@apply tw-mt-6 tw-bg-white tw-border tw-border-gray-200 tw-rounded-lg tw-shadow-sm;}.global-file-uploader .upload-queue .queue-header{@apply tw-flex tw-justify-between tw-items-center tw-p-4 tw-border-b tw-border-gray-200;}.global-file-uploader .upload-queue .queue-header .queue-title{@apply tw-text-lg tw-font-medium tw-text-gray-700 tw-m-0;}.global-file-uploader .upload-queue .queue-header .queue-actions{@apply tw-flex tw-space-x-2;}.global-file-uploader .upload-queue .queue-items{@apply tw-max-h-96 tw-overflow-y-auto;}.global-file-uploader .upload-queue .queue-items .upload-item{@apply tw-flex tw-items-center tw-justify-between tw-p-4 tw-border-b tw-border-gray-100 tw-transition-colors tw-duration-200;}.global-file-uploader .upload-queue .queue-items .upload-item:last-child{@apply tw-border-b-0;}.global-file-uploader .upload-queue .queue-items .upload-item.status-pending{@apply tw-bg-yellow-50;}.global-file-uploader .upload-queue .queue-items .upload-item.status-uploading{@apply tw-bg-blue-50;}.global-file-uploader .upload-queue .queue-items .upload-item.status-completed{@apply tw-bg-green-50;}.global-file-uploader .upload-queue .queue-items .upload-item.status-error{@apply tw-bg-red-50;}.global-file-uploader .upload-queue .queue-items .upload-item.status-cancelled{@apply tw-bg-gray-50;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info{@apply tw-flex tw-items-center tw-flex-1 tw-min-w-0;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .status-icon{@apply tw-mr-3 tw-flex-shrink-0;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details{@apply tw-min-w-0 tw-flex-1;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details .file-name{@apply tw-text-sm tw-font-medium tw-text-gray-700 tw-truncate;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details .file-size{@apply tw-text-xs tw-text-gray-500 tw-mt-1;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container{@apply tw-flex tw-items-center tw-space-x-3 tw-flex-1 tw-max-w-xs tw-mx-4;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-bar{@apply tw-flex-1 tw-h-2 tw-bg-gray-200 tw-rounded-full tw-overflow-hidden;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-bar .progress-fill{@apply tw-h-full tw-bg-blue-500 tw-transition-all tw-duration-300 tw-ease-out;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-text{@apply tw-text-xs tw-font-medium tw-text-gray-600 tw-min-w-12 tw-text-right;}.global-file-uploader .upload-queue .queue-items .upload-item .status-text{@apply tw-flex-1 tw-text-sm tw-text-center;}.global-file-uploader .upload-queue .queue-items .upload-item .status-text span{@apply tw-font-medium;}.global-file-uploader .upload-queue .queue-items .upload-item .upload-actions{@apply tw-flex tw-space-x-1 tw-ml-4;}.global-file-uploader .upload-queue .queue-summary{@apply tw-p-4 tw-bg-gray-50 tw-border-t tw-border-gray-200;}.global-file-uploader .upload-queue .queue-summary .summary-stats{@apply tw-flex tw-flex-wrap tw-gap-4 tw-text-sm tw-text-gray-600;}.global-file-uploader .upload-queue .queue-summary .summary-stats .stat{@apply tw-flex tw-items-center tw-space-x-1;}.global-file-uploader .upload-queue .queue-summary .summary-stats .stat.error{@apply tw-text-red-600;}@media (max-width: 640px){.global-file-uploader{@apply tw-p-2;}.global-file-uploader .upload-zone{@apply tw-p-6;}.global-file-uploader .upload-zone .upload-zone-content .upload-title{@apply tw-text-lg;}.global-file-uploader .upload-zone .upload-zone-content .upload-subtitle{@apply tw-text-xs;}.global-file-uploader .upload-queue .queue-header{@apply tw-p-3 tw-flex-col tw-space-y-2 tw-items-start;}.global-file-uploader .upload-queue .queue-header .queue-actions{@apply tw-w-full tw-justify-end;}.global-file-uploader .upload-queue .queue-items .upload-item{@apply tw-p-3 tw-flex-col tw-space-y-3 tw-items-start;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info{@apply tw-w-full;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container{@apply tw-w-full tw-mx-0;}.global-file-uploader .upload-queue .queue-items .upload-item .status-text{@apply tw-w-full tw-text-left;}.global-file-uploader .upload-queue .queue-items .upload-item .upload-actions{@apply tw-w-full tw-justify-end tw-ml-0;}}@media (prefers-color-scheme: dark){.global-file-uploader .upload-zone{@apply tw-border-gray-600 hover:tw-border-blue-400 hover:tw-bg-gray-800;}.global-file-uploader .upload-zone.drag-over{@apply tw-bg-blue-900;}.global-file-uploader .upload-zone .upload-zone-content .upload-icon{@apply tw-text-gray-500;}.global-file-uploader .upload-zone .upload-zone-content .upload-title{@apply tw-text-gray-200;}.global-file-uploader .upload-zone .upload-zone-content .upload-subtitle{@apply tw-text-gray-400;}.global-file-uploader .upload-queue{@apply tw-bg-gray-800 tw-border-gray-700;}.global-file-uploader .upload-queue .queue-header{@apply tw-border-gray-700;}.global-file-uploader .upload-queue .queue-header .queue-title{@apply tw-text-gray-200;}.global-file-uploader .upload-queue .queue-items .upload-item{@apply tw-border-gray-700;}.global-file-uploader .upload-queue .queue-items .upload-item.status-pending{@apply tw-bg-yellow-900;}.global-file-uploader .upload-queue .queue-items .upload-item.status-uploading{@apply tw-bg-blue-900;}.global-file-uploader .upload-queue .queue-items .upload-item.status-completed{@apply tw-bg-green-900;}.global-file-uploader .upload-queue .queue-items .upload-item.status-error{@apply tw-bg-red-900;}.global-file-uploader .upload-queue .queue-items .upload-item.status-cancelled{@apply tw-bg-gray-700;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details .file-name{@apply tw-text-gray-200;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details .file-size{@apply tw-text-gray-400;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-bar{@apply tw-bg-gray-600;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-text{@apply tw-text-gray-300;}.global-file-uploader .upload-queue .queue-summary{@apply tw-bg-gray-700 tw-border-gray-600;}.global-file-uploader .upload-queue .queue-summary .summary-stats{@apply tw-text-gray-300;}.global-file-uploader .upload-queue .queue-summary .summary-stats .stat.error{@apply tw-text-red-400;}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton]", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
5110
- }
5111
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleGlobalFileUploaderComponent, decorators: [{
5112
- type: Component,
5113
- args: [{ selector: 'cide-ele-global-file-uploader', standalone: true, imports: [
5114
- CommonModule,
5115
- CideEleButtonComponent,
5116
- CideIconComponent
5117
- ], template: "<!-- Global File Uploader Component -->\r\n<div class=\"global-file-uploader\">\r\n\r\n <!-- Hidden file input -->\r\n <input id=\"global-file-input\" type=\"file\" [multiple]=\"multiple\" [accept]=\"accept\" \r\n (change)=\"onFileInputChange($event)\" style=\"display: none;\">\r\n\r\n <!-- Drag and Drop Zone -->\r\n <div class=\"upload-zone\" [class.drag-over]=\"isDragOver()\" (dragover)=\"onDragOver($event)\"\r\n (dragleave)=\"onDragLeave($event)\" (drop)=\"onDrop($event)\" (click)=\"triggerFileInput()\">\r\n\r\n <div class=\"upload-zone-content\">\r\n <cide-ele-icon name=\"cloud_upload\" class=\"upload-icon\" size=\"lg\">\r\n </cide-ele-icon>\r\n\r\n <h3 class=\"upload-title\">\r\n {{ isDragOver() ? 'Drop files here' : 'Upload Files' }}\r\n </h3>\r\n\r\n <p class=\"upload-subtitle\">\r\n {{ isDragOver() ? 'Release to upload' : 'Drag and drop files here or click to browse' }}\r\n </p>\r\n\r\n <button cideEleButton cideEleButton variant=\"outline\" size=\"sm\"\r\n (click)=\"triggerFileInput(); $event.stopPropagation()\">\r\n <cide-ele-icon name=\"add\" size=\"sm\"></cide-ele-icon>\r\n Choose Files\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Upload Queue -->\r\n @if (hasUploads()) {\r\n <div class=\"upload-queue\">\r\n <div class=\"queue-header\">\r\n <h4 class=\"queue-title\">Upload Queue</h4>\r\n <div class=\"queue-actions\">\r\n @if (completedUploads().length > 0) {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"clearCompleted()\">\r\n Clear Completed\r\n </button>\r\n }\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"clearAll()\">\r\n Clear All\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"queue-items\">\r\n @for (upload of uploadQueue(); track upload.fileId) {\r\n <div class=\"upload-item\" [class]=\"getStatusClass(upload.status)\">\r\n\r\n <!-- File Info -->\r\n <div class=\"file-info\">\r\n <cide-ele-icon class=\"status-icon\" size=\"sm\">\r\n {{getStatusIcon(upload.status)}}\r\n </cide-ele-icon>\r\n\r\n <div class=\"file-details\">\r\n <div class=\"file-name\">{{ upload.fileName }}</div>\r\n @if (upload.file) {\r\n <div class=\"file-size\">{{ getFileSizeDisplay(upload.file) }}</div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Progress Bar -->\r\n @if (upload.status === 'uploading') {\r\n <div class=\"progress-container\">\r\n <div class=\"progress-bar\">\r\n <div class=\"progress-fill\" [style.width.%]=\"upload.progress\">\r\n </div>\r\n </div>\r\n <span class=\"progress-text\">{{ upload.progress }}%</span>\r\n </div>\r\n }\r\n\r\n <!-- Status Text -->\r\n @if (upload.status !== 'uploading') {\r\n <div class=\"status-text\">\r\n @switch (upload.status) {\r\n @case ('pending') {\r\n <span class=\"text-yellow-600\">Waiting...</span>\r\n }\r\n @case ('completed') {\r\n <span class=\"text-green-600\">Uploaded successfully</span>\r\n }\r\n @case ('error') {\r\n <span class=\"text-red-600\">{{ upload.error || 'Upload failed' }}</span>\r\n }\r\n @case ('cancelled') {\r\n <span class=\"text-gray-600\">Cancelled</span>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Actions -->\r\n <div class=\"upload-actions\">\r\n @switch (upload.status) {\r\n @case ('pending') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"cancelUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"cancel\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n @case ('uploading') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"cancelUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"cancel\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n @case ('completed') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"removeUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"close\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n @case ('error') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"retryUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"refresh\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"removeUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"close\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n @case ('cancelled') {\r\n <button cideEleButton variant=\"text\" size=\"sm\" (click)=\"removeUpload(upload.fileId)\">\r\n <cide-ele-icon name=\"close\" size=\"xs\"></cide-ele-icon>\r\n </button>\r\n }\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Queue Summary -->\r\n <div class=\"queue-summary\">\r\n <div class=\"summary-stats\">\r\n <span class=\"stat\">\r\n <cide-ele-icon name=\"schedule\" size=\"xs\"></cide-ele-icon>\r\n {{ pendingUploads().length }} pending\r\n </span>\r\n <span class=\"stat\">\r\n <cide-ele-icon name=\"cloud_upload\" size=\"xs\"></cide-ele-icon>\r\n {{ activeUploads().length }} uploading\r\n </span>\r\n <span class=\"stat\">\r\n <cide-ele-icon name=\"check_circle\" size=\"xs\"></cide-ele-icon>\r\n {{ completedUploads().length }} completed\r\n </span>\r\n @if (failedUploads().length > 0) {\r\n <span class=\"stat error\">\r\n <cide-ele-icon name=\"error\" size=\"xs\"></cide-ele-icon>\r\n {{ failedUploads().length }} failed\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n", styles: [".global-file-uploader{@apply tw-w-full tw-max-w-2xl tw-mx-auto tw-p-4;}.global-file-uploader .upload-zone{@apply tw-border-2 tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-p-8 tw-text-center tw-cursor-pointer tw-transition-all tw-duration-200 tw-ease-in-out;@apply hover:tw-border-blue-400 hover:tw-bg-blue-50;}.global-file-uploader .upload-zone.drag-over{@apply tw-border-blue-500 tw-bg-blue-100 tw-scale-105;}.global-file-uploader .upload-zone .upload-zone-content{@apply tw-space-y-4;}.global-file-uploader .upload-zone .upload-zone-content .upload-icon{@apply tw-text-gray-400 tw-mx-auto;}.global-file-uploader .upload-zone .upload-zone-content .upload-title{@apply tw-text-xl tw-font-semibold tw-text-gray-700 tw-m-0;}.global-file-uploader .upload-zone .upload-zone-content .upload-subtitle{@apply tw-text-sm tw-text-gray-500 tw-m-0;}.global-file-uploader .upload-queue{@apply tw-mt-6 tw-bg-white tw-border tw-border-gray-200 tw-rounded-lg tw-shadow-sm;}.global-file-uploader .upload-queue .queue-header{@apply tw-flex tw-justify-between tw-items-center tw-p-4 tw-border-b tw-border-gray-200;}.global-file-uploader .upload-queue .queue-header .queue-title{@apply tw-text-lg tw-font-medium tw-text-gray-700 tw-m-0;}.global-file-uploader .upload-queue .queue-header .queue-actions{@apply tw-flex tw-space-x-2;}.global-file-uploader .upload-queue .queue-items{@apply tw-max-h-96 tw-overflow-y-auto;}.global-file-uploader .upload-queue .queue-items .upload-item{@apply tw-flex tw-items-center tw-justify-between tw-p-4 tw-border-b tw-border-gray-100 tw-transition-colors tw-duration-200;}.global-file-uploader .upload-queue .queue-items .upload-item:last-child{@apply tw-border-b-0;}.global-file-uploader .upload-queue .queue-items .upload-item.status-pending{@apply tw-bg-yellow-50;}.global-file-uploader .upload-queue .queue-items .upload-item.status-uploading{@apply tw-bg-blue-50;}.global-file-uploader .upload-queue .queue-items .upload-item.status-completed{@apply tw-bg-green-50;}.global-file-uploader .upload-queue .queue-items .upload-item.status-error{@apply tw-bg-red-50;}.global-file-uploader .upload-queue .queue-items .upload-item.status-cancelled{@apply tw-bg-gray-50;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info{@apply tw-flex tw-items-center tw-flex-1 tw-min-w-0;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .status-icon{@apply tw-mr-3 tw-flex-shrink-0;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details{@apply tw-min-w-0 tw-flex-1;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details .file-name{@apply tw-text-sm tw-font-medium tw-text-gray-700 tw-truncate;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details .file-size{@apply tw-text-xs tw-text-gray-500 tw-mt-1;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container{@apply tw-flex tw-items-center tw-space-x-3 tw-flex-1 tw-max-w-xs tw-mx-4;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-bar{@apply tw-flex-1 tw-h-2 tw-bg-gray-200 tw-rounded-full tw-overflow-hidden;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-bar .progress-fill{@apply tw-h-full tw-bg-blue-500 tw-transition-all tw-duration-300 tw-ease-out;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-text{@apply tw-text-xs tw-font-medium tw-text-gray-600 tw-min-w-12 tw-text-right;}.global-file-uploader .upload-queue .queue-items .upload-item .status-text{@apply tw-flex-1 tw-text-sm tw-text-center;}.global-file-uploader .upload-queue .queue-items .upload-item .status-text span{@apply tw-font-medium;}.global-file-uploader .upload-queue .queue-items .upload-item .upload-actions{@apply tw-flex tw-space-x-1 tw-ml-4;}.global-file-uploader .upload-queue .queue-summary{@apply tw-p-4 tw-bg-gray-50 tw-border-t tw-border-gray-200;}.global-file-uploader .upload-queue .queue-summary .summary-stats{@apply tw-flex tw-flex-wrap tw-gap-4 tw-text-sm tw-text-gray-600;}.global-file-uploader .upload-queue .queue-summary .summary-stats .stat{@apply tw-flex tw-items-center tw-space-x-1;}.global-file-uploader .upload-queue .queue-summary .summary-stats .stat.error{@apply tw-text-red-600;}@media (max-width: 640px){.global-file-uploader{@apply tw-p-2;}.global-file-uploader .upload-zone{@apply tw-p-6;}.global-file-uploader .upload-zone .upload-zone-content .upload-title{@apply tw-text-lg;}.global-file-uploader .upload-zone .upload-zone-content .upload-subtitle{@apply tw-text-xs;}.global-file-uploader .upload-queue .queue-header{@apply tw-p-3 tw-flex-col tw-space-y-2 tw-items-start;}.global-file-uploader .upload-queue .queue-header .queue-actions{@apply tw-w-full tw-justify-end;}.global-file-uploader .upload-queue .queue-items .upload-item{@apply tw-p-3 tw-flex-col tw-space-y-3 tw-items-start;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info{@apply tw-w-full;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container{@apply tw-w-full tw-mx-0;}.global-file-uploader .upload-queue .queue-items .upload-item .status-text{@apply tw-w-full tw-text-left;}.global-file-uploader .upload-queue .queue-items .upload-item .upload-actions{@apply tw-w-full tw-justify-end tw-ml-0;}}@media (prefers-color-scheme: dark){.global-file-uploader .upload-zone{@apply tw-border-gray-600 hover:tw-border-blue-400 hover:tw-bg-gray-800;}.global-file-uploader .upload-zone.drag-over{@apply tw-bg-blue-900;}.global-file-uploader .upload-zone .upload-zone-content .upload-icon{@apply tw-text-gray-500;}.global-file-uploader .upload-zone .upload-zone-content .upload-title{@apply tw-text-gray-200;}.global-file-uploader .upload-zone .upload-zone-content .upload-subtitle{@apply tw-text-gray-400;}.global-file-uploader .upload-queue{@apply tw-bg-gray-800 tw-border-gray-700;}.global-file-uploader .upload-queue .queue-header{@apply tw-border-gray-700;}.global-file-uploader .upload-queue .queue-header .queue-title{@apply tw-text-gray-200;}.global-file-uploader .upload-queue .queue-items .upload-item{@apply tw-border-gray-700;}.global-file-uploader .upload-queue .queue-items .upload-item.status-pending{@apply tw-bg-yellow-900;}.global-file-uploader .upload-queue .queue-items .upload-item.status-uploading{@apply tw-bg-blue-900;}.global-file-uploader .upload-queue .queue-items .upload-item.status-completed{@apply tw-bg-green-900;}.global-file-uploader .upload-queue .queue-items .upload-item.status-error{@apply tw-bg-red-900;}.global-file-uploader .upload-queue .queue-items .upload-item.status-cancelled{@apply tw-bg-gray-700;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details .file-name{@apply tw-text-gray-200;}.global-file-uploader .upload-queue .queue-items .upload-item .file-info .file-details .file-size{@apply tw-text-gray-400;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-bar{@apply tw-bg-gray-600;}.global-file-uploader .upload-queue .queue-items .upload-item .progress-container .progress-text{@apply tw-text-gray-300;}.global-file-uploader .upload-queue .queue-summary{@apply tw-bg-gray-700 tw-border-gray-600;}.global-file-uploader .upload-queue .queue-summary .summary-stats{@apply tw-text-gray-300;}.global-file-uploader .upload-queue .queue-summary .summary-stats .stat.error{@apply tw-text-red-400;}}\n"] }]
5118
- }], ctorParameters: () => [], propDecorators: { userId: [{
5119
- type: Input
5120
- }], multiple: [{
5121
- type: Input
5122
- }], accept: [{
5123
- type: Input
5124
- }], maxFileSize: [{
5125
- type: Input
5126
- }], allowedTypes: [{
5127
- type: Input
5128
- }], uploadComplete: [{
5129
- type: Output
5130
- }], uploadError: [{
5131
- type: Output
5132
- }], uploadCancelled: [{
5133
- type: Output
5134
- }], allUploadsComplete: [{
5135
- type: Output
5136
- }] } });
5137
-
5138
4865
  class CideFloatingUploadTriggerDirective {
5139
4866
  elementRef = inject(ElementRef);
5140
4867
  floatingUploader = inject(CideEleFloatingFileUploaderComponent);
@@ -9481,5 +9208,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
9481
9208
  * Generated bundle index. Do not edit.
9482
9209
  */
9483
9210
 
9484
- export { CideCoreFileManagerService, CideEleButtonComponent, CideEleConfirmationModalComponent, CideEleDataGridComponent, CideEleDropdownComponent, CideEleFileImageDirective, CideEleFileInputComponent, CideEleFileManagerService, CideEleFloatingFileUploaderComponent, CideEleGlobalFileUploaderComponent, CideEleGlobalNotificationsComponent, CideEleJsonEditorComponent, CideEleResizerDirective, CideEleSkeletonLoaderComponent, CideEleTabComponent, CideEleToastNotificationComponent, CideElementsService, CideFloatingUploadTriggerDirective, CideIconComponent, CideInputComponent, CideSelectComponent, CideSelectOptionComponent, CideSpinnerComponent, CideTextareaComponent, ConfirmationService, CoreFileManagerInsertUpdatePayload, DEFAULT_GRID_CONFIG, DropdownManagerService, ICoreCyfmSave, MFileManager, NotificationService, TooltipDirective };
9211
+ export { CideCoreFileManagerService, CideEleButtonComponent, CideEleConfirmationModalComponent, CideEleDataGridComponent, CideEleDropdownComponent, CideEleFileImageDirective, CideEleFileInputComponent, CideEleFileManagerService, CideEleFloatingFileUploaderComponent, CideEleGlobalNotificationsComponent, CideEleJsonEditorComponent, CideEleResizerDirective, CideEleSkeletonLoaderComponent, CideEleTabComponent, CideEleToastNotificationComponent, CideElementsService, CideFloatingUploadTriggerDirective, CideIconComponent, CideInputComponent, CideSelectComponent, CideSelectOptionComponent, CideSpinnerComponent, CideTextareaComponent, ConfirmationService, CoreFileManagerInsertUpdatePayload, DEFAULT_GRID_CONFIG, DropdownManagerService, ICoreCyfmSave, MFileManager, NotificationService, TooltipDirective };
9485
9212
  //# sourceMappingURL=cloud-ide-element.mjs.map