cloud-ide-element 1.0.119 → 1.0.121

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.
@@ -4990,9 +4990,8 @@ class CideEleFloatingFileUploaderComponent {
4990
4990
  fileManagerService = inject(CideEleFileManagerService);
4991
4991
  // Input data from floating container
4992
4992
  data = {};
4993
- // Signals for reactive state
4993
+ // Signals for reactive state (simplified for floating container)
4994
4994
  isVisible = signal(true, ...(ngDevMode ? [{ debugName: "isVisible" }] : [])); // Set to true by default for floating containers
4995
- isMinimized = signal(false, ...(ngDevMode ? [{ debugName: "isMinimized" }] : []));
4996
4995
  currentUserId = signal('', ...(ngDevMode ? [{ debugName: "currentUserId" }] : []));
4997
4996
  currentGroupId = signal(null, ...(ngDevMode ? [{ debugName: "currentGroupId" }] : []));
4998
4997
  // Use file manager service as the single source of truth
@@ -5016,23 +5015,27 @@ class CideEleFloatingFileUploaderComponent {
5016
5015
  hasFilesToShow = computed(() => {
5017
5016
  return this.hasActiveUploads() || this.allFilesForGroup().length > 0;
5018
5017
  }, ...(ngDevMode ? [{ debugName: "hasFilesToShow" }] : []));
5018
+ // Count methods for template
5019
+ getUploadingCount() {
5020
+ return this.activeUploadsLocal().length;
5021
+ }
5022
+ getCompletedCount() {
5023
+ return this.completedUploads().length;
5024
+ }
5025
+ getFailedCount() {
5026
+ return this.failedUploads().length;
5027
+ }
5019
5028
  // Animation states
5020
5029
  isAnimating = signal(false, ...(ngDevMode ? [{ debugName: "isAnimating" }] : []));
5021
- // Drag functionality
5022
- isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
5023
- position = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "position" }] : []));
5024
- dragOffset = { x: 0, y: 0 };
5030
+ // Drag functionality removed - handled by floating container
5025
5031
  // File drag and drop functionality
5026
5032
  isDragOver = signal(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : []));
5027
- // Window resize handler reference for cleanup
5028
- windowResizeHandler;
5033
+ // Window resize handler removed - handled by floating container
5029
5034
  // Cached dimensions for performance
5030
- cachedDimensions = { width: 320, height: 200 };
5031
- lastDimensionUpdate = 0;
5035
+ // Cached dimensions removed - handled by floating container
5032
5036
  constructor() {
5033
5037
  console.log('🚀 [FloatingFileUploader] Component initialized');
5034
- // Initialize default position
5035
- this.initializePosition();
5038
+ // Position initialization removed - handled by floating container
5036
5039
  // Consolidated effect for all visibility logic - SINGLE SOURCE OF TRUTH
5037
5040
  effect(() => {
5038
5041
  const hasActiveUploads = this.hasActiveUploads();
@@ -5079,8 +5082,7 @@ class CideEleFloatingFileUploaderComponent {
5079
5082
  this.setupDragAndDrop();
5080
5083
  // Set up file input change listeners
5081
5084
  this.setupFileInputListeners();
5082
- // Set up window resize listener
5083
- this.setupWindowResize();
5085
+ // Window resize setup removed - handled by floating container
5084
5086
  }
5085
5087
  initializeWithData() {
5086
5088
  console.log('🚀 [FloatingFileUploader] Initializing with data:', this.data);
@@ -5119,10 +5121,7 @@ class CideEleFloatingFileUploaderComponent {
5119
5121
  console.log('🧹 [FloatingFileUploader] Component destroyed');
5120
5122
  this.removeDragAndDropListeners();
5121
5123
  this.removeFileInputListeners();
5122
- // Clean up window resize listener
5123
- if (this.windowResizeHandler) {
5124
- window.removeEventListener('resize', this.windowResizeHandler);
5125
- }
5124
+ // Window resize cleanup removed - handled by floating container
5126
5125
  }
5127
5126
  /**
5128
5127
  * Set up drag and drop functionality
@@ -5249,20 +5248,7 @@ class CideEleFloatingFileUploaderComponent {
5249
5248
  this.isAnimating.set(false);
5250
5249
  }, 300);
5251
5250
  }
5252
- /**
5253
- * Toggle minimize state
5254
- */
5255
- toggleMinimize() {
5256
- this.isMinimized.set(!this.isMinimized());
5257
- }
5258
- /**
5259
- * Close the floating uploader
5260
- */
5261
- close() {
5262
- // Don't clear files from service - just hide the uploader
5263
- // Files will be fetched from API when "Show Files" is clicked
5264
- this.hideWithAnimation();
5265
- }
5251
+ // Minimize and close functionality removed - handled by floating container
5266
5252
  /**
5267
5253
  * Get upload summary text
5268
5254
  */
@@ -5432,143 +5418,15 @@ class CideEleFloatingFileUploaderComponent {
5432
5418
  });
5433
5419
  });
5434
5420
  }
