cloud-ide-element 1.0.117 → 1.0.120

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.
@@ -3385,8 +3385,7 @@ class CideEleFloatingContainerService {
3385
3385
  activeComponents = new Map();
3386
3386
  constructor(injector) {
3387
3387
  this.injector = injector;
3388
- // Set up keyboard shortcuts for container navigation
3389
- this.setupKeyboardShortcuts();
3388
+ // Keyboard shortcuts are now handled by FloatingContainerShortcutsService
3390
3389
  }
3391
3390
  // Computed properties
3392
3391
  visibleContainers = computed(() => Array.from(this.containers().values()).filter(container => container.isVisible), ...(ngDevMode ? [{ debugName: "visibleContainers" }] : []));
@@ -3450,75 +3449,24 @@ class CideEleFloatingContainerService {
3450
3449
  bringToFront(containerId) {
3451
3450
  const maxZIndex = this.getMaxZIndex();
3452
3451
  const newZIndex = maxZIndex + 1;
3452
+ console.log(`🎯 [FloatingContainer] Bringing container '${containerId}' to front`);
3453
+ console.log(`🎯 [FloatingContainer] Current max z-index: ${maxZIndex}, new z-index: ${newZIndex}`);
3453
3454
  this.containers.update(containers => {
3454
3455
  const newContainers = new Map(containers);
3455
3456
  const container = newContainers.get(containerId);
3456
3457
  if (container) {
3458
+ const oldZIndex = container.zIndex;
3457
3459
  container.zIndex = newZIndex;
3458
3460
  container.lastAccessed = new Date();
3459
3461
  newContainers.set(containerId, container);
3460
- console.log(`🎯 [FloatingContainer] Container '${containerId}' brought to front with z-index: ${newZIndex}`);
3462
+ console.log(`🎯 [FloatingContainer] Container '${containerId}' z-index updated: ${oldZIndex} → ${newZIndex}`);
3461
3463
  }
3462
- return newContainers;
3463
- });
3464
- }
3465
- /**
3466
- * Set up keyboard shortcuts for container navigation
3467
- */
3468
- setupKeyboardShortcuts() {
3469
- document.addEventListener('keydown', (event) => {
3470
- // Alt + Tab: Cycle through containers (like Windows Alt+Tab)
3471
- if (event.altKey && event.key === 'Tab') {
3472
- event.preventDefault();
3473
- this.cycleToNextContainer();
3474
- }
3475
- // Alt + Shift + Tab: Cycle backwards through containers
3476
- if (event.altKey && event.shiftKey && event.key === 'Tab') {
3477
- event.preventDefault();
3478
- this.cycleToPreviousContainer();
3479
- }
3480
- // Escape: Hide all containers
3481
- if (event.key === 'Escape') {
3482
- this.hideAll();
3464
+ else {
3465
+ console.warn(`⚠️ [FloatingContainer] Container '${containerId}' not found!`);
3483
3466
  }
3467
+ return newContainers;
3484
3468
  });
3485
3469
  }
3486
- /**
3487
- * Cycle to the next container (Alt+Tab behavior)
3488
- */
3489
- cycleToNextContainer() {
3490
- const visibleContainers = this.visibleContainers();
3491
- if (visibleContainers.length === 0)
3492
- return;
3493
- // Sort by last accessed time (most recent first)
3494
- const sortedContainers = visibleContainers.sort((a, b) => b.lastAccessed.getTime() - a.lastAccessed.getTime());
3495
- // Find current front container
3496
- const currentFront = sortedContainers[0];
3497
- const currentIndex = sortedContainers.findIndex(c => c.id === currentFront.id);
3498
- // Get next container (wrap around)
3499
- const nextIndex = (currentIndex + 1) % sortedContainers.length;
3500
- const nextContainer = sortedContainers[nextIndex];
3501
- this.bringToFront(nextContainer.id);
3502
- console.log(`🔄 [FloatingContainer] Cycled to container: ${nextContainer.config.title}`);
3503
- }
3504
- /**
3505
- * Cycle to the previous container (Alt+Shift+Tab behavior)
3506
- */
3507
- cycleToPreviousContainer() {
3508
- const visibleContainers = this.visibleContainers();
3509
- if (visibleContainers.length === 0)
3510
- return;
3511
- // Sort by last accessed time (most recent first)
3512
- const sortedContainers = visibleContainers.sort((a, b) => b.lastAccessed.getTime() - a.lastAccessed.getTime());
3513
- // Find current front container
3514
- const currentFront = sortedContainers[0];
3515
- const currentIndex = sortedContainers.findIndex(c => c.id === currentFront.id);
3516
- // Get previous container (wrap around)
3517
- const prevIndex = currentIndex === 0 ? sortedContainers.length - 1 : currentIndex - 1;
3518
- const prevContainer = sortedContainers[prevIndex];
3519
- this.bringToFront(prevContainer.id);
3520
- console.log(`🔄 [FloatingContainer] Cycled backwards to container: ${prevContainer.config.title}`);
3521
- }
3522
3470
  minimize(containerId) {
3523
3471
  this.containers.update(containers => {
3524
3472
  const newContainers = new Map(containers);
@@ -3757,6 +3705,35 @@ class CideEleFloatingContainerService {
3757
3705
  return container?.isMaximized || false;
3758
3706
  });
3759
3707
  }
3708
+ getZIndexSignal(containerId) {
3709
+ return computed(() => {
3710
+ const container = this.getContainer(containerId);
3711
+ const zIndex = container?.zIndex || 1000;
3712
+ console.log(`🎯 [FloatingContainer] Z-index signal for '${containerId}': ${zIndex}`);
3713
+ return zIndex;
3714
+ });
3715
+ }
3716
+ /**
3717
+ * Set z-index for a specific container
3718
+ */
3719
+ setZIndex(containerId, zIndex) {
3720
+ console.log(`🎯 [FloatingContainer] Setting z-index for '${containerId}' to ${zIndex}`);
3721
+ this.containers.update(containers => {
3722
+ const newContainers = new Map(containers);
3723
+ const container = newContainers.get(containerId);
3724
+ if (container) {
3725
+ const oldZIndex = container.zIndex;
3726
+ container.zIndex = zIndex;
3727
+ container.lastAccessed = new Date();
3728
+ newContainers.set(containerId, container);
3729
+ console.log(`🎯 [FloatingContainer] Container '${containerId}' z-index updated: ${oldZIndex} → ${zIndex}`);
3730
+ }
3731
+ else {
3732
+ console.warn(`⚠️ [FloatingContainer] Container '${containerId}' not found for z-index update!`);
3733
+ }
3734
+ return newContainers;
3735
+ });
3736
+ }
3760
3737
  /**
3761
3738
  * Get visible signal for a container
3762
3739
  */
@@ -5013,9 +4990,8 @@ class CideEleFloatingFileUploaderComponent {
5013
4990
  fileManagerService = inject(CideEleFileManagerService);
5014
4991
  // Input data from floating container
5015
4992
  data = {};
5016
- // Signals for reactive state
5017
- isVisible = signal(false, ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
5018
- isMinimized = signal(false, ...(ngDevMode ? [{ debugName: "isMinimized" }] : []));
4993
+ // Signals for reactive state (simplified for floating container)
4994
+ isVisible = signal(true, ...(ngDevMode ? [{ debugName: "isVisible" }] : [])); // Set to true by default for floating containers
5019
4995
  currentUserId = signal('', ...(ngDevMode ? [{ debugName: "currentUserId" }] : []));
5020
4996
  currentGroupId = signal(null, ...(ngDevMode ? [{ debugName: "currentGroupId" }] : []));
5021
4997
  // Use file manager service as the single source of truth
@@ -5041,21 +5017,15 @@ class CideEleFloatingFileUploaderComponent {
5041
5017
  }, ...(ngDevMode ? [{ debugName: "hasFilesToShow" }] : []));
5042
5018
  // Animation states
5043
5019
  isAnimating = signal(false, ...(ngDevMode ? [{ debugName: "isAnimating" }] : []));
5044
- // Drag functionality
5045
- isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
5046
- position = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "position" }] : []));
5047
- dragOffset = { x: 0, y: 0 };
5020
+ // Drag functionality removed - handled by floating container
5048
5021
  // File drag and drop functionality
5049
5022
  isDragOver = signal(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : []));
