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.
- package/fesm2022/cloud-ide-element.mjs +807 -312
- package/fesm2022/cloud-ide-element.mjs.map +1 -1
- package/index.d.ts +246 -61
- package/package.json +1 -1
|
@@ -3385,8 +3385,7 @@ class CideEleFloatingContainerService {
|
|
|
3385
3385
|
activeComponents = new Map();
|
|
3386
3386
|
constructor(injector) {
|
|
3387
3387
|
this.injector = injector;
|
|
3388
|
-
//
|
|
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}'
|
|
3462
|
+
console.log(`🎯 [FloatingContainer] Container '${containerId}' z-index updated: ${oldZIndex} → ${newZIndex}`);
|
|
3461
3463
|
}
|
|
3462
|
-
|
|
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(
|
|
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
|
|
5051
|
-
windowResizeHandler;
|
|
5023
|
+
// Window resize handler removed - handled by floating container
|
|
5052
5024
|
// Cached dimensions for performance
|
|
5053
|
-
|
|
5054
|
-
lastDimensionUpdate = 0;
|
|
5025
|
+
// Cached dimensions removed - handled by floating container
|
|
5055
5026
|
constructor() {
|
|
5056
5027
|
console.log('🚀 [FloatingFileUploader] Component initialized');
|
|
5057
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
9873
|
-
|
|
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.
|
|
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.
|
|
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
|