5435
- /**
5436
- * Update cached dimensions (throttled for performance)
5437
- */
5438
- updateCachedDimensions() {
5439
- const now = Date.now();
5440
- // Only update dimensions every 100ms to avoid excessive DOM queries
5441
- if (now - this.lastDimensionUpdate < 100) {
5442
- return;
5443
- }
5444
- const uploaderElement = document.querySelector('.floating-uploader');
5445
- if (uploaderElement) {
5446
- this.cachedDimensions = {
5447
- width: uploaderElement.offsetWidth,
5448
- height: uploaderElement.offsetHeight
5449
- };
5450
- this.lastDimensionUpdate = now;
5451
- }
5452
- }
5453
- /**
5454
- * Start dragging the uploader
5455
- */
5456
- startDrag(event) {
5457
- event.preventDefault();
5458
- const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
5459
- const clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;
5460
- const currentPos = this.position();
5461
- this.dragOffset = {
5462
- x: clientX - currentPos.x,
5463
- y: clientY - currentPos.y
5464
- };
5465
- this.isDragging.set(true);
5466
- // Update cached dimensions at the start of drag for better performance
5467
- this.updateCachedDimensions();
5468
- // Add event listeners for drag and end
5469
- const moveHandler = (e) => this.onDrag(e);
5470
- const endHandler = () => this.endDrag(moveHandler, endHandler);
5471
- document.addEventListener('mousemove', moveHandler, { passive: false });
5472
- document.addEventListener('mouseup', endHandler);
5473
- document.addEventListener('touchmove', moveHandler, { passive: false });
5474
- document.addEventListener('touchend', endHandler);
5475
- // Prevent text selection during drag
5476
- document.body.style.userSelect = 'none';
5477
- }
5478
- /**
5479
- * Handle dragging movement
5480
- */
5481
- onDrag(event) {
5482
- if (!this.isDragging())
5483
- return;
5484
- event.preventDefault();
5485
- const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
5486
- const clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;
5487
- const newX = clientX - this.dragOffset.x;
5488
- const newY = clientY - this.dragOffset.y;
5489
- // Constrain to viewport bounds using cached dimensions for performance
5490
- const viewportWidth = window.innerWidth;
5491
- const viewportHeight = window.innerHeight;
5492
- // Use cached dimensions instead of DOM queries for better performance
5493
- const uploaderWidth = this.cachedDimensions.width;
5494
- const uploaderHeight = this.cachedDimensions.height;
5495
- // Ensure uploader stays within viewport bounds
5496
- const constrainedX = Math.max(0, Math.min(newX, viewportWidth - uploaderWidth));
5497
- const constrainedY = Math.max(0, Math.min(newY, viewportHeight - uploaderHeight));
5498
- this.position.set({ x: constrainedX, y: constrainedY });
5499
- }
5500
- /**
5501
- * End dragging
5502
- */
5503
- endDrag(moveHandler, endHandler) {
5504
- this.isDragging.set(false);
5505
- // Remove event listeners
5506
- document.removeEventListener('mousemove', moveHandler);
5507
- document.removeEventListener('mouseup', endHandler);
5508
- document.removeEventListener('touchmove', moveHandler);
5509
- document.removeEventListener('touchend', endHandler);
5510
- // Restore text selection
5511
- document.body.style.userSelect = '';
5512
- }
5513
- /**
5514
- * Set up window resize listener to keep uploader within bounds
5515
- */
5516
- setupWindowResize() {
5517
- const handleResize = () => {
5518
- const currentPos = this.position();
5519
- const viewportWidth = window.innerWidth;
5520
- const viewportHeight = window.innerHeight;
5521
- // Update cached dimensions on resize
5522
- this.updateCachedDimensions();
5523
- // Use cached dimensions for performance
5524
- const uploaderWidth = this.cachedDimensions.width;
5525
- const uploaderHeight = this.cachedDimensions.height;
5526
- // Constrain position to new viewport bounds
5527
- const constrainedX = Math.max(0, Math.min(currentPos.x, viewportWidth - uploaderWidth));
5528
- const constrainedY = Math.max(0, Math.min(currentPos.y, viewportHeight - uploaderHeight));
5529
- // Update position if it changed
5530
- if (constrainedX !== currentPos.x || constrainedY !== currentPos.y) {
5531
- this.position.set({ x: constrainedX, y: constrainedY });
5532
- console.log('📐 [FloatingFileUploader] Position adjusted for window resize:', { x: constrainedX, y: constrainedY });
5533
- }
5534
- };
5535
- window.addEventListener('resize', handleResize);
5536
- // Store reference for cleanup
5537
- this.windowResizeHandler = handleResize;
5538
- }
5539
- /**
5540
- * Initialize default position
5541
- */
5542
- initializePosition() {
5543
- // Set initial position to bottom-right corner
5544
- const viewportWidth = window.innerWidth;
5545
- const viewportHeight = window.innerHeight;
5546
- // Initialize cached dimensions with defaults
5547
- this.cachedDimensions = { width: 320, height: 300 };
5548
- // Use cached dimensions for initial positioning
5549
- const uploaderWidth = this.cachedDimensions.width;
5550
- const uploaderHeight = this.cachedDimensions.height;
5551
- // Ensure initial position is within bounds
5552
- const initialX = Math.max(20, viewportWidth - uploaderWidth - 20);
5553
- const initialY = Math.max(20, viewportHeight - uploaderHeight - 20);
5554
- this.position.set({
5555
- x: initialX,
5556
- y: initialY
5557
- });
5558
- // Update dimensions after a short delay to get actual rendered size
5559
- setTimeout(() => {
5560
- this.updateCachedDimensions();
5561
- }, 100);
5562
- }
5563
5421
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingFileUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5564
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFloatingFileUploaderComponent, isStandalone: true, selector: "cide-ele-floating-file-uploader", inputs: { data: "data" }, 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=\"sm\">cloud_upload</cide-ele-icon>\n \n <div class=\"upload-text\">\n <div class=\"upload-title\">\n {{ isDragOver() ? 'Drop files here' : 'Drag files here or click to browse' }}\n </div>\n </div>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (allFilesForGroup().length > 0) {\n <div class=\"upload-queue\">\n <!-- Show all files from service state -->\n @for (file of allFilesForGroup(); 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:8px 16px;padding:12px;border:2px dashed #d1d5db;border-radius:6px;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.01)}.floating-uploader .uploader-content .upload-zone .upload-zone-content{display:flex;flex-direction:column;align-items:center;gap:6px}.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:13px;font-weight:500;color:#374151;margin:0;line-height:1.2}.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: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"] }] });
5422
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFloatingFileUploaderComponent, isStandalone: true, selector: "cide-ele-floating-file-uploader", inputs: { data: "data" }, ngImport: i0, template: "<!-- File Uploader Content (No absolute positioning - works within floating container) -->\n@if (isVisible()) {\n<div class=\"tw-w-full tw-max-h-[500px] tw-bg-white tw-rounded-xl tw-shadow-lg tw-border tw-border-gray-200 tw-overflow-hidden tw-transition-all tw-duration-300\">\n <!-- Simple header without window controls (floating container handles these) -->\n <div class=\"tw-flex tw-items-center tw-justify-between tw-px-4 tw-py-3 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-bg-blue-600 tw-rounded-md tw-text-white\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n </div>\n <div>\n <div class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">{{ data.title || 'File Upload' }}</div>\n <div class=\"tw-text-xs tw-text-gray-500\">{{ getUploadSummary() }}</div>\n </div>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tw-max-h-[400px] tw-overflow-y-auto\">\n \n <!-- Drag and Drop Zone -->\n <div class=\"tw-m-2 tw-p-3 tw-border-2 tw-border-dashed tw-border-gray-300 tw-rounded-md tw-bg-gray-50 tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-center hover:tw-border-blue-500 hover:tw-bg-blue-50\" \n [class.tw-border-blue-500]=\"isDragOver()\"\n [class.tw-bg-blue-100]=\"isDragOver()\"\n [class.tw-scale-105]=\"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]=\"data.multiple !== false\" \n [accept]=\"data.allowedFileTypes?.join(',') || '*/*'\" \n (change)=\"onFileInputChange($event)\" \n class=\"tw-hidden\">\n \n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-gray-400 tw-transition-colors tw-duration-200\" \n [class.tw-text-blue-500]=\"isDragOver()\"\n size=\"sm\">cloud_upload</cide-ele-icon>\n \n <div>\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">\n {{ isDragOver() ? 'Drop files here' : 'Drag files here or click to browse' }}\n </div>\n @if (data.description) {\n <div class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ data.description }}</div>\n }\n </div>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (allFilesForGroup().length > 0) {\n <div class=\"tw-space-y-0\">\n <!-- Show all files from service state -->\n @for (file of allFilesForGroup(); track file.fileId) {\n <div class=\"tw-flex tw-items-center tw-px-4 tw-py-2 tw-border-b tw-border-gray-100 tw-transition-colors tw-duration-200\"\n [class.tw-bg-blue-50]=\"file.stage === 'uploading'\"\n [class.tw-bg-green-50]=\"file.stage === 'complete'\"\n [class.tw-bg-red-50]=\"file.stage === 'error'\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-flex-1 tw-min-w-0\">\n <cide-ele-icon class=\"tw-flex-shrink-0\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"tw-min-w-0 tw-flex-1\">\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\">{{ file.fileName }}</div>\n <div class=\"tw-text-xs\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"tw-text-blue-600 tw-font-medium\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"tw-text-green-600 tw-font-medium\">Completed</span>\n }\n @case ('error') {\n <span class=\"tw-text-red-600 tw-font-medium\">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=\"tw-flex tw-items-center tw-gap-2 tw-ml-2 tw-min-w-[80px]\">\n <div class=\"tw-flex-1 tw-h-1 tw-bg-gray-200 tw-rounded-full tw-overflow-hidden\">\n <div class=\"tw-h-full tw-bg-blue-500 tw-transition-all tw-duration-300\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"tw-text-xs tw-text-gray-500 tw-min-w-[24px] tw-text-right\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"tw-flex tw-gap-1 tw-ml-2\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (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=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (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=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (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=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-text-green-600\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-blue-50 hover:tw-text-blue-600\" \n 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=\"tw-p-8 tw-text-center tw-text-gray-500\">\n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-4\">\n <cide-ele-icon size=\"md\" class=\"tw-text-gray-300 tw-opacity-70\">cloud_upload</cide-ele-icon>\n <div>\n <h4 class=\"tw-text-lg tw-font-semibold tw-text-gray-700 tw-mb-2\">No active uploads</h4>\n <p class=\"tw-text-sm tw-text-gray-500\">Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Footer -->\n <div class=\"tw-px-4 tw-py-2 tw-bg-gray-50 tw-border-t tw-border-gray-200\">\n <div class=\"tw-flex tw-gap-3 tw-text-xs\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-blue-600\" \n [class.tw-text-blue-600]=\"hasActiveUploads()\">\n <cide-ele-icon size=\"xs\">upload</cide-ele-icon>\n <span>{{ getUploadingCount() }} uploading</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-green-600\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n <span>{{ getCompletedCount() }} completed</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-red-600\" \n [class.tw-text-red-600]=\"getFailedCount() > 0\">\n <cide-ele-icon size=\"xs\">error</cide-ele-icon>\n <span>{{ getFailedCount() }} failed</span>\n </div>\n </div>\n </div>\n</div>\n}", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
5565
5423
  }