5050
- // Window resize handler reference for cleanup
5051
- windowResizeHandler;
5023
+ // Window resize handler removed - handled by floating container
5052
5024
  // Cached dimensions for performance
5053
- cachedDimensions = { width: 320, height: 200 };
5054
- lastDimensionUpdate = 0;
5025
+ // Cached dimensions removed - handled by floating container
5055
5026
  constructor() {
5056
5027
  console.log('🚀 [FloatingFileUploader] Component initialized');
5057
- // Initialize default position
5058
- this.initializePosition();
5028
+ // Position initialization removed - handled by floating container
5059
5029
  // Consolidated effect for all visibility logic - SINGLE SOURCE OF TRUTH
5060
5030
  effect(() => {
5061
5031
  const hasActiveUploads = this.hasActiveUploads();
@@ -5102,8 +5072,7 @@ class CideEleFloatingFileUploaderComponent {
5102
5072
  this.setupDragAndDrop();
5103
5073
  // Set up file input change listeners
5104
5074
  this.setupFileInputListeners();
5105
- // Set up window resize listener
5106
- this.setupWindowResize();
5075
+ // Window resize setup removed - handled by floating container
5107
5076
  }
5108
5077
  initializeWithData() {
5109
5078
  console.log('🚀 [FloatingFileUploader] Initializing with data:', this.data);
@@ -5142,10 +5111,7 @@ class CideEleFloatingFileUploaderComponent {
5142
5111
  console.log('🧹 [FloatingFileUploader] Component destroyed');
5143
5112
  this.removeDragAndDropListeners();
5144
5113
  this.removeFileInputListeners();
5145
- // Clean up window resize listener
5146
- if (this.windowResizeHandler) {
5147
- window.removeEventListener('resize', this.windowResizeHandler);
5148
- }
5114
+ // Window resize cleanup removed - handled by floating container
5149
5115
  }
5150
5116
  /**
5151
5117
  * Set up drag and drop functionality
@@ -5272,20 +5238,7 @@ class CideEleFloatingFileUploaderComponent {
5272
5238
  this.isAnimating.set(false);
5273
5239
  }, 300);
5274
5240
  }
5275
- /**
5276
- * Toggle minimize state
5277
- */
5278
- toggleMinimize() {
5279
- this.isMinimized.set(!this.isMinimized());
5280
- }
5281
- /**
5282
- * Close the floating uploader
5283
- */
5284
- close() {
5285
- // Don't clear files from service - just hide the uploader
5286
- // Files will be fetched from API when "Show Files" is clicked
5287
- this.hideWithAnimation();
5288
- }
5241
+ // Minimize and close functionality removed - handled by floating container
5289
5242
  /**
5290
5243
  * Get upload summary text
5291
5244
  */
@@ -5455,143 +5408,15 @@ class CideEleFloatingFileUploaderComponent {
5455
5408
  });
5456
5409
  });
5457
5410
  }
5458
- /**
5459
- * Update cached dimensions (throttled for performance)
5460
- */
5461
- updateCachedDimensions() {
5462
- const now = Date.now();
5463
- // Only update dimensions every 100ms to avoid excessive DOM queries
5464
- if (now - this.lastDimensionUpdate < 100) {
5465
- return;
5466
- }
5467
- const uploaderElement = document.querySelector('.floating-uploader');
5468
- if (uploaderElement) {
5469
- this.cachedDimensions = {
5470
- width: uploaderElement.offsetWidth,
5471
- height: uploaderElement.offsetHeight
5472
- };
5473
- this.lastDimensionUpdate = now;
5474
- }
5475
- }
5476
- /**
5477
- * Start dragging the uploader
5478
- */
5479
- startDrag(event) {
5480
- event.preventDefault();
5481
- const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
5482
- const clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;
5483
- const currentPos = this.position();
5484
- this.dragOffset = {
5485
- x: clientX - currentPos.x,
5486
- y: clientY - currentPos.y
5487
- };
5488
- this.isDragging.set(true);
5489
- // Update cached dimensions at the start of drag for better performance
5490
- this.updateCachedDimensions();
5491
- // Add event listeners for drag and end
5492
- const moveHandler = (e) => this.onDrag(e);
5493
- const endHandler = () => this.endDrag(moveHandler, endHandler);
5494
- document.addEventListener('mousemove', moveHandler, { passive: false });
5495
- document.addEventListener('mouseup', endHandler);
5496
- document.addEventListener('touchmove', moveHandler, { passive: false });
5497
- document.addEventListener('touchend', endHandler);
5498
- // Prevent text selection during drag
5499
- document.body.style.userSelect = 'none';
5500
- }
5501
- /**
5502
- * Handle dragging movement
5503
- */
5504
- onDrag(event) {
5505
- if (!this.isDragging())
5506
- return;
5507
- event.preventDefault();
5508
- const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
5509
- const clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;
5510
- const newX = clientX - this.dragOffset.x;
5511
- const newY = clientY - this.dragOffset.y;
5512
- // Constrain to viewport bounds using cached dimensions for performance
5513
- const viewportWidth = window.innerWidth;
5514
- const viewportHeight = window.innerHeight;
5515
- // Use cached dimensions instead of DOM queries for better performance
5516
- const uploaderWidth = this.cachedDimensions.width;
5517
- const uploaderHeight = this.cachedDimensions.height;
5518
- // Ensure uploader stays within viewport bounds
5519
- const constrainedX = Math.max(0, Math.min(newX, viewportWidth - uploaderWidth));
5520
- const constrainedY = Math.max(0, Math.min(newY, viewportHeight - uploaderHeight));
5521
- this.position.set({ x: constrainedX, y: constrainedY });
5522
- }
5523
- /**
5524
- * End dragging
5525
- */
5526
- endDrag(moveHandler, endHandler) {
5527
- this.isDragging.set(false);
5528
- // Remove event listeners
5529
- document.removeEventListener('mousemove', moveHandler);
5530
- document.removeEventListener('mouseup', endHandler);
5531
- document.removeEventListener('touchmove', moveHandler);
5532
- document.removeEventListener('touchend', endHandler);
5533
- // Restore text selection
5534
- document.body.style.userSelect = '';
5535
- }
5536
- /**
5537
- * Set up window resize listener to keep uploader within bounds
5538
- */
5539
- setupWindowResize() {
5540
- const handleResize = () => {
5541
- const currentPos = this.position();
5542
- const viewportWidth = window.innerWidth;
5543
- const viewportHeight = window.innerHeight;
5544
- // Update cached dimensions on resize
5545
- this.updateCachedDimensions();
5546
- // Use cached dimensions for performance
5547
- const uploaderWidth = this.cachedDimensions.width;
5548
- const uploaderHeight = this.cachedDimensions.height;
5549
- // Constrain position to new viewport bounds
5550
- const constrainedX = Math.max(0, Math.min(currentPos.x, viewportWidth - uploaderWidth));
5551
- const constrainedY = Math.max(0, Math.min(currentPos.y, viewportHeight - uploaderHeight));
5552
- // Update position if it changed
5553
- if (constrainedX !== currentPos.x || constrainedY !== currentPos.y) {
5554
- this.position.set({ x: constrainedX, y: constrainedY });
5555
- console.log('📐 [FloatingFileUploader] Position adjusted for window resize:', { x: constrainedX, y: constrainedY });
5556
- }
5557
- };
5558
- window.addEventListener('resize', handleResize);
5559
- // Store reference for cleanup
5560
- this.windowResizeHandler = handleResize;
5561
- }
5562
- /**
5563
- * Initialize default position
5564
- */
5565
- initializePosition() {
5566
- // Set initial position to bottom-right corner
5567
- const viewportWidth = window.innerWidth;
5568
- const viewportHeight = window.innerHeight;
5569
- // Initialize cached dimensions with defaults
5570
- this.cachedDimensions = { width: 320, height: 300 };
5571
- // Use cached dimensions for initial positioning
5572
- const uploaderWidth = this.cachedDimensions.width;
5573
- const uploaderHeight = this.cachedDimensions.height;
5574
- // Ensure initial position is within bounds
5575
- const initialX = Math.max(20, viewportWidth - uploaderWidth - 20);
5576
- const initialY = Math.max(20, viewportHeight - uploaderHeight - 20);
5577
- this.position.set({
5578
- x: initialX,
5579
- y: initialY
5580
- });
5581
- // Update dimensions after a short delay to get actual rendered size
5582
- setTimeout(() => {
5583
- this.updateCachedDimensions();
5584
- }, 100);
5585
- }
5586
5411
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingFileUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5587
- 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"] }] });
5412
+ 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=\"file-uploader-content\">\n <!-- Simple header without window controls (floating container handles these) -->\n <div class=\"uploader-header\">\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 <!-- Content -->\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</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"] }] });
5588
5413
  }
5589
5414
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingFileUploaderComponent, decorators: [{
5590
5415
  type: Component,
5591
5416
  args: [{ selector: 'cide-ele-floating-file-uploader', standalone: true, imports: [
5592
5417
  CommonModule,
5593
5418
  CideIconComponent
5594
- ], 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"] }]
5419
+ ], template: "<!-- File Uploader Content (No absolute positioning - works within floating container) -->\n@if (isVisible()) {\n<div class=\"file-uploader-content\">\n <!-- Simple header without window controls (floating container handles these) -->\n <div class=\"uploader-header\">\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 <!-- Content -->\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</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"] }]
5595
5420
  }], ctorParameters: () => [], propDecorators: { data: [{
5596
5421
  type: Input
5597
5422
  }] } });
@@ -5750,6 +5575,669 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
5750
5575
  type: Output
5751
5576
  }] } });
5752
5577
 
5578
+ class KeyboardShortcutService {
5579
+ shortcuts = new Map();
5580
+ overrides = new Map();
5581
+ keydownListener;
5582
+ constructor() {
5583
+ this.setupGlobalListener();
5584
+ }
5585
+ ngOnDestroy() {
5586
+ this.removeGlobalListener();
5587
+ }
5588
+ /**
5589
+ * Register a new keyboard shortcut
5590
+ */
5591
+ register(shortcut) {
5592
+ this.shortcuts.set(shortcut.id, shortcut);
5593
+ console.log(`⌨️ [KeyboardShortcut] Registered shortcut: ${shortcut.id} (${this.getKeyDescription(shortcut)})`);
5594
+ }
5595
+ /**
5596
+ * Override an existing shortcut with new key combination
5597
+ */
5598
+ override(shortcutId, newKey, options) {
5599
+ const originalShortcut = this.shortcuts.get(shortcutId);
5600
+ if (!originalShortcut) {
5601
+ console.warn(`⚠️ [KeyboardShortcut] Cannot override shortcut '${shortcutId}' - not found`);
5602
+ return;
5603
+ }
5604
+ const override = {
5605
+ shortcutId,
5606
+ newKey,
5607
+ newCtrlKey: options?.ctrlKey,
5608
+ newAltKey: options?.altKey,
5609
+ newShiftKey: options?.shiftKey,
5610
+ newMetaKey: options?.metaKey
5611
+ };
5612
+ this.overrides.set(shortcutId, override);
5613
+ console.log(`🔄 [KeyboardShortcut] Override registered for '${shortcutId}': ${this.getKeyDescription({ ...originalShortcut, ...options, key: newKey })}`);
5614
+ }
5615
+ /**
5616
+ * Remove a shortcut
5617
+ */
5618
+ unregister(shortcutId) {
5619
+ this.shortcuts.delete(shortcutId);
5620
+ this.overrides.delete(shortcutId);
5621
+ console.log(`🗑️ [KeyboardShortcut] Removed shortcut: ${shortcutId}`);
5622
+ }
5623
+ /**
5624
+ * Remove override for a shortcut (restore original key combination)
5625
+ */
5626
+ removeOverride(shortcutId) {
5627
+ this.overrides.delete(shortcutId);
5628
+ console.log(`🔄 [KeyboardShortcut] Override removed for: ${shortcutId}`);
5629
+ }
5630
+ /**
5631
+ * Get all registered shortcuts
5632
+ */
5633
+ getAllShortcuts() {
5634
+ return Array.from(this.shortcuts.values());
5635
+ }
5636
+ /**
5637
+ * Get shortcuts by category or filter
5638
+ */
5639
+ getShortcuts(filter) {
5640
+ const shortcuts = this.getAllShortcuts();
5641
+ return filter ? shortcuts.filter(filter) : shortcuts;
5642
+ }
5643
+ /**
5644
+ * Check if a shortcut is registered
5645
+ */
5646
+ hasShortcut(shortcutId) {
5647
+ return this.shortcuts.has(shortcutId);
5648
+ }
5649
+ /**
5650
+ * Get shortcut information
5651
+ */
5652
+ getShortcut(shortcutId) {
5653
+ return this.shortcuts.get(shortcutId);
5654
+ }
5655
+ /**
5656
+ * Clear all shortcuts
5657
+ */
5658
+ clearAll() {
5659
+ this.shortcuts.clear();
5660
+ this.overrides.clear();
5661
+ console.log(`🧹 [KeyboardShortcut] All shortcuts cleared`);
5662
+ }
5663
+ /**
5664
+ * Set up global keyboard listener
5665
+ */
5666
+ setupGlobalListener() {
5667
+ this.keydownListener = (event) => {
5668
+ this.handleKeydown(event);
5669
+ };
5670
+ document.addEventListener('keydown', this.keydownListener);
5671
+ console.log(`🎧 [KeyboardShortcut] Global keyboard listener attached`);
5672
+ }
5673
+ /**
5674
+ * Remove global keyboard listener
5675
+ */
5676
+ removeGlobalListener() {
5677
+ if (this.keydownListener) {
5678
+ document.removeEventListener('keydown', this.keydownListener);
5679
+ this.keydownListener = undefined;
5680
+ console.log(`🎧 [KeyboardShortcut] Global keyboard listener removed`);
5681
+ }
5682
+ }
5683
+ /**
5684
+ * Handle keydown events
5685
+ */
5686
+ handleKeydown(event) {
5687
+ for (const [shortcutId, shortcut] of this.shortcuts) {
5688
+ if (this.matchesShortcut(event, shortcut)) {
5689
+ // Check for override
5690
+ const override = this.overrides.get(shortcutId);
5691
+ if (override && !this.matchesOverride(event, override)) {
5692
+ continue; // Skip if override doesn't match
5693
+ }
5694
+ if (shortcut.preventDefault !== false) {
5695
+ event.preventDefault();
5696
+ }
5697
+ if (shortcut.stopPropagation) {
5698
+ event.stopPropagation();
5699
+ }
5700
+ console.log(`⌨️ [KeyboardShortcut] Executing shortcut: ${shortcutId}`);
5701
+ shortcut.action();
5702
+ break; // Only execute one shortcut per keydown
5703
+ }
5704
+ }
5705
+ }
5706
+ /**
5707
+ * Check if event matches shortcut
5708
+ */
5709
+ matchesShortcut(event, shortcut) {
5710
+ return event.key === shortcut.key &&
5711
+ (shortcut.ctrlKey === undefined || event.ctrlKey === shortcut.ctrlKey) &&
5712
+ (shortcut.altKey === undefined || event.altKey === shortcut.altKey) &&
5713
+ (shortcut.shiftKey === undefined || event.shiftKey === shortcut.shiftKey) &&
5714
+ (shortcut.metaKey === undefined || event.metaKey === shortcut.metaKey);
5715
+ }
5716
+ /**
5717
+ * Check if event matches override
5718
+ */
5719
+ matchesOverride(event, override) {
5720
+ return event.key === override.newKey &&
5721
+ (override.newCtrlKey === undefined || event.ctrlKey === override.newCtrlKey) &&
5722
+ (override.newAltKey === undefined || event.altKey === override.newAltKey) &&
5723
+ (override.newShiftKey === undefined || event.shiftKey === override.newShiftKey) &&
5724
+ (override.newMetaKey === undefined || event.metaKey === override.newMetaKey);
5725
+ }
5726
+ /**
5727
+ * Get human-readable key description
5728
+ */
5729
+ getKeyDescription(shortcut) {
5730
+ const modifiers = [];
5731
+ if (shortcut.ctrlKey)
5732
+ modifiers.push('Ctrl');
5733
+ if (shortcut.altKey)
5734
+ modifiers.push('Alt');
5735
+ if (shortcut.shiftKey)
5736
+ modifiers.push('Shift');
5737
+ if (shortcut.metaKey)
5738
+ modifiers.push('Meta');
5739
+ return [...modifiers, shortcut.key].join(' + ');
5740
+ }
5741
+ /**
5742
+ * Get key description for a shortcut ID
5743
+ */
5744
+ getKeyDescriptionForShortcut(shortcutId) {
5745
+ const shortcut = this.shortcuts.get(shortcutId);
5746
+ if (!shortcut)
5747
+ return 'Not found';
5748
+ const override = this.overrides.get(shortcutId);
5749
+ if (override) {
5750
+ return this.getKeyDescription({
5751
+ key: override.newKey,
5752
+ ctrlKey: override.newCtrlKey,
5753
+ altKey: override.newAltKey,
5754
+ shiftKey: override.newShiftKey,
5755
+ metaKey: override.newMetaKey
5756
+ });
5757
+ }
5758
+ return this.getKeyDescription(shortcut);
5759
+ }
5760
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: KeyboardShortcutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5761
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: KeyboardShortcutService, providedIn: 'root' });
5762
+ }
5763
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: KeyboardShortcutService, decorators: [{
5764
+ type: Injectable,
5765
+ args: [{
5766
+ providedIn: 'root'
5767
+ }]
5768
+ }], ctorParameters: () => [] });
5769
+
5770
+ class FloatingContainerShortcutsService {
5771
+ keyboardShortcutService = inject(KeyboardShortcutService);
5772
+ containerService = inject(CideEleFloatingContainerService);
5773
+ // Z-index layers for different container states
5774
+ Z_INDEX_LAYERS = {
5775
+ HIDDEN: 100, // Hidden containers (behind everything)
5776
+ BACKGROUND: 1000, // Background containers
5777
+ NORMAL: 2000, // Normal visible containers
5778
+ FOCUSED: 3000, // Focused containers
5779
+ MODAL: 4000, // Modal containers
5780
+ TOOLTIP: 5000 // Tooltips and overlays
5781
+ };
5782
+ constructor() {
5783
+ this.registerDefaultShortcuts();
5784
+ }
5785
+ /**
5786
+ * Register default floating container shortcuts using custom key combinations
5787
+ */
5788
+ registerDefaultShortcuts() {
5789
+ // C + 1: Focus on first container
5790
+ this.keyboardShortcutService.register({
5791
+ id: 'floating-container-focus-first',
5792
+ key: '1',
5793
+ ctrlKey: true,
5794
+ description: 'Focus on first floating container (C+1)',
5795
+ action: () => this.focusFirstContainer(),
5796
+ preventDefault: true
5797
+ });
5798
+ // C + 2: Focus on second container
5799
+ this.keyboardShortcutService.register({
5800
+ id: 'floating-container-focus-second',
5801
+ key: '2',
5802
+ ctrlKey: true,
5803
+ description: 'Focus on second floating container (C+2)',
5804
+ action: () => this.focusContainerByIndex(1),
5805
+ preventDefault: true
5806
+ });
5807
+ // C + 3: Focus on third container
5808
+ this.keyboardShortcutService.register({
5809
+ id: 'floating-container-focus-third',
5810
+ key: '3',
5811
+ ctrlKey: true,
5812
+ description: 'Focus on third floating container (C+3)',
5813
+ action: () => this.focusContainerByIndex(2),
5814
+ preventDefault: true
5815
+ });
5816
+ // C + 4: Focus on fourth container
5817
+ this.keyboardShortcutService.register({
5818
+ id: 'floating-container-focus-fourth',
5819
+ key: '4',
5820
+ ctrlKey: true,
5821
+ description: 'Focus on fourth floating container (C+4)',
5822
+ action: () => this.focusContainerByIndex(3),
5823
+ preventDefault: true
5824
+ });
5825
+ // C + 5: Focus on fifth container
5826
+ this.keyboardShortcutService.register({
5827
+ id: 'floating-container-focus-fifth',
5828
+ key: '5',
5829
+ ctrlKey: true,
5830
+ description: 'Focus on fifth floating container (C+5)',
5831
+ action: () => this.focusContainerByIndex(4),
5832
+ preventDefault: true
5833
+ });
5834
+ // C + N: Cycle to next container
5835
+ this.keyboardShortcutService.register({
5836
+ id: 'floating-container-cycle-forward',
5837
+ key: 'n',
5838
+ ctrlKey: true,
5839
+ description: 'Cycle forward through floating containers (C+N)',
5840
+ action: () => this.cycleToNextContainer(),
5841
+ preventDefault: true
5842
+ });
5843
+ // C + P: Cycle to previous container
5844
+ this.keyboardShortcutService.register({
5845
+ id: 'floating-container-cycle-backward',
5846
+ key: 'p',
5847
+ ctrlKey: true,
5848
+ description: 'Cycle backward through floating containers (C+P)',
5849
+ action: () => this.cycleToPreviousContainer(),
5850
+ preventDefault: true
5851
+ });
5852
+ // C + H: Hide all containers
5853
+ this.keyboardShortcutService.register({
5854
+ id: 'floating-container-hide-all',
5855
+ key: 'h',
5856
+ ctrlKey: true,
5857
+ description: 'Hide all floating containers (C+H)',
5858
+ action: () => this.hideAllContainers(),
5859
+ preventDefault: true
5860
+ });
5861
+ // C + M: Minimize all containers
5862
+ this.keyboardShortcutService.register({
5863
+ id: 'floating-container-minimize-all',
5864
+ key: 'm',
5865
+ ctrlKey: true,
5866
+ description: 'Minimize all floating containers (C+M)',
5867
+ action: () => this.minimizeAllContainers(),
5868
+ preventDefault: true
5869
+ });
5870
+ // C + O: Open file uploader
5871
+ this.keyboardShortcutService.register({
5872
+ id: 'floating-container-open-file-uploader',
5873
+ key: 'o',
5874
+ ctrlKey: true,
5875
+ description: 'Open file uploader (C+O)',
5876
+ action: () => this.openFileUploader(),
5877
+ preventDefault: true
5878
+ });
5879
+ // C + R: Open entity rights sharing
5880
+ this.keyboardShortcutService.register({
5881
+ id: 'floating-container-open-entity-rights',
5882
+ key: 'r',
5883
+ ctrlKey: true,
5884
+ description: 'Open entity rights sharing (C+R)',
5885
+ action: () => this.openEntityRightsSharing(),
5886
+ preventDefault: true
5887
+ });
5888
+ // C + S: Show all containers
5889
+ this.keyboardShortcutService.register({
5890
+ id: 'floating-container-show-all',
5891
+ key: 's',
5892
+ ctrlKey: true,
5893
+ description: 'Show all floating containers (C+S)',
5894
+ action: () => this.showAllContainers(),
5895
+ preventDefault: true
5896
+ });
5897
+ // C + D: Duplicate current container
5898
+ this.keyboardShortcutService.register({
5899
+ id: 'floating-container-duplicate',
5900
+ key: 'd',
5901
+ ctrlKey: true,
5902
+ description: 'Duplicate current container (C+D)',
5903
+ action: () => this.duplicateCurrentContainer(),
5904
+ preventDefault: true
5905
+ });
5906
+ // C + W: Close current container
5907
+ this.keyboardShortcutService.register({
5908
+ id: 'floating-container-close-current',
5909
+ key: 'w',
5910
+ ctrlKey: true,
5911
+ description: 'Close current container (C+W)',
5912
+ action: () => this.closeCurrentContainer(),
5913
+ preventDefault: true
5914
+ });
5915
+ // C + T: Toggle container visibility
5916
+ this.keyboardShortcutService.register({
5917
+ id: 'floating-container-toggle-visibility',
5918
+ key: 't',
5919
+ ctrlKey: true,
5920
+ description: 'Toggle container visibility (C+T)',
5921
+ action: () => this.toggleContainerVisibility(),
5922
+ preventDefault: true
5923
+ });
5924
+ console.log('🎯 [FloatingContainerShortcuts] Custom shortcuts registered (C+1, C+2, C+O, etc.)');
5925
+ }
5926
+ /**
5927
+ * Override a floating container shortcut
5928
+ */
5929
+ overrideShortcut(shortcutId, newKey, options) {
5930
+ this.keyboardShortcutService.override(shortcutId, newKey, options);
5931
+ }
5932
+ /**
5933
+ * Add a custom floating container shortcut
5934
+ */
5935
+ addCustomShortcut(shortcut) {
5936
+ this.keyboardShortcutService.register({
5937
+ ...shortcut,
5938
+ preventDefault: true
5939
+ });
5940
+ }
5941
+ /**
5942
+ * Remove a floating container shortcut
5943
+ */
5944
+ removeShortcut(shortcutId) {
5945
+ this.keyboardShortcutService.unregister(shortcutId);
5946
+ }
5947
+ /**
5948
+ * Get all floating container shortcuts
5949
+ */
5950
+ getShortcuts() {
5951
+ return this.keyboardShortcutService.getShortcuts(shortcut => shortcut.id.startsWith('floating-container-'));
5952
+ }
5953
+ // Action methods
5954
+ cycleToNextContainer() {
5955
+ const visibleContainers = this.containerService.visibleContainers();
5956
+ if (visibleContainers.length === 0)
5957
+ return;
5958
+ // Sort by last accessed time (most recent first)
5959
+ const sortedContainers = visibleContainers.sort((a, b) => b.lastAccessed.getTime() - a.lastAccessed.getTime());
5960
+ // Find current front container
5961
+ const currentFront = sortedContainers[0];
5962
+ const currentIndex = sortedContainers.findIndex(c => c.id === currentFront.id);
5963
+ // Get next container (wrap around)
5964
+ const nextIndex = (currentIndex + 1) % sortedContainers.length;
5965
+ const nextContainer = sortedContainers[nextIndex];
5966
+ this.containerService.bringToFront(nextContainer.id);
5967
+ console.log(`🔄 [FloatingContainerShortcuts] Cycled to container: ${nextContainer.config.title}`);
5968
+ }
5969
+ cycleToPreviousContainer() {
5970
+ const visibleContainers = this.containerService.visibleContainers();
5971
+ if (visibleContainers.length === 0)
5972
+ return;
5973
+ // Sort by last accessed time (most recent first)
5974
+ const sortedContainers = visibleContainers.sort((a, b) => b.lastAccessed.getTime() - a.lastAccessed.getTime());
5975
+ // Find current front container
5976
+ const currentFront = sortedContainers[0];
5977
+ const currentIndex = sortedContainers.findIndex(c => c.id === currentFront.id);
5978
+ // Get previous container (wrap around)
5979
+ const prevIndex = currentIndex === 0 ? sortedContainers.length - 1 : currentIndex - 1;
5980
+ const prevContainer = sortedContainers[prevIndex];
5981
+ this.containerService.bringToFront(prevContainer.id);
5982
+ console.log(`🔄 [FloatingContainerShortcuts] Cycled backwards to container: ${prevContainer.config.title}`);
5983
+ }
5984
+ hideAllContainers() {
5985
+ const visibleContainers = this.containerService.visibleContainers();
5986
+ visibleContainers.forEach(container => {
5987
+ this.containerService.setZIndex(container.id, this.Z_INDEX_LAYERS.HIDDEN);
5988
+ });
5989
+ console.log(`👁️ [FloatingContainerShortcuts] All containers moved to hidden layer (z-index: ${this.Z_INDEX_LAYERS.HIDDEN})`);
5990
+ }
5991
+ focusFirstContainer() {
5992
+ const visibleContainers = this.containerService.visibleContainers();
5993
+ if (visibleContainers.length === 0)
5994
+ return;
5995
+ const firstContainer = visibleContainers[0];
5996
+ this.containerService.bringToFront(firstContainer.id);
5997
+ console.log(`🎯 [FloatingContainerShortcuts] Focused on first container: ${firstContainer.config.title}`);
5998
+ }
5999
+ minimizeAllContainers() {
6000
+ this.containerService.minimizeAll();
6001
+ console.log(`📦 [FloatingContainerShortcuts] All containers minimized`);
6002
+ }
6003
+ focusContainerByIndex(index) {
6004
+ const visibleContainers = this.containerService.visibleContainers();
6005
+ if (visibleContainers.length === 0 || index >= visibleContainers.length) {
6006
+ console.log(`⚠️ [FloatingContainerShortcuts] No container at index ${index}`);
6007
+ return;
6008
+ }
6009
+ const container = visibleContainers[index];
6010
+ this.containerService.bringToFront(container.id);
6011
+ console.log(`🎯 [FloatingContainerShortcuts] Focused on container ${index + 1}: ${container.config.title}`);
6012
+ }
6013
+ openFileUploader() {
6014
+ console.log(`📁 [FloatingContainerShortcuts] Opening file uploader...`);
6015
+ // This would need to be implemented based on your file uploader service
6016
+ // Example: this.fileUploaderService.show();
6017
+ }
6018
+ openEntityRightsSharing() {
6019
+ console.log(`🔐 [FloatingContainerShortcuts] Opening entity rights sharing...`);
6020
+ // This would need to be implemented based on your entity rights service
6021
+ // Example: this.entityRightsService.show();
6022
+ }
6023
+ showAllContainers() {
6024
+ const visibleContainers = this.containerService.visibleContainers();
6025
+ visibleContainers.forEach((container, index) => {
6026
+ // Give each container a slightly different z-index to maintain order
6027
+ const zIndex = this.Z_INDEX_LAYERS.NORMAL + index;
6028
+ this.containerService.setZIndex(container.id, zIndex);
6029
+ });
6030
+ console.log(`👁️ [FloatingContainerShortcuts] All containers moved to normal layer (z-index: ${this.Z_INDEX_LAYERS.NORMAL}+)`);
6031
+ }
6032
+ duplicateCurrentContainer() {
6033
+ const visibleContainers = this.containerService.visibleContainers();
6034
+ if (visibleContainers.length === 0) {
6035
+ console.log(`⚠️ [FloatingContainerShortcuts] No containers to duplicate`);
6036
+ return;
6037
+ }
6038
+ const currentContainer = visibleContainers[0]; // Most recent container
6039
+ console.log(`📋 [FloatingContainerShortcuts] Duplicating container: ${currentContainer.config.title}`);
6040
+ // This would need to be implemented based on your container duplication logic
6041
+ }
6042
+ closeCurrentContainer() {
6043
+ const visibleContainers = this.containerService.visibleContainers();
6044
+ if (visibleContainers.length === 0) {
6045
+ console.log(`⚠️ [FloatingContainerShortcuts] No containers to close`);
6046
+ return;
6047
+ }
6048
+ const currentContainer = visibleContainers[0]; // Most recent container
6049
+ this.containerService.hide(currentContainer.id);
6050
+ console.log(`❌ [FloatingContainerShortcuts] Closed container: ${currentContainer.config.title}`);
6051
+ }
6052
+ toggleContainerVisibility() {
6053
+ const visibleContainers = this.containerService.visibleContainers();
6054
+ if (visibleContainers.length === 0) {
6055
+ console.log(`⚠️ [FloatingContainerShortcuts] No containers to toggle`);
6056
+ return;
6057
+ }
6058
+ // Toggle visibility of the most recent container using z-index
6059
+ const currentContainer = visibleContainers[0];
6060
+ const currentZIndex = currentContainer.zIndex;
6061
+ if (currentZIndex >= this.Z_INDEX_LAYERS.NORMAL) {
6062
+ // Container is visible, move to hidden layer
6063
+ this.containerService.setZIndex(currentContainer.id, this.Z_INDEX_LAYERS.HIDDEN);
6064
+ console.log(`👁️ [FloatingContainerShortcuts] Hidden container (z-index: ${this.Z_INDEX_LAYERS.HIDDEN}): ${currentContainer.config.title}`);
6065
+ }
6066
+ else {
6067
+ // Container is hidden, move to normal layer
6068
+ this.containerService.setZIndex(currentContainer.id, this.Z_INDEX_LAYERS.NORMAL);
6069
+ console.log(`👁️ [FloatingContainerShortcuts] Shown container (z-index: ${this.Z_INDEX_LAYERS.NORMAL}): ${currentContainer.config.title}`);
6070
+ }
6071
+ }
6072
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6073
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, providedIn: 'root' });
6074
+ }
6075
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, decorators: [{
6076
+ type: Injectable,
6077
+ args: [{
6078
+ providedIn: 'root'
6079
+ }]
6080
+ }], ctorParameters: () => [] });
6081
+
6082
+ class AppShortcutService {
6083
+ keyboardShortcutService = inject(KeyboardShortcutService);
6084
+ registeredShortcuts = new Map();
6085
+ /**
6086
+ * Register shortcuts from app component
6087
+ * @param shortcuts Array of shortcut configurations
6088
+ */
6089
+ registerShortcuts(shortcuts) {
6090
+ console.log('🎯 [AppShortcut] Registering app shortcuts:', shortcuts.length);
6091
+ shortcuts.forEach(config => {
6092
+ const shortcutId = `app-${config.eventName}`;
6093
+ // Convert AppShortcutConfig to KeyboardShortcut format
6094
+ this.keyboardShortcutService.register({
6095
+ id: shortcutId,
6096
+ key: config.key,
6097
+ ctrlKey: config.ctrlKey,
6098
+ altKey: config.altKey,
6099
+ shiftKey: config.shiftKey,
6100
+ metaKey: config.metaKey,
6101
+ description: config.description,
6102
+ action: () => {
6103
+ console.log(`🎯 [AppShortcut] Executing app shortcut: ${config.eventName}`);
6104
+ this.executeAppEvent(config.eventName);
6105
+ },
6106
+ preventDefault: config.preventDefault !== false,
6107
+ stopPropagation: config.stopPropagation || false
6108
+ });
6109
+ // Store the configuration
6110
+ this.registeredShortcuts.set(shortcutId, config);
6111
+ console.log(`✅ [AppShortcut] Registered shortcut: ${shortcutId} (${this.getKeyDescription(config)})`);
6112
+ });
6113
+ }
6114
+ /**
6115
+ * Unregister shortcuts by event names
6116
+ * @param eventNames Array of event names to unregister
6117
+ */
6118
+ unregisterShortcuts(eventNames) {
6119
+ console.log('🗑️ [AppShortcut] Unregistering app shortcuts:', eventNames);
6120
+ eventNames.forEach(eventName => {
6121
+ const shortcutId = `app-${eventName}`;
6122
+ if (this.registeredShortcuts.has(shortcutId)) {
6123
+ this.keyboardShortcutService.unregister(shortcutId);
6124
+ this.registeredShortcuts.delete(shortcutId);
6125
+ console.log(`✅ [AppShortcut] Unregistered shortcut: ${shortcutId}`);
6126
+ }
6127
+ else {
6128
+ console.warn(`⚠️ [AppShortcut] Shortcut not found: ${shortcutId}`);
6129
+ }
6130
+ });
6131
+ }
6132
+ /**
6133
+ * Get all registered app shortcuts
6134
+ */
6135
+ getRegisteredShortcuts() {
6136
+ return Array.from(this.registeredShortcuts.values());
6137
+ }
6138
+ /**
6139
+ * Check if a shortcut is registered
6140
+ * @param eventName Event name to check
6141
+ */
6142
+ isShortcutRegistered(eventName) {
6143
+ const shortcutId = `app-${eventName}`;
6144
+ return this.registeredShortcuts.has(shortcutId);
6145
+ }
6146
+ /**
6147
+ * Update an existing shortcut
6148
+ * @param eventName Event name to update
6149
+ * @param newConfig New shortcut configuration
6150
+ */
6151
+ updateShortcut(eventName, newConfig) {
6152
+ const shortcutId = `app-${eventName}`;
6153
+ if (this.registeredShortcuts.has(shortcutId)) {
6154
+ // Unregister old shortcut
6155
+ this.keyboardShortcutService.unregister(shortcutId);
6156
+ // Register new shortcut
6157
+ this.keyboardShortcutService.register({
6158
+ id: shortcutId,
6159
+ key: newConfig.key,
6160
+ ctrlKey: newConfig.ctrlKey,
6161
+ altKey: newConfig.altKey,
6162
+ shiftKey: newConfig.shiftKey,
6163
+ metaKey: newConfig.metaKey,
6164
+ description: newConfig.description,
6165
+ action: () => {
6166
+ console.log(`🎯 [AppShortcut] Executing updated app shortcut: ${eventName}`);
6167
+ this.executeAppEvent(eventName);
6168
+ },
6169
+ preventDefault: newConfig.preventDefault !== false,
6170
+ stopPropagation: newConfig.stopPropagation || false
6171
+ });
6172
+ // Update stored configuration
6173
+ this.registeredShortcuts.set(shortcutId, newConfig);
6174
+ console.log(`🔄 [AppShortcut] Updated shortcut: ${shortcutId}`);
6175
+ }
6176
+ else {
6177
+ console.warn(`⚠️ [AppShortcut] Shortcut not found for update: ${shortcutId}`);
6178
+ }
6179
+ }
6180
+ /**
6181
+ * Clear all app shortcuts
6182
+ */
6183
+ clearAllShortcuts() {
6184
+ console.log('🧹 [AppShortcut] Clearing all app shortcuts');
6185
+ const shortcutIds = Array.from(this.registeredShortcuts.keys());
6186
+ shortcutIds.forEach(shortcutId => {
6187
+ this.keyboardShortcutService.unregister(shortcutId);
6188
+ });
6189
+ this.registeredShortcuts.clear();
6190
+ console.log('✅ [AppShortcut] All app shortcuts cleared');
6191
+ }
6192
+ /**
6193
+ * Get shortcut information for help/documentation
6194
+ */
6195
+ getShortcutHelp() {
6196
+ return Array.from(this.registeredShortcuts.values()).map(config => ({
6197
+ eventName: config.eventName,
6198
+ description: config.description,
6199
+ keys: this.getKeyDescription(config)
6200
+ }));
6201
+ }
6202
+ /**
6203
+ * Execute app event (this would be implemented by the app component)
6204
+ * @param eventName Name of the event to execute
6205
+ */
6206
+ executeAppEvent(eventName) {
6207
+ // This method should be overridden by the app component
6208
+ // or connected to an event emitter system
6209
+ console.log(`🎯 [AppShortcut] Executing app event: ${eventName}`);
6210
+ // Emit custom event that the app component can listen to
6211
+ const customEvent = new CustomEvent('app-shortcut-triggered', {
6212
+ detail: { eventName }
6213
+ });
6214
+ window.dispatchEvent(customEvent);
6215
+ }
6216
+ /**
6217
+ * Get human-readable key description
6218
+ */
6219
+ getKeyDescription(config) {
6220
+ const modifiers = [];
6221
+ if (config.ctrlKey)
6222
+ modifiers.push('Ctrl');
6223
+ if (config.altKey)
6224
+ modifiers.push('Alt');
6225
+ if (config.shiftKey)
6226
+ modifiers.push('Shift');
6227
+ if (config.metaKey)
6228
+ modifiers.push('Meta');
6229
+ return [...modifiers, config.key].join(' + ');
6230
+ }
6231
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: AppShortcutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6232
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: AppShortcutService, providedIn: 'root' });
6233
+ }
6234
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: AppShortcutService, decorators: [{
6235
+ type: Injectable,
6236
+ args: [{
6237
+ providedIn: 'root'
6238
+ }]
6239
+ }] });
6240
+
5753
6241
  /**
5754
6242
  <!-- Basic horizontal (left-right) layout -->
5755
6243
  <div class="panel-container">
@@ -9869,8 +10357,12 @@ class CideEleFloatingContainerComponent {
9869
10357
  savedPosition = { x: 100, y: 100 }; // Store position before maximizing
9870
10358
  savedHeight = ''; // Store height before maximizing
9871
10359
  ngAfterViewInit() {
9872
- // Center the container on screen
9873
- this.centerContainer();
10360
+ // Only center the container if it's at the default position (100, 100)
10361
+ // This prevents position jumping when containers are focused
10362
+ const currentPos = this.position();
10363
+ if (currentPos.x === 100 && currentPos.y === 100) {
10364
+ this.centerContainer();
10365
+ }
9874
10366
  }
9875
10367
  constructor() {
9876
10368
  // Watch for maximize state changes
@@ -9987,6 +10479,9 @@ class CideEleFloatingContainerComponent {
9987
10479
  // This will be handled by the container service through the manager component
9988
10480
  // The manager component will call the service's bringToFront method
9989
10481
  console.log(`🎯 [FloatingContainer] Container '${this.computedConfig().id}' clicked - bringing to front`);
10482
+ // Preserve current position to prevent jumping
10483
+ const currentPos = this.position();
10484
+ console.log(`🎯 [FloatingContainer] Preserving position: x=${currentPos.x}, y=${currentPos.y}`);
9990
10485
  }
9991
10486
  toggleMaximize() {
9992
10487
  this.maximizeEvent.emit(this.computedConfig().id);
@@ -10239,96 +10734,96 @@ class CideEleFloatingContainerManagerComponent {
10239
10734
  // Computed properties
10240
10735
  visibleContainers = computed(() => this.containerService.visibleContainers(), ...(ngDevMode ? [{ debugName: "visibleContainers" }] : []));
10241
10736
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingContainerManagerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10242
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFloatingContainerManagerComponent, isStandalone: true, selector: "cide-ele-floating-container-manager", ngImport: i0, template: `
10243
- @for (container of visibleContainers(); track container.id) {
10244
- <cide-ele-floating-container
10245
- [config]="containerService.getConfigSignal(container.config)"
10246
- [isMinimized]="containerService.getMinimizedSignal(container.id)"
10247
- [isMaximized]="containerService.getMaximizedSignal(container.id)"
10248
- [isVisible]="containerService.getVisibleSignal(container.id)"
10249
- [style.z-index]="container.zIndex"
10250
- (closeEvent)="containerService.onClose($event)"
10251
- (minimizeEvent)="containerService.onMinimize($event)"
10252
- (maximizeEvent)="containerService.onMaximize($event)"
10253
- (clickEvent)="containerService.bringToFront($event)">
10254
-
10255
- <!-- Dynamic content loading with @defer for performance -->
10256
- @defer (when container.isVisible) {
10257
- <div
10258
- cideEleFloatingDynamic
10259
- [componentId]="container.config.componentId || container.config.id"
10260
- [componentConfig]="containerService.getComponentConfig(container.config)"
10261
- [isVisible]="container.isVisible">
10262
- </div>
10263
- } @placeholder {
10264
- <div class="tw-flex tw-items-center tw-justify-center tw-p-4">
10265
- <cide-ele-spinner size="sm"></cide-ele-spinner>
10266
- <span class="tw-ml-2 tw-text-sm tw-text-gray-600">Loading component...</span>
10267
- </div>
10268
- } @error {
10269
- <div class="tw-flex tw-flex-col tw-items-center tw-justify-center tw-p-4 tw-text-center">
10270
- <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-red-500 tw-mb-2">error</cide-ele-icon>
10271
- <p class="tw-text-red-600 tw-font-medium">Failed to load component</p>
10272
- <p class="tw-text-gray-500 tw-text-sm">Component "{{ container.config.componentId || container.config.id }}" is not available</p>
10273
- <button
10274
- cideEleButton
10275
- variant="outline"
10276
- size="xs"
10277
- (click)="containerService.onClose(container.id)"
10278
- class="tw-mt-2">
10279
- Close
10280
- </button>
10281
- </div>
10282
- }
10283
- </cide-ele-floating-container>
10284
- }
10737
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFloatingContainerManagerComponent, isStandalone: true, selector: "cide-ele-floating-container-manager", ngImport: i0, template: `
10738
+ @for (container of visibleContainers(); track container.id) {
10739
+ <cide-ele-floating-container
10740
+ [config]="containerService.getConfigSignal(container.config)"
10741
+ [isMinimized]="containerService.getMinimizedSignal(container.id)"
10742
+ [isMaximized]="containerService.getMaximizedSignal(container.id)"
10743
+ [isVisible]="containerService.getVisibleSignal(container.id)"
10744
+ [style.z-index]="containerService.getZIndexSignal(container.id)()"
10745
+ (closeEvent)="containerService.onClose($event)"
10746
+ (minimizeEvent)="containerService.onMinimize($event)"
10747
+ (maximizeEvent)="containerService.onMaximize($event)"
10748
+ (clickEvent)="containerService.bringToFront($event)">
10749
+
10750
+ <!-- Dynamic content loading with @defer for performance -->
10751
+ @defer (when container.isVisible) {
10752
+ <div
10753
+ cideEleFloatingDynamic
10754
+ [componentId]="container.config.componentId || container.config.id"
10755
+ [componentConfig]="containerService.getComponentConfig(container.config)"
10756
+ [isVisible]="container.isVisible">
10757
+ </div>
10758
+ } @placeholder {
10759
+ <div class="tw-flex tw-items-center tw-justify-center tw-p-4">
10760
+ <cide-ele-spinner size="sm"></cide-ele-spinner>
10761
+ <span class="tw-ml-2 tw-text-sm tw-text-gray-600">Loading component...</span>
10762
+ </div>
10763
+ } @error {
10764
+ <div class="tw-flex tw-flex-col tw-items-center tw-justify-center tw-p-4 tw-text-center">
10765
+ <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-red-500 tw-mb-2">error</cide-ele-icon>
10766
+ <p class="tw-text-red-600 tw-font-medium">Failed to load component</p>
10767
+ <p class="tw-text-gray-500 tw-text-sm">Component "{{ container.config.componentId || container.config.id }}" is not available</p>
10768
+ <button
10769
+ cideEleButton
10770
+ variant="outline"
10771
+ size="xs"
10772
+ (click)="containerService.onClose(container.id)"
10773
+ class="tw-mt-2">
10774
+ Close
10775
+ </button>
10776
+ </div>
10777
+ }
10778
+ </cide-ele-floating-container>
10779
+ }
10285
10780
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideEleFloatingContainerComponent, selector: "cide-ele-floating-container", inputs: ["config", "isMinimized", "isMaximized", "isVisible"], outputs: ["closeEvent", "minimizeEvent", "maximizeEvent", "clickEvent"] }, { kind: "component", type: CideSpinnerComponent, selector: "cide-ele-spinner", inputs: ["size", "type"] }, { 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"] }], deferBlockDependencies: [() => [Promise.resolve().then(function () { return floatingContainerDynamic_directive; }).then(m => m.CideEleFloatingContainerDynamicDirective)]] });
10286
10781
  }
10287
10782
  i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingContainerManagerComponent, resolveDeferredDeps: () => [Promise.resolve().then(function () { return floatingContainerDynamic_directive; }).then(m => m.CideEleFloatingContainerDynamicDirective)], resolveMetadata: CideEleFloatingContainerDynamicDirective => ({ decorators: [{
10288
10783
  type: Component,
10289
- args: [{ selector: 'cide-ele-floating-container-manager', standalone: true, imports: [CommonModule, CideEleFloatingContainerComponent, CideEleFloatingContainerDynamicDirective, CideSpinnerComponent, CideEleButtonComponent, CideIconComponent], template: `
10290
- @for (container of visibleContainers(); track container.id) {
10291
- <cide-ele-floating-container
10292
- [config]="containerService.getConfigSignal(container.config)"
10293
- [isMinimized]="containerService.getMinimizedSignal(container.id)"
10294
- [isMaximized]="containerService.getMaximizedSignal(container.id)"
10295
- [isVisible]="containerService.getVisibleSignal(container.id)"
10296
- [style.z-index]="container.zIndex"
10297
- (closeEvent)="containerService.onClose($event)"
10298
- (minimizeEvent)="containerService.onMinimize($event)"
10299
- (maximizeEvent)="containerService.onMaximize($event)"
10300
- (clickEvent)="containerService.bringToFront($event)">
10301
-
10302
- <!-- Dynamic content loading with @defer for performance -->
10303
- @defer (when container.isVisible) {
10304
- <div
10305
- cideEleFloatingDynamic
10306
- [componentId]="container.config.componentId || container.config.id"
10307
- [componentConfig]="containerService.getComponentConfig(container.config)"
10308
- [isVisible]="container.isVisible">
10309
- </div>
10310
- } @placeholder {
10311
- <div class="tw-flex tw-items-center tw-justify-center tw-p-4">
10312
- <cide-ele-spinner size="sm"></cide-ele-spinner>
10313
- <span class="tw-ml-2 tw-text-sm tw-text-gray-600">Loading component...</span>
10314
- </div>
10315
- } @error {
10316
- <div class="tw-flex tw-flex-col tw-items-center tw-justify-center tw-p-4 tw-text-center">
10317
- <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-red-500 tw-mb-2">error</cide-ele-icon>
10318
- <p class="tw-text-red-600 tw-font-medium">Failed to load component</p>
10319
- <p class="tw-text-gray-500 tw-text-sm">Component "{{ container.config.componentId || container.config.id }}" is not available</p>
10320
- <button
10321
- cideEleButton
10322
- variant="outline"
10323
- size="xs"
10324
- (click)="containerService.onClose(container.id)"
10325
- class="tw-mt-2">
10326
- Close
10327
- </button>
10328
- </div>
10329
- }
10330
- </cide-ele-floating-container>
10331
- }
10784
+ args: [{ selector: 'cide-ele-floating-container-manager', standalone: true, imports: [CommonModule, CideEleFloatingContainerComponent, CideEleFloatingContainerDynamicDirective, CideSpinnerComponent, CideEleButtonComponent, CideIconComponent], template: `
10785
+ @for (container of visibleContainers(); track container.id) {
10786
+ <cide-ele-floating-container
10787
+ [config]="containerService.getConfigSignal(container.config)"
10788
+ [isMinimized]="containerService.getMinimizedSignal(container.id)"
10789
+ [isMaximized]="containerService.getMaximizedSignal(container.id)"
10790
+ [isVisible]="containerService.getVisibleSignal(container.id)"
10791
+ [style.z-index]="containerService.getZIndexSignal(container.id)()"
10792
+ (closeEvent)="containerService.onClose($event)"
10793
+ (minimizeEvent)="containerService.onMinimize($event)"
10794
+ (maximizeEvent)="containerService.onMaximize($event)"
10795
+ (clickEvent)="containerService.bringToFront($event)">
10796
+
10797
+ <!-- Dynamic content loading with @defer for performance -->
10798
+ @defer (when container.isVisible) {
10799
+ <div
10800
+ cideEleFloatingDynamic
10801
+ [componentId]="container.config.componentId || container.config.id"
10802
+ [componentConfig]="containerService.getComponentConfig(container.config)"
10803
+ [isVisible]="container.isVisible">
10804
+ </div>
10805
+ } @placeholder {
10806
+ <div class="tw-flex tw-items-center tw-justify-center tw-p-4">
10807
+ <cide-ele-spinner size="sm"></cide-ele-spinner>
10808
+ <span class="tw-ml-2 tw-text-sm tw-text-gray-600">Loading component...</span>
10809
+ </div>
10810
+ } @error {
10811
+ <div class="tw-flex tw-flex-col tw-items-center tw-justify-center tw-p-4 tw-text-center">
10812
+ <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-red-500 tw-mb-2">error</cide-ele-icon>
10813
+ <p class="tw-text-red-600 tw-font-medium">Failed to load component</p>
10814
+ <p class="tw-text-gray-500 tw-text-sm">Component "{{ container.config.componentId || container.config.id }}" is not available</p>
10815
+ <button
10816
+ cideEleButton
10817
+ variant="outline"
10818
+ size="xs"
10819
+ (click)="containerService.onClose(container.id)"
10820
+ class="tw-mt-2">
10821
+ Close
10822
+ </button>
10823
+ </div>
10824
+ }
10825
+ </cide-ele-floating-container>
10826
+ }
10332
10827
  ` }]
10333
10828
  }], ctorParameters: null, propDecorators: null }) });
10334
10829
 
@@ -10588,5 +11083,5 @@ var floatingContainerDynamic_directive = /*#__PURE__*/Object.freeze({
10588
11083
  * Generated bundle index. Do not edit.
10589
11084
  */
10590
11085
 
10591
- export { CideCoreFileManagerService, CideEleButtonComponent, CideEleConfirmationModalComponent, CideEleDataGridComponent, CideEleDropdownComponent, CideEleFileImageDirective, CideEleFileInputComponent, CideEleFileManagerService, CideEleFloatingContainerComponent, CideEleFloatingContainerDynamicDirective, CideEleFloatingContainerManagerComponent, CideEleFloatingContainerService, CideEleFloatingFeaturesService, CideEleFloatingFileUploaderComponent, CideEleFloatingFileUploaderService, CideEleGlobalNotificationsComponent, CideEleJsonEditorComponent, CideEleResizerDirective, CideEleSkeletonLoaderComponent, CideEleTabComponent, CideEleToastNotificationComponent, CideElementsService, CideIconComponent, CideInputComponent, CideSelectComponent, CideSelectOptionComponent, CideSpinnerComponent, CideTextareaComponent, ConfirmationService, CoreFileManagerInsertUpdatePayload, DEFAULT_GRID_CONFIG, DropdownManagerService, ICoreCyfmSave, MFileManager, NotificationService, TooltipDirective };
11086
+ export { AppShortcutService, CideCoreFileManagerService, CideEleButtonComponent, CideEleConfirmationModalComponent, CideEleDataGridComponent, CideEleDropdownComponent, CideEleFileImageDirective, CideEleFileInputComponent, CideEleFileManagerService, CideEleFloatingContainerComponent, CideEleFloatingContainerDynamicDirective, CideEleFloatingContainerManagerComponent, CideEleFloatingContainerService, CideEleFloatingFeaturesService, CideEleFloatingFileUploaderComponent, CideEleFloatingFileUploaderService, CideEleGlobalNotificationsComponent, CideEleJsonEditorComponent, CideEleResizerDirective, CideEleSkeletonLoaderComponent, CideEleTabComponent, CideEleToastNotificationComponent, CideElementsService, CideIconComponent, CideInputComponent, CideSelectComponent, CideSelectOptionComponent, CideSpinnerComponent, CideTextareaComponent, ConfirmationService, CoreFileManagerInsertUpdatePayload, DEFAULT_GRID_CONFIG, DropdownManagerService, FloatingContainerShortcutsService, ICoreCyfmSave, KeyboardShortcutService, MFileManager, NotificationService, TooltipDirective };
10592
11087
  //# sourceMappingURL=cloud-ide-element.mjs.map