5566
5424
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingFileUploaderComponent, decorators: [{
5567
5425
  type: Component,
5568
5426
  args: [{ selector: 'cide-ele-floating-file-uploader', standalone: true, imports: [
5569
5427
  CommonModule,
5570
5428
  CideIconComponent
5571
- ], 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=\"sm\">cloud_upload</cide-ele-icon>\n \n <div class=\"upload-text\">\n <div class=\"upload-title\">\n {{ isDragOver() ? 'Drop files here' : 'Drag files here or click to browse' }}\n </div>\n </div>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (allFilesForGroup().length > 0) {\n <div class=\"upload-queue\">\n <!-- Show all files from service state -->\n @for (file of allFilesForGroup(); 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:8px 16px;padding:12px;border:2px dashed #d1d5db;border-radius:6px;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.01)}.floating-uploader .uploader-content .upload-zone .upload-zone-content{display:flex;flex-direction:column;align-items:center;gap:6px}.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:13px;font-weight:500;color:#374151;margin:0;line-height:1.2}.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: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"] }]
5429
+ ], template: "<!-- File Uploader Content (No absolute positioning - works within floating container) -->\n@if (isVisible()) {\n<div class=\"tw-w-full tw-max-h-[500px] tw-bg-white tw-rounded-xl tw-shadow-lg tw-border tw-border-gray-200 tw-overflow-hidden tw-transition-all tw-duration-300\">\n <!-- Simple header without window controls (floating container handles these) -->\n <div class=\"tw-flex tw-items-center tw-justify-between tw-px-4 tw-py-3 tw-bg-gray-50 tw-border-b tw-border-gray-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-bg-blue-600 tw-rounded-md tw-text-white\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n </div>\n <div>\n <div class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">{{ data.title || 'File Upload' }}</div>\n <div class=\"tw-text-xs tw-text-gray-500\">{{ getUploadSummary() }}</div>\n </div>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tw-max-h-[400px] tw-overflow-y-auto\">\n \n <!-- Drag and Drop Zone -->\n <div class=\"tw-m-2 tw-p-3 tw-border-2 tw-border-dashed tw-border-gray-300 tw-rounded-md tw-bg-gray-50 tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-center hover:tw-border-blue-500 hover:tw-bg-blue-50\" \n [class.tw-border-blue-500]=\"isDragOver()\"\n [class.tw-bg-blue-100]=\"isDragOver()\"\n [class.tw-scale-105]=\"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]=\"data.multiple !== false\" \n [accept]=\"data.allowedFileTypes?.join(',') || '*/*'\" \n (change)=\"onFileInputChange($event)\" \n class=\"tw-hidden\">\n \n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-gray-400 tw-transition-colors tw-duration-200\" \n [class.tw-text-blue-500]=\"isDragOver()\"\n size=\"sm\">cloud_upload</cide-ele-icon>\n \n <div>\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">\n {{ isDragOver() ? 'Drop files here' : 'Drag files here or click to browse' }}\n </div>\n @if (data.description) {\n <div class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ data.description }}</div>\n }\n </div>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (allFilesForGroup().length > 0) {\n <div class=\"tw-space-y-0\">\n <!-- Show all files from service state -->\n @for (file of allFilesForGroup(); track file.fileId) {\n <div class=\"tw-flex tw-items-center tw-px-4 tw-py-2 tw-border-b tw-border-gray-100 tw-transition-colors tw-duration-200\"\n [class.tw-bg-blue-50]=\"file.stage === 'uploading'\"\n [class.tw-bg-green-50]=\"file.stage === 'complete'\"\n [class.tw-bg-red-50]=\"file.stage === 'error'\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-flex-1 tw-min-w-0\">\n <cide-ele-icon class=\"tw-flex-shrink-0\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"tw-min-w-0 tw-flex-1\">\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\">{{ file.fileName }}</div>\n <div class=\"tw-text-xs\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"tw-text-blue-600 tw-font-medium\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"tw-text-green-600 tw-font-medium\">Completed</span>\n }\n @case ('error') {\n <span class=\"tw-text-red-600 tw-font-medium\">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=\"tw-flex tw-items-center tw-gap-2 tw-ml-2 tw-min-w-[80px]\">\n <div class=\"tw-flex-1 tw-h-1 tw-bg-gray-200 tw-rounded-full tw-overflow-hidden\">\n <div class=\"tw-h-full tw-bg-blue-500 tw-transition-all tw-duration-300\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"tw-text-xs tw-text-gray-500 tw-min-w-[24px] tw-text-right\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"tw-flex tw-gap-1 tw-ml-2\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (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=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (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=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (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=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-text-green-600\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-blue-50 hover:tw-text-blue-600\" \n 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=\"tw-p-8 tw-text-center tw-text-gray-500\">\n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-4\">\n <cide-ele-icon size=\"md\" class=\"tw-text-gray-300 tw-opacity-70\">cloud_upload</cide-ele-icon>\n <div>\n <h4 class=\"tw-text-lg tw-font-semibold tw-text-gray-700 tw-mb-2\">No active uploads</h4>\n <p class=\"tw-text-sm tw-text-gray-500\">Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Footer -->\n <div class=\"tw-px-4 tw-py-2 tw-bg-gray-50 tw-border-t tw-border-gray-200\">\n <div class=\"tw-flex tw-gap-3 tw-text-xs\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-blue-600\" \n [class.tw-text-blue-600]=\"hasActiveUploads()\">\n <cide-ele-icon size=\"xs\">upload</cide-ele-icon>\n <span>{{ getUploadingCount() }} uploading</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-green-600\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n <span>{{ getCompletedCount() }} completed</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-red-600\" \n [class.tw-text-red-600]=\"getFailedCount() > 0\">\n <cide-ele-icon size=\"xs\">error</cide-ele-icon>\n <span>{{ getFailedCount() }} failed</span>\n </div>\n </div>\n </div>\n</div>\n}" }]
5572
5430
  }], ctorParameters: () => [], propDecorators: { data: [{
5573
5431
  type: Input
5574
5432
  }] } });
@@ -5919,318 +5777,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
5919
5777
  }]
5920
5778
  }], ctorParameters: () => [] });
5921
5779
 
5922
- class FloatingContainerShortcutsService {
5923
- keyboardShortcutService = inject(KeyboardShortcutService);
5924
- containerService = inject(CideEleFloatingContainerService);
5925
- // Z-index layers for different container states
5926
- Z_INDEX_LAYERS = {
5927
- HIDDEN: 100, // Hidden containers (behind everything)
5928
- BACKGROUND: 1000, // Background containers
5929
- NORMAL: 2000, // Normal visible containers
5930
- FOCUSED: 3000, // Focused containers
5931
- MODAL: 4000, // Modal containers
5932
- TOOLTIP: 5000 // Tooltips and overlays
5933
- };
5934
- constructor() {
5935
- this.registerDefaultShortcuts();
5936
- }
5937
- /**
5938
- * Register default floating container shortcuts using custom key combinations
5939
- */
5940
- registerDefaultShortcuts() {
5941
- // C + 1: Focus on first container
5942
- this.keyboardShortcutService.register({
5943
- id: 'floating-container-focus-first',
5944
- key: '1',
5945
- ctrlKey: true,
5946
- description: 'Focus on first floating container (C+1)',
5947
- action: () => this.focusFirstContainer(),
5948
- preventDefault: true
5949
- });
5950
- // C + 2: Focus on second container
5951
- this.keyboardShortcutService.register({
5952
- id: 'floating-container-focus-second',
5953
- key: '2',
5954
- ctrlKey: true,
5955
- description: 'Focus on second floating container (C+2)',
5956
- action: () => this.focusContainerByIndex(1),
5957
- preventDefault: true
5958
- });
5959
- // C + 3: Focus on third container
5960
- this.keyboardShortcutService.register({
5961
- id: 'floating-container-focus-third',
5962
- key: '3',
5963
- ctrlKey: true,
5964
- description: 'Focus on third floating container (C+3)',
5965
- action: () => this.focusContainerByIndex(2),
5966
- preventDefault: true
5967
- });
5968
- // C + 4: Focus on fourth container
5969
- this.keyboardShortcutService.register({
5970
- id: 'floating-container-focus-fourth',
5971
- key: '4',
5972
- ctrlKey: true,
5973
- description: 'Focus on fourth floating container (C+4)',
5974
- action: () => this.focusContainerByIndex(3),
5975
- preventDefault: true
5976
- });
5977
- // C + 5: Focus on fifth container
5978
- this.keyboardShortcutService.register({
5979
- id: 'floating-container-focus-fifth',
5980
- key: '5',
5981
- ctrlKey: true,
5982
- description: 'Focus on fifth floating container (C+5)',
5983
- action: () => this.focusContainerByIndex(4),
5984
- preventDefault: true
5985
- });
5986
- // C + N: Cycle to next container
5987
- this.keyboardShortcutService.register({
5988
- id: 'floating-container-cycle-forward',
5989
- key: 'n',
5990
- ctrlKey: true,
5991
- description: 'Cycle forward through floating containers (C+N)',
5992
- action: () => this.cycleToNextContainer(),
5993
- preventDefault: true
5994
- });
5995
- // C + P: Cycle to previous container
5996
- this.keyboardShortcutService.register({
5997
- id: 'floating-container-cycle-backward',
5998
- key: 'p',
5999
- ctrlKey: true,
6000
- description: 'Cycle backward through floating containers (C+P)',
6001
- action: () => this.cycleToPreviousContainer(),
6002
- preventDefault: true
6003
- });
6004
- // C + H: Hide all containers
6005
- this.keyboardShortcutService.register({
6006
- id: 'floating-container-hide-all',
6007
- key: 'h',
6008
- ctrlKey: true,
6009
- description: 'Hide all floating containers (C+H)',
6010
- action: () => this.hideAllContainers(),
6011
- preventDefault: true
6012
- });
6013
- // C + M: Minimize all containers
6014
- this.keyboardShortcutService.register({
6015
- id: 'floating-container-minimize-all',
6016
- key: 'm',
6017
- ctrlKey: true,
6018
- description: 'Minimize all floating containers (C+M)',
6019
- action: () => this.minimizeAllContainers(),
6020
- preventDefault: true
6021
- });
6022
- // C + O: Open file uploader
6023
- this.keyboardShortcutService.register({
6024
- id: 'floating-container-open-file-uploader',
6025
- key: 'o',
6026
- ctrlKey: true,
6027
- description: 'Open file uploader (C+O)',
6028
- action: () => this.openFileUploader(),
6029
- preventDefault: true
6030
- });
6031
- // C + R: Open entity rights sharing
6032
- this.keyboardShortcutService.register({
6033
- id: 'floating-container-open-entity-rights',
6034
- key: 'r',
6035
- ctrlKey: true,
6036
- description: 'Open entity rights sharing (C+R)',
6037
- action: () => this.openEntityRightsSharing(),
6038
- preventDefault: true
6039
- });
6040
- // C + S: Show all containers
6041
- this.keyboardShortcutService.register({
6042
- id: 'floating-container-show-all',
6043
- key: 's',
6044
- ctrlKey: true,
6045
- description: 'Show all floating containers (C+S)',
6046
- action: () => this.showAllContainers(),
6047
- preventDefault: true
6048
- });
6049
- // C + D: Duplicate current container
6050
- this.keyboardShortcutService.register({
6051
- id: 'floating-container-duplicate',
6052
- key: 'd',
6053
- ctrlKey: true,
6054
- description: 'Duplicate current container (C+D)',
6055
- action: () => this.duplicateCurrentContainer(),
6056
- preventDefault: true
6057
- });
6058
- // C + W: Close current container
6059
- this.keyboardShortcutService.register({
6060
- id: 'floating-container-close-current',
6061
- key: 'w',
6062
- ctrlKey: true,
6063
- description: 'Close current container (C+W)',
6064
- action: () => this.closeCurrentContainer(),
6065
- preventDefault: true
6066
- });
6067
- // C + T: Toggle container visibility
6068
- this.keyboardShortcutService.register({
6069
- id: 'floating-container-toggle-visibility',
6070
- key: 't',
6071
- ctrlKey: true,
6072
- description: 'Toggle container visibility (C+T)',
6073
- action: () => this.toggleContainerVisibility(),
6074
- preventDefault: true
6075
- });
6076
- console.log('🎯 [FloatingContainerShortcuts] Custom shortcuts registered (C+1, C+2, C+O, etc.)');
6077
- }
6078
- /**
6079
- * Override a floating container shortcut
6080
- */
6081
- overrideShortcut(shortcutId, newKey, options) {
6082
- this.keyboardShortcutService.override(shortcutId, newKey, options);
6083
- }
6084
- /**
6085
- * Add a custom floating container shortcut
6086
- */
6087
- addCustomShortcut(shortcut) {
6088
- this.keyboardShortcutService.register({
6089
- ...shortcut,
6090
- preventDefault: true
6091
- });
6092
- }
6093
- /**
6094
- * Remove a floating container shortcut
6095
- */
6096
- removeShortcut(shortcutId) {
6097
- this.keyboardShortcutService.unregister(shortcutId);
6098
- }
6099
- /**
6100
- * Get all floating container shortcuts
6101
- */
6102
- getShortcuts() {
6103
- return this.keyboardShortcutService.getShortcuts(shortcut => shortcut.id.startsWith('floating-container-'));
6104
- }
6105
- // Action methods
6106
- cycleToNextContainer() {
6107
- const visibleContainers = this.containerService.visibleContainers();
6108
- if (visibleContainers.length === 0)
6109
- return;
6110
- // Sort by last accessed time (most recent first)
6111
- const sortedContainers = visibleContainers.sort((a, b) => b.lastAccessed.getTime() - a.lastAccessed.getTime());
6112
- // Find current front container
6113
- const currentFront = sortedContainers[0];
6114
- const currentIndex = sortedContainers.findIndex(c => c.id === currentFront.id);
6115
- // Get next container (wrap around)
6116
- const nextIndex = (currentIndex + 1) % sortedContainers.length;
6117
- const nextContainer = sortedContainers[nextIndex];
6118
- this.containerService.bringToFront(nextContainer.id);
6119
- console.log(`🔄 [FloatingContainerShortcuts] Cycled to container: ${nextContainer.config.title}`);
6120
- }
6121
- cycleToPreviousContainer() {
6122
- const visibleContainers = this.containerService.visibleContainers();
6123
- if (visibleContainers.length === 0)
6124
- return;
6125
- // Sort by last accessed time (most recent first)
6126
- const sortedContainers = visibleContainers.sort((a, b) => b.lastAccessed.getTime() - a.lastAccessed.getTime());
6127
- // Find current front container
6128
- const currentFront = sortedContainers[0];
6129
- const currentIndex = sortedContainers.findIndex(c => c.id === currentFront.id);
6130
- // Get previous container (wrap around)
6131
- const prevIndex = currentIndex === 0 ? sortedContainers.length - 1 : currentIndex - 1;
6132
- const prevContainer = sortedContainers[prevIndex];
6133
- this.containerService.bringToFront(prevContainer.id);
6134
- console.log(`🔄 [FloatingContainerShortcuts] Cycled backwards to container: ${prevContainer.config.title}`);
6135
- }
6136
- hideAllContainers() {
6137
- const visibleContainers = this.containerService.visibleContainers();
6138
- visibleContainers.forEach(container => {
6139
- this.containerService.setZIndex(container.id, this.Z_INDEX_LAYERS.HIDDEN);
6140
- });
6141
- console.log(`👁️ [FloatingContainerShortcuts] All containers moved to hidden layer (z-index: ${this.Z_INDEX_LAYERS.HIDDEN})`);
6142
- }
6143
- focusFirstContainer() {
6144
- const visibleContainers = this.containerService.visibleContainers();
6145
- if (visibleContainers.length === 0)
6146
- return;
6147
- const firstContainer = visibleContainers[0];
6148
- this.containerService.bringToFront(firstContainer.id);
6149
- console.log(`🎯 [FloatingContainerShortcuts] Focused on first container: ${firstContainer.config.title}`);
6150
- }
6151
- minimizeAllContainers() {
6152
- this.containerService.minimizeAll();
6153
- console.log(`📦 [FloatingContainerShortcuts] All containers minimized`);
6154
- }
6155
- focusContainerByIndex(index) {
6156
- const visibleContainers = this.containerService.visibleContainers();
6157
- if (visibleContainers.length === 0 || index >= visibleContainers.length) {
6158
- console.log(`⚠️ [FloatingContainerShortcuts] No container at index ${index}`);
6159
- return;
6160
- }
6161
- const container = visibleContainers[index];
6162
- this.containerService.bringToFront(container.id);
6163
- console.log(`🎯 [FloatingContainerShortcuts] Focused on container ${index + 1}: ${container.config.title}`);
6164
- }
6165
- openFileUploader() {
6166
- console.log(`📁 [FloatingContainerShortcuts] Opening file uploader...`);
6167
- // This would need to be implemented based on your file uploader service
6168
- // Example: this.fileUploaderService.show();
6169
- }
6170
- openEntityRightsSharing() {
6171
- console.log(`🔐 [FloatingContainerShortcuts] Opening entity rights sharing...`);
6172
- // This would need to be implemented based on your entity rights service
6173
- // Example: this.entityRightsService.show();
6174
- }
6175
- showAllContainers() {
6176
- const visibleContainers = this.containerService.visibleContainers();
6177
- visibleContainers.forEach((container, index) => {
6178
- // Give each container a slightly different z-index to maintain order
6179
- const zIndex = this.Z_INDEX_LAYERS.NORMAL + index;
6180
- this.containerService.setZIndex(container.id, zIndex);
6181
- });
6182
- console.log(`👁️ [FloatingContainerShortcuts] All containers moved to normal layer (z-index: ${this.Z_INDEX_LAYERS.NORMAL}+)`);
6183
- }
6184
- duplicateCurrentContainer() {
6185
- const visibleContainers = this.containerService.visibleContainers();
6186
- if (visibleContainers.length === 0) {
6187
- console.log(`⚠️ [FloatingContainerShortcuts] No containers to duplicate`);
6188
- return;
6189
- }
6190
- const currentContainer = visibleContainers[0]; // Most recent container
6191
- console.log(`📋 [FloatingContainerShortcuts] Duplicating container: ${currentContainer.config.title}`);
6192
- // This would need to be implemented based on your container duplication logic
6193
- }
6194
- closeCurrentContainer() {
6195
- const visibleContainers = this.containerService.visibleContainers();
6196
- if (visibleContainers.length === 0) {
6197
- console.log(`⚠️ [FloatingContainerShortcuts] No containers to close`);
6198
- return;
6199
- }
6200
- const currentContainer = visibleContainers[0]; // Most recent container
6201
- this.containerService.hide(currentContainer.id);
6202
- console.log(`❌ [FloatingContainerShortcuts] Closed container: ${currentContainer.config.title}`);
6203
- }
6204
- toggleContainerVisibility() {
6205
- const visibleContainers = this.containerService.visibleContainers();
6206
- if (visibleContainers.length === 0) {
6207
- console.log(`⚠️ [FloatingContainerShortcuts] No containers to toggle`);
6208
- return;
6209
- }
6210
- // Toggle visibility of the most recent container using z-index
6211
- const currentContainer = visibleContainers[0];
6212
- const currentZIndex = currentContainer.zIndex;
6213
- if (currentZIndex >= this.Z_INDEX_LAYERS.NORMAL) {
6214
- // Container is visible, move to hidden layer
6215
- this.containerService.setZIndex(currentContainer.id, this.Z_INDEX_LAYERS.HIDDEN);
6216
- console.log(`👁️ [FloatingContainerShortcuts] Hidden container (z-index: ${this.Z_INDEX_LAYERS.HIDDEN}): ${currentContainer.config.title}`);
6217
- }
6218
- else {
6219
- // Container is hidden, move to normal layer
6220
- this.containerService.setZIndex(currentContainer.id, this.Z_INDEX_LAYERS.NORMAL);
6221
- console.log(`👁️ [FloatingContainerShortcuts] Shown container (z-index: ${this.Z_INDEX_LAYERS.NORMAL}): ${currentContainer.config.title}`);
6222
- }
6223
- }
6224
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6225
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, providedIn: 'root' });
6226
- }
6227
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, decorators: [{
6228
- type: Injectable,
6229
- args: [{
6230
- providedIn: 'root'
6231
- }]
6232
- }], ctorParameters: () => [] });
6233
-
6234
5780
  /**
6235
5781
  <!-- Basic horizontal (left-right) layout -->
6236
5782
  <div class="panel-container">
@@ -11067,6 +10613,291 @@ var floatingContainerDynamic_directive = /*#__PURE__*/Object.freeze({
11067
10613
  CideEleFloatingContainerDynamicDirective: CideEleFloatingContainerDynamicDirective
11068
10614
  });
11069
10615
 
10616
+ class FloatingContainerShortcutsService {
10617
+ keyboardShortcutService = inject(KeyboardShortcutService);
10618
+ containerService = inject(CideEleFloatingContainerService);
10619
+ // Z-index layers for different container states
10620
+ Z_INDEX_LAYERS = {
10621
+ HIDDEN: 100, // Hidden containers (behind everything)
10622
+ BACKGROUND: 1000, // Background containers
10623
+ NORMAL: 2000, // Normal visible containers
10624
+ FOCUSED: 3000, // Focused containers
10625
+ MODAL: 4000, // Modal containers
10626
+ TOOLTIP: 5000 // Tooltips and overlays
10627
+ };
10628
+ constructor() {
10629
+ this.registerDefaultShortcuts();
10630
+ }
10631
+ /**
10632
+ * Register default floating container shortcuts
10633
+ */
10634
+ registerDefaultShortcuts() {
10635
+ console.log('🎯 [FloatingContainerShortcuts] Registering default shortcuts');
10636
+ // Alt + 1, Alt + 2, etc. - Focus specific containers
10637
+ this.registerNumberShortcuts();
10638
+ // Alt + N - New container
10639
+ this.keyboardShortcutService.register({
10640
+ id: 'floating-container-new',
10641
+ key: 'n',
10642
+ altKey: true,
10643
+ description: 'Create new floating container',
10644
+ action: () => this.openNewContainer(),
10645
+ preventDefault: true
10646
+ });
10647
+ // Alt + P - Previous container
10648
+ this.keyboardShortcutService.register({
10649
+ id: 'floating-container-previous',
10650
+ key: 'p',
10651
+ altKey: true,
10652
+ description: 'Focus previous container',
10653
+ action: () => this.focusPreviousContainer(),
10654
+ preventDefault: true
10655
+ });
10656
+ // Alt + H - Hide all containers
10657
+ this.keyboardShortcutService.register({
10658
+ id: 'floating-container-hide-all',
10659
+ key: 'h',
10660
+ altKey: true,
10661
+ description: 'Hide all containers',
10662
+ action: () => this.hideAllContainers(),
10663
+ preventDefault: true
10664
+ });
10665
+ // Alt + S - Show all containers
10666
+ this.keyboardShortcutService.register({
10667
+ id: 'floating-container-show-all',
10668
+ key: 's',
10669
+ altKey: true,
10670
+ description: 'Show all containers',
10671
+ action: () => this.showAllContainers(),
10672
+ preventDefault: true
10673
+ });
10674
+ // Alt + M - Minimize all containers
10675
+ this.keyboardShortcutService.register({
10676
+ id: 'floating-container-minimize-all',
10677
+ key: 'm',
10678
+ altKey: true,
10679
+ description: 'Minimize all containers',
10680
+ action: () => this.minimizeAllContainers(),
10681
+ preventDefault: true
10682
+ });
10683
+ // Alt + W - Close current container
10684
+ this.keyboardShortcutService.register({
10685
+ id: 'floating-container-close-current',
10686
+ key: 'w',
10687
+ altKey: true,
10688
+ description: 'Close current container',
10689
+ action: () => this.closeCurrentContainer(),
10690
+ preventDefault: true
10691
+ });
10692
+ // Alt + D - Duplicate current container
10693
+ this.keyboardShortcutService.register({
10694
+ id: 'floating-container-duplicate',
10695
+ key: 'd',
10696
+ altKey: true,
10697
+ description: 'Duplicate current container',
10698
+ action: () => this.duplicateCurrentContainer(),
10699
+ preventDefault: true
10700
+ });
10701
+ // Alt + T - Toggle container visibility
10702
+ this.keyboardShortcutService.register({
10703
+ id: 'floating-container-toggle-visibility',
10704
+ key: 't',
10705
+ altKey: true,
10706
+ description: 'Toggle container visibility',
10707
+ action: () => this.toggleContainerVisibility(),
10708
+ preventDefault: true
10709
+ });
10710
+ // Alt + O - Open file uploader
10711
+ this.keyboardShortcutService.register({
10712
+ id: 'floating-container-open-file-uploader',
10713
+ key: 'o',
10714
+ altKey: true,
10715
+ description: 'Open file uploader',
10716
+ action: () => this.openFileUploader(),
10717
+ preventDefault: true
10718
+ });
10719
+ // Alt + R - Open entity rights sharing
10720
+ this.keyboardShortcutService.register({
10721
+ id: 'floating-container-open-entity-rights',
10722
+ key: 'r',
10723
+ altKey: true,
10724
+ description: 'Open entity rights sharing',
10725
+ action: () => this.openEntityRightsSharing(),
10726
+ preventDefault: true
10727
+ });
10728
+ console.log('✅ [FloatingContainerShortcuts] Default shortcuts registered');
10729
+ }
10730
+ /**
10731
+ * Register number shortcuts (Alt + 1, Alt + 2, etc.)
10732
+ */
10733
+ registerNumberShortcuts() {
10734
+ for (let i = 1; i <= 9; i++) {
10735
+ this.keyboardShortcutService.register({
10736
+ id: `floating-container-focus-${i}`,
10737
+ key: i.toString(),
10738
+ altKey: true,
10739
+ description: `Focus container ${i}`,
10740
+ action: () => this.focusContainerByIndex(i - 1),
10741
+ preventDefault: true
10742
+ });
10743
+ }
10744
+ }
10745
+ /**
10746
+ * Open new floating container
10747
+ */
10748
+ openNewContainer() {
10749
+ console.log('🎯 [FloatingContainerShortcuts] Opening new container');
10750
+ const containerId = this.containerService.show({
10751
+ id: 'new-container-' + Date.now(),
10752
+ title: 'New Container',
10753
+ width: '400px',
10754
+ height: '300px'
10755
+ });
10756
+ console.log('✅ [FloatingContainerShortcuts] New container created:', containerId);
10757
+ }
10758
+ /**
10759
+ * Focus previous container
10760
+ */
10761
+ focusPreviousContainer() {
10762
+ console.log('🎯 [FloatingContainerShortcuts] Focusing previous container');
10763
+ const containers = this.containerService.visibleContainers();
10764
+ if (containers.length > 0) {
10765
+ // For now, just focus the last container
10766
+ const previousIndex = containers.length - 1;
10767
+ this.containerService.bringToFront(containers[previousIndex].id);
10768
+ }
10769
+ }
10770
+ /**
10771
+ * Hide all containers
10772
+ */
10773
+ hideAllContainers() {
10774
+ console.log('🎯 [FloatingContainerShortcuts] Hiding all containers');
10775
+ const containers = this.containerService.visibleContainers();
10776
+ containers.forEach(container => {
10777
+ this.containerService.setZIndex(container.id, this.Z_INDEX_LAYERS.HIDDEN);
10778
+ });
10779
+ console.log('✅ [FloatingContainerShortcuts] All containers hidden');
10780
+ }
10781
+ /**
10782
+ * Show all containers
10783
+ */
10784
+ showAllContainers() {
10785
+ console.log('🎯 [FloatingContainerShortcuts] Showing all containers');
10786
+ const containers = this.containerService.visibleContainers();
10787
+ containers.forEach((container, index) => {
10788
+ this.containerService.setZIndex(container.id, this.Z_INDEX_LAYERS.NORMAL + index);
10789
+ });
10790
+ console.log('✅ [FloatingContainerShortcuts] All containers shown');
10791
+ }
10792
+ /**
10793
+ * Minimize all containers
10794
+ */
10795
+ minimizeAllContainers() {
10796
+ console.log('🎯 [FloatingContainerShortcuts] Minimizing all containers');
10797
+ const containers = this.containerService.visibleContainers();
10798
+ containers.forEach(container => {
10799
+ // Implement minimize logic here
10800
+ console.log('📦 [FloatingContainerShortcuts] Minimizing container:', container.id);
10801
+ });
10802
+ console.log('✅ [FloatingContainerShortcuts] All containers minimized');
10803
+ }
10804
+ /**
10805
+ * Focus container by index
10806
+ */
10807
+ focusContainerByIndex(index) {
10808
+ console.log('🎯 [FloatingContainerShortcuts] Focusing container at index:', index);
10809
+ const containers = this.containerService.visibleContainers();
10810
+ if (containers[index]) {
10811
+ this.containerService.bringToFront(containers[index].id);
10812
+ console.log('✅ [FloatingContainerShortcuts] Container focused:', containers[index].id);
10813
+ }
10814
+ else {
10815
+ console.warn('⚠️ [FloatingContainerShortcuts] Container not found at index:', index);
10816
+ }
10817
+ }
10818
+ /**
10819
+ * Open file uploader
10820
+ */
10821
+ openFileUploader() {
10822
+ console.log('🎯 [FloatingContainerShortcuts] Opening file uploader');
10823
+ // Implement file uploader opening logic here
10824
+ console.log('✅ [FloatingContainerShortcuts] File uploader opened');
10825
+ }
10826
+ /**
10827
+ * Open entity rights sharing
10828
+ */
10829
+ openEntityRightsSharing() {
10830
+ console.log('🎯 [FloatingContainerShortcuts] Opening entity rights sharing');
10831
+ // Implement entity rights sharing opening logic here
10832
+ console.log('✅ [FloatingContainerShortcuts] Entity rights sharing opened');
10833
+ }
10834
+ /**
10835
+ * Duplicate current container
10836
+ */
10837
+ duplicateCurrentContainer() {
10838
+ console.log('🎯 [FloatingContainerShortcuts] Duplicating current container');
10839
+ const containers = this.containerService.visibleContainers();
10840
+ if (containers.length > 0) {
10841
+ const containerToDuplicate = containers[containers.length - 1]; // Use last container
10842
+ const newContainerId = this.containerService.show({
10843
+ id: 'duplicate-' + Date.now(),
10844
+ title: `${containerToDuplicate.config.title} (Copy)`,
10845
+ width: containerToDuplicate.config.width,
10846
+ height: containerToDuplicate.config.height
10847
+ });
10848
+ console.log('✅ [FloatingContainerShortcuts] Container duplicated:', newContainerId);
10849
+ }
10850
+ else {
10851
+ console.warn('⚠️ [FloatingContainerShortcuts] No container to duplicate');
10852
+ }
10853
+ }
10854
+ /**
10855
+ * Close current container
10856
+ */
10857
+ closeCurrentContainer() {
10858
+ console.log('🎯 [FloatingContainerShortcuts] Closing current container');
10859
+ const containers = this.containerService.visibleContainers();
10860
+ if (containers.length > 0) {
10861
+ const containerToClose = containers[containers.length - 1]; // Use last container
10862
+ this.containerService.hide(containerToClose.id);
10863
+ console.log('✅ [FloatingContainerShortcuts] Container closed:', containerToClose.id);
10864
+ }
10865
+ else {
10866
+ console.warn('⚠️ [FloatingContainerShortcuts] No container to close');
10867
+ }
10868
+ }
10869
+ /**
10870
+ * Toggle container visibility
10871
+ */
10872
+ toggleContainerVisibility() {
10873
+ console.log('🎯 [FloatingContainerShortcuts] Toggling container visibility');
10874
+ const containers = this.containerService.visibleContainers();
10875
+ if (containers.length > 0) {
10876
+ const containerToToggle = containers[containers.length - 1]; // Use last container
10877
+ const currentZIndex = this.containerService.getZIndexSignal(containerToToggle.id)();
10878
+ if (currentZIndex === this.Z_INDEX_LAYERS.HIDDEN) {
10879
+ this.containerService.setZIndex(containerToToggle.id, this.Z_INDEX_LAYERS.NORMAL);
10880
+ console.log('✅ [FloatingContainerShortcuts] Container shown:', containerToToggle.id);
10881
+ }
10882
+ else {
10883
+ this.containerService.setZIndex(containerToToggle.id, this.Z_INDEX_LAYERS.HIDDEN);
10884
+ console.log('✅ [FloatingContainerShortcuts] Container hidden:', containerToToggle.id);
10885
+ }
10886
+ }
10887
+ else {
10888
+ console.warn('⚠️ [FloatingContainerShortcuts] No container to toggle');
10889
+ }
10890
+ }
10891
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
10892
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, providedIn: 'root' });
10893
+ }
10894
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, decorators: [{
10895
+ type: Injectable,
10896
+ args: [{
10897
+ providedIn: 'root'
10898
+ }]
10899
+ }], ctorParameters: () => [] });
10900
+
11070
10901
  /*
11071
10902
  * Public API Surface of cloud-ide-element
11072
10903
  * Here we can add what need to be exported from library