cloud-ide-layout 1.0.23 → 1.0.24
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-layout-cloud-ide-layout-urOTUFvE.mjs → cloud-ide-layout-cloud-ide-layout-RD9NYgsO.mjs} +551 -6
- package/fesm2022/cloud-ide-layout-cloud-ide-layout-RD9NYgsO.mjs.map +1 -0
- package/fesm2022/{cloud-ide-layout-drawer-theme.component-B-VlqH0O.mjs → cloud-ide-layout-drawer-theme.component-B4u9LnTe.mjs} +2 -2
- package/fesm2022/{cloud-ide-layout-drawer-theme.component-B-VlqH0O.mjs.map → cloud-ide-layout-drawer-theme.component-B4u9LnTe.mjs.map} +1 -1
- package/fesm2022/{cloud-ide-layout-home-wrapper.component-DtB5EqE3.mjs → cloud-ide-layout-home-wrapper.component-DEec7PZk.mjs} +2 -2
- package/fesm2022/{cloud-ide-layout-home-wrapper.component-DtB5EqE3.mjs.map → cloud-ide-layout-home-wrapper.component-DEec7PZk.mjs.map} +1 -1
- package/fesm2022/{cloud-ide-layout-sidedrawer-notes.component-B4p_uGox.mjs → cloud-ide-layout-sidedrawer-notes.component-GT7A-85i.mjs} +2 -2
- package/fesm2022/{cloud-ide-layout-sidedrawer-notes.component-B4p_uGox.mjs.map → cloud-ide-layout-sidedrawer-notes.component-GT7A-85i.mjs.map} +1 -1
- package/fesm2022/cloud-ide-layout.mjs +1 -1
- package/index.d.ts +215 -2
- package/package.json +1 -1
- package/fesm2022/cloud-ide-layout-cloud-ide-layout-urOTUFvE.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, inject, signal, computed, effect, Component, ElementRef, HostListener, ViewContainerRef, ViewChild, ViewChildren, InjectionToken, PLATFORM_ID } from '@angular/core';
|
|
2
|
+
import { Injectable, inject, signal, computed, effect, Component, ElementRef, HostListener, ViewContainerRef, ViewChild, ViewChildren, InjectionToken, PLATFORM_ID, DestroyRef, Input, Directive } from '@angular/core';
|
|
3
3
|
import { HttpClient } from '@angular/common/http';
|
|
4
4
|
import { cidePath, hostManagerRoutesUrl, coreRoutesUrl, commonRoutesUrl, designConfigRoutesUrl } from 'cloud-ide-lms-model';
|
|
5
5
|
import { Observable, throwError, of, BehaviorSubject, interval, take as take$1 } from 'rxjs';
|
|
@@ -13,6 +13,7 @@ import { CommonModule, NgClass, NgFor, NgIf, isPlatformBrowser } from '@angular/
|
|
|
13
13
|
import { CloudIdeAuthService, authGuard } from 'cloud-ide-auth';
|
|
14
14
|
import { trigger, state, transition, style, animate } from '@angular/animations';
|
|
15
15
|
import { merge } from 'lodash';
|
|
16
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
16
17
|
|
|
17
18
|
class CloudIdeLayoutService {
|
|
18
19
|
constructor() { }
|
|
@@ -2651,8 +2652,8 @@ class CideLytSidedrawerWrapperComponent {
|
|
|
2651
2652
|
}
|
|
2652
2653
|
ngOnInit() {
|
|
2653
2654
|
// Initialize the component map (You'd likely populate this from a config or service)
|
|
2654
|
-
this.componentMap['drowar_notes'] = () => import('./cloud-ide-layout-sidedrawer-notes.component-
|
|
2655
|
-
this.componentMap['drawer_theme'] = () => import('./cloud-ide-layout-drawer-theme.component-
|
|
2655
|
+
this.componentMap['drowar_notes'] = () => import('./cloud-ide-layout-sidedrawer-notes.component-GT7A-85i.mjs').then(m => m.CideLytSidedrawerNotesComponent);
|
|
2656
|
+
this.componentMap['drawer_theme'] = () => import('./cloud-ide-layout-drawer-theme.component-B4u9LnTe.mjs').then(m => m.CideLytDrawerThemeComponent);
|
|
2656
2657
|
}
|
|
2657
2658
|
async loadComponent(configFor) {
|
|
2658
2659
|
console.log('🔍 SIDEDRAWER - Loading component:', configFor, 'Current tab:', this.currentTabId);
|
|
@@ -3024,7 +3025,7 @@ const layoutControlPannelChildRoutes = [{
|
|
|
3024
3025
|
},
|
|
3025
3026
|
{
|
|
3026
3027
|
path: "home",
|
|
3027
|
-
loadComponent: () => import('./cloud-ide-layout-home-wrapper.component-
|
|
3028
|
+
loadComponent: () => import('./cloud-ide-layout-home-wrapper.component-DEec7PZk.mjs').then(c => c.CideLytHomeWrapperComponent),
|
|
3028
3029
|
canActivate: [authGuard],
|
|
3029
3030
|
data: {
|
|
3030
3031
|
reuseTab: true, // For CustomRouteReuseStrategy
|
|
@@ -3281,6 +3282,550 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
3281
3282
|
}]
|
|
3282
3283
|
}] });
|
|
3283
3284
|
|
|
3285
|
+
class CideLytFloatingUploadService {
|
|
3286
|
+
destroyRef = inject(DestroyRef);
|
|
3287
|
+
// Private signals for state management
|
|
3288
|
+
_uploadQueue = signal([], ...(ngDevMode ? [{ debugName: "_uploadQueue" }] : []));
|
|
3289
|
+
_isUploading = signal(false, ...(ngDevMode ? [{ debugName: "_isUploading" }] : []));
|
|
3290
|
+
_uploadProgress = signal(0, ...(ngDevMode ? [{ debugName: "_uploadProgress" }] : []));
|
|
3291
|
+
_isVisible = signal(false, ...(ngDevMode ? [{ debugName: "_isVisible" }] : []));
|
|
3292
|
+
_currentUserId = signal('', ...(ngDevMode ? [{ debugName: "_currentUserId" }] : []));
|
|
3293
|
+
// Public readonly signals
|
|
3294
|
+
uploadQueue = this._uploadQueue.asReadonly();
|
|
3295
|
+
isUploading = this._isUploading.asReadonly();
|
|
3296
|
+
uploadProgress = this._uploadProgress.asReadonly();
|
|
3297
|
+
isVisible = this._isVisible.asReadonly();
|
|
3298
|
+
currentUserId = this._currentUserId.asReadonly();
|
|
3299
|
+
// Computed values
|
|
3300
|
+
hasUploads = computed(() => this._uploadQueue().length > 0, ...(ngDevMode ? [{ debugName: "hasUploads" }] : []));
|
|
3301
|
+
pendingUploads = computed(() => this._uploadQueue().filter(upload => upload.status === 'pending'), ...(ngDevMode ? [{ debugName: "pendingUploads" }] : []));
|
|
3302
|
+
activeUploads = computed(() => this._uploadQueue().filter(upload => upload.status === 'uploading'), ...(ngDevMode ? [{ debugName: "activeUploads" }] : []));
|
|
3303
|
+
completedUploads = computed(() => this._uploadQueue().filter(upload => upload.status === 'completed'), ...(ngDevMode ? [{ debugName: "completedUploads" }] : []));
|
|
3304
|
+
failedUploads = computed(() => this._uploadQueue().filter(upload => upload.status === 'error'), ...(ngDevMode ? [{ debugName: "failedUploads" }] : []));
|
|
3305
|
+
// BehaviorSubjects for external subscriptions
|
|
3306
|
+
uploadQueueSubject = new BehaviorSubject([]);
|
|
3307
|
+
isUploadingSubject = new BehaviorSubject(false);
|
|
3308
|
+
uploadProgressSubject = new BehaviorSubject(0);
|
|
3309
|
+
isVisibleSubject = new BehaviorSubject(false);
|
|
3310
|
+
currentUserIdSubject = new BehaviorSubject('');
|
|
3311
|
+
// Public observables
|
|
3312
|
+
uploadQueue$ = this.uploadQueueSubject.asObservable();
|
|
3313
|
+
isUploading$ = this.isUploadingSubject.asObservable();
|
|
3314
|
+
uploadProgress$ = this.uploadProgressSubject.asObservable();
|
|
3315
|
+
isVisible$ = this.isVisibleSubject.asObservable();
|
|
3316
|
+
currentUserId$ = this.currentUserIdSubject.asObservable();
|
|
3317
|
+
constructor() {
|
|
3318
|
+
console.log('🚀 [FloatingUploadService] Service initialized');
|
|
3319
|
+
}
|
|
3320
|
+
/**
|
|
3321
|
+
* Set the current user ID
|
|
3322
|
+
*/
|
|
3323
|
+
setCurrentUserId(userId) {
|
|
3324
|
+
console.log('👤 [FloatingUploadService] Setting user ID:', userId);
|
|
3325
|
+
this._currentUserId.set(userId);
|
|
3326
|
+
this.currentUserIdSubject.next(userId);
|
|
3327
|
+
}
|
|
3328
|
+
/**
|
|
3329
|
+
* Add files to upload queue
|
|
3330
|
+
*/
|
|
3331
|
+
addFilesToQueue(files) {
|
|
3332
|
+
console.log('📁 [FloatingUploadService] Adding files to queue:', files.length);
|
|
3333
|
+
const newUploads = files.map(file => ({
|
|
3334
|
+
fileId: this.generateFileId(),
|
|
3335
|
+
fileName: file.name,
|
|
3336
|
+
progress: 0,
|
|
3337
|
+
status: 'pending'
|
|
3338
|
+
}));
|
|
3339
|
+
const currentQueue = this._uploadQueue();
|
|
3340
|
+
const updatedQueue = [...currentQueue, ...newUploads];
|
|
3341
|
+
this._uploadQueue.set(updatedQueue);
|
|
3342
|
+
this.uploadQueueSubject.next(updatedQueue);
|
|
3343
|
+
this.updateVisibility();
|
|
3344
|
+
}
|
|
3345
|
+
/**
|
|
3346
|
+
* Update upload status
|
|
3347
|
+
*/
|
|
3348
|
+
updateUploadStatus(fileId, status, progress, error, uploadedFile) {
|
|
3349
|
+
console.log('🔄 [FloatingUploadService] Updating upload status:', fileId, status, progress);
|
|
3350
|
+
const currentQueue = this._uploadQueue();
|
|
3351
|
+
const updatedQueue = currentQueue.map(upload => upload.fileId === fileId
|
|
3352
|
+
? { ...upload, status, progress, error, uploadedFile }
|
|
3353
|
+
: upload);
|
|
3354
|
+
this._uploadQueue.set(updatedQueue);
|
|
3355
|
+
this.uploadQueueSubject.next(updatedQueue);
|
|
3356
|
+
this.updateUploadingState();
|
|
3357
|
+
this.updateVisibility();
|
|
3358
|
+
}
|
|
3359
|
+
/**
|
|
3360
|
+
* Cancel upload
|
|
3361
|
+
*/
|
|
3362
|
+
cancelUpload(fileId) {
|
|
3363
|
+
console.log('🚫 [FloatingUploadService] Cancelling upload:', fileId);
|
|
3364
|
+
this.updateUploadStatus(fileId, 'cancelled', 0);
|
|
3365
|
+
}
|
|
3366
|
+
/**
|
|
3367
|
+
* Remove upload from queue
|
|
3368
|
+
*/
|
|
3369
|
+
removeUpload(fileId) {
|
|
3370
|
+
console.log('🗑️ [FloatingUploadService] Removing upload:', fileId);
|
|
3371
|
+
const currentQueue = this._uploadQueue();
|
|
3372
|
+
const updatedQueue = currentQueue.filter(upload => upload.fileId !== fileId);
|
|
3373
|
+
this._uploadQueue.set(updatedQueue);
|
|
3374
|
+
this.uploadQueueSubject.next(updatedQueue);
|
|
3375
|
+
this.updateUploadingState();
|
|
3376
|
+
this.updateVisibility();
|
|
3377
|
+
}
|
|
3378
|
+
/**
|
|
3379
|
+
* Clear all uploads
|
|
3380
|
+
*/
|
|
3381
|
+
clearAllUploads() {
|
|
3382
|
+
console.log('🧹 [FloatingUploadService] Clearing all uploads');
|
|
3383
|
+
this._uploadQueue.set([]);
|
|
3384
|
+
this.uploadQueueSubject.next([]);
|
|
3385
|
+
this._isUploading.set(false);
|
|
3386
|
+
this.isUploadingSubject.next(false);
|
|
3387
|
+
this._uploadProgress.set(0);
|
|
3388
|
+
this.uploadProgressSubject.next(0);
|
|
3389
|
+
this._isVisible.set(false);
|
|
3390
|
+
this.isVisibleSubject.next(false);
|
|
3391
|
+
}
|
|
3392
|
+
/**
|
|
3393
|
+
* Clear completed uploads
|
|
3394
|
+
*/
|
|
3395
|
+
clearCompletedUploads() {
|
|
3396
|
+
console.log('✅ [FloatingUploadService] Clearing completed uploads');
|
|
3397
|
+
const currentQueue = this._uploadQueue();
|
|
3398
|
+
const updatedQueue = currentQueue.filter(upload => upload.status !== 'completed');
|
|
3399
|
+
this._uploadQueue.set(updatedQueue);
|
|
3400
|
+
this.uploadQueueSubject.next(updatedQueue);
|
|
3401
|
+
this.updateUploadingState();
|
|
3402
|
+
this.updateVisibility();
|
|
3403
|
+
}
|
|
3404
|
+
/**
|
|
3405
|
+
* Handle all uploads complete
|
|
3406
|
+
*/
|
|
3407
|
+
handleAllUploadsComplete(event) {
|
|
3408
|
+
console.log('🎉 [FloatingUploadService] All uploads complete:', event);
|
|
3409
|
+
// Update all pending/uploading files to completed
|
|
3410
|
+
const currentQueue = this._uploadQueue();
|
|
3411
|
+
const updatedQueue = currentQueue.map(upload => {
|
|
3412
|
+
if (upload.status === 'pending' || upload.status === 'uploading') {
|
|
3413
|
+
return { ...upload, status: 'completed', progress: 100 };
|
|
3414
|
+
}
|
|
3415
|
+
return upload;
|
|
3416
|
+
});
|
|
3417
|
+
this._uploadQueue.set(updatedQueue);
|
|
3418
|
+
this.uploadQueueSubject.next(updatedQueue);
|
|
3419
|
+
this.updateUploadingState();
|
|
3420
|
+
}
|
|
3421
|
+
/**
|
|
3422
|
+
* Show the floating uploader
|
|
3423
|
+
*/
|
|
3424
|
+
show() {
|
|
3425
|
+
console.log('👁️ [FloatingUploadService] Showing floating uploader');
|
|
3426
|
+
this._isVisible.set(true);
|
|
3427
|
+
this.isVisibleSubject.next(true);
|
|
3428
|
+
}
|
|
3429
|
+
/**
|
|
3430
|
+
* Hide the floating uploader
|
|
3431
|
+
*/
|
|
3432
|
+
hide() {
|
|
3433
|
+
console.log('🙈 [FloatingUploadService] Hiding floating uploader');
|
|
3434
|
+
this._isVisible.set(false);
|
|
3435
|
+
this.isVisibleSubject.next(false);
|
|
3436
|
+
}
|
|
3437
|
+
/**
|
|
3438
|
+
* Update uploading state based on queue
|
|
3439
|
+
*/
|
|
3440
|
+
updateUploadingState() {
|
|
3441
|
+
const activeUploads = this.activeUploads();
|
|
3442
|
+
const isUploading = activeUploads.length > 0;
|
|
3443
|
+
this._isUploading.set(isUploading);
|
|
3444
|
+
this.isUploadingSubject.next(isUploading);
|
|
3445
|
+
if (isUploading) {
|
|
3446
|
+
const totalProgress = activeUploads.reduce((sum, upload) => sum + upload.progress, 0);
|
|
3447
|
+
const averageProgress = Math.round(totalProgress / activeUploads.length);
|
|
3448
|
+
this._uploadProgress.set(averageProgress);
|
|
3449
|
+
this.uploadProgressSubject.next(averageProgress);
|
|
3450
|
+
}
|
|
3451
|
+
else {
|
|
3452
|
+
this._uploadProgress.set(0);
|
|
3453
|
+
this.uploadProgressSubject.next(0);
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
/**
|
|
3457
|
+
* Update visibility based on upload state
|
|
3458
|
+
*/
|
|
3459
|
+
updateVisibility() {
|
|
3460
|
+
const hasActiveUploads = this.activeUploads().length > 0;
|
|
3461
|
+
const hasPendingUploads = this.pendingUploads().length > 0;
|
|
3462
|
+
const hasCompletedUploads = this.completedUploads().length > 0;
|
|
3463
|
+
const hasFailedUploads = this.failedUploads().length > 0;
|
|
3464
|
+
// Show if there are active, pending, or recent completed/failed uploads
|
|
3465
|
+
const shouldShow = hasActiveUploads || hasPendingUploads || hasCompletedUploads || hasFailedUploads;
|
|
3466
|
+
if (shouldShow && !this._isVisible()) {
|
|
3467
|
+
this.show();
|
|
3468
|
+
}
|
|
3469
|
+
else if (!shouldShow && this._isVisible()) {
|
|
3470
|
+
this.hide();
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
/**
|
|
3474
|
+
* Generate unique file ID
|
|
3475
|
+
*/
|
|
3476
|
+
generateFileId() {
|
|
3477
|
+
return `upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
3478
|
+
}
|
|
3479
|
+
/**
|
|
3480
|
+
* Get upload by ID
|
|
3481
|
+
*/
|
|
3482
|
+
getUploadById(fileId) {
|
|
3483
|
+
return this._uploadQueue().find(upload => upload.fileId === fileId);
|
|
3484
|
+
}
|
|
3485
|
+
/**
|
|
3486
|
+
* Get upload statistics
|
|
3487
|
+
*/
|
|
3488
|
+
getUploadStats() {
|
|
3489
|
+
const queue = this._uploadQueue();
|
|
3490
|
+
return {
|
|
3491
|
+
total: queue.length,
|
|
3492
|
+
pending: queue.filter(u => u.status === 'pending').length,
|
|
3493
|
+
uploading: queue.filter(u => u.status === 'uploading').length,
|
|
3494
|
+
completed: queue.filter(u => u.status === 'completed').length,
|
|
3495
|
+
failed: queue.filter(u => u.status === 'error').length,
|
|
3496
|
+
cancelled: queue.filter(u => u.status === 'cancelled').length
|
|
3497
|
+
};
|
|
3498
|
+
}
|
|
3499
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytFloatingUploadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3500
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytFloatingUploadService, providedIn: 'root' });
|
|
3501
|
+
}
|
|
3502
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytFloatingUploadService, decorators: [{
|
|
3503
|
+
type: Injectable,
|
|
3504
|
+
args: [{
|
|
3505
|
+
providedIn: 'root'
|
|
3506
|
+
}]
|
|
3507
|
+
}], ctorParameters: () => [] });
|
|
3508
|
+
|
|
3509
|
+
class CideLytFloatingFileUploaderComponent {
|
|
3510
|
+
destroyRef = inject(DestroyRef);
|
|
3511
|
+
floatingUploadService = inject(CideLytFloatingUploadService);
|
|
3512
|
+
// Signals for reactive state
|
|
3513
|
+
isVisible = signal(false, ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
|
|
3514
|
+
isMinimized = signal(false, ...(ngDevMode ? [{ debugName: "isMinimized" }] : []));
|
|
3515
|
+
uploadQueue = signal([], ...(ngDevMode ? [{ debugName: "uploadQueue" }] : []));
|
|
3516
|
+
isUploading = signal(false, ...(ngDevMode ? [{ debugName: "isUploading" }] : []));
|
|
3517
|
+
uploadProgress = signal(0, ...(ngDevMode ? [{ debugName: "uploadProgress" }] : []));
|
|
3518
|
+
currentUserId = signal('', ...(ngDevMode ? [{ debugName: "currentUserId" }] : []));
|
|
3519
|
+
// Computed values
|
|
3520
|
+
hasUploads = computed(() => this.uploadQueue().length > 0, ...(ngDevMode ? [{ debugName: "hasUploads" }] : []));
|
|
3521
|
+
pendingUploads = computed(() => this.uploadQueue().filter(upload => upload.status === 'pending'), ...(ngDevMode ? [{ debugName: "pendingUploads" }] : []));
|
|
3522
|
+
activeUploads = computed(() => this.uploadQueue().filter(upload => upload.status === 'uploading'), ...(ngDevMode ? [{ debugName: "activeUploads" }] : []));
|
|
3523
|
+
completedUploads = computed(() => this.uploadQueue().filter(upload => upload.status === 'completed'), ...(ngDevMode ? [{ debugName: "completedUploads" }] : []));
|
|
3524
|
+
failedUploads = computed(() => this.uploadQueue().filter(upload => upload.status === 'error'), ...(ngDevMode ? [{ debugName: "failedUploads" }] : []));
|
|
3525
|
+
// Animation states
|
|
3526
|
+
isAnimating = signal(false, ...(ngDevMode ? [{ debugName: "isAnimating" }] : []));
|
|
3527
|
+
constructor() {
|
|
3528
|
+
console.log('🚀 [FloatingFileUploader] Component initialized');
|
|
3529
|
+
}
|
|
3530
|
+
ngOnInit() {
|
|
3531
|
+
// Subscribe to upload service state changes
|
|
3532
|
+
this.floatingUploadService.uploadQueue$
|
|
3533
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3534
|
+
.subscribe(queue => {
|
|
3535
|
+
this.uploadQueue.set(queue);
|
|
3536
|
+
this.updateVisibility();
|
|
3537
|
+
});
|
|
3538
|
+
this.floatingUploadService.isUploading$
|
|
3539
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3540
|
+
.subscribe(isUploading => {
|
|
3541
|
+
this.isUploading.set(isUploading);
|
|
3542
|
+
});
|
|
3543
|
+
this.floatingUploadService.uploadProgress$
|
|
3544
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3545
|
+
.subscribe(progress => {
|
|
3546
|
+
this.uploadProgress.set(progress);
|
|
3547
|
+
});
|
|
3548
|
+
this.floatingUploadService.isVisible$
|
|
3549
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3550
|
+
.subscribe(visible => {
|
|
3551
|
+
this.isVisible.set(visible);
|
|
3552
|
+
});
|
|
3553
|
+
this.floatingUploadService.currentUserId$
|
|
3554
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3555
|
+
.subscribe(userId => {
|
|
3556
|
+
this.currentUserId.set(userId);
|
|
3557
|
+
});
|
|
3558
|
+
}
|
|
3559
|
+
ngOnDestroy() {
|
|
3560
|
+
console.log('🧹 [FloatingFileUploader] Component destroyed');
|
|
3561
|
+
}
|
|
3562
|
+
/**
|
|
3563
|
+
* Update visibility based on upload state
|
|
3564
|
+
*/
|
|
3565
|
+
updateVisibility() {
|
|
3566
|
+
const hasActiveUploads = this.activeUploads().length > 0;
|
|
3567
|
+
const hasPendingUploads = this.pendingUploads().length > 0;
|
|
3568
|
+
const hasCompletedUploads = this.completedUploads().length > 0;
|
|
3569
|
+
const hasFailedUploads = this.failedUploads().length > 0;
|
|
3570
|
+
// Show if there are active, pending, or recent completed/failed uploads
|
|
3571
|
+
const shouldShow = hasActiveUploads || hasPendingUploads || hasCompletedUploads || hasFailedUploads;
|
|
3572
|
+
if (shouldShow && !this.isVisible()) {
|
|
3573
|
+
this.showWithAnimation();
|
|
3574
|
+
}
|
|
3575
|
+
else if (!shouldShow && this.isVisible()) {
|
|
3576
|
+
this.hideWithAnimation();
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
/**
|
|
3580
|
+
* Show with animation
|
|
3581
|
+
*/
|
|
3582
|
+
showWithAnimation() {
|
|
3583
|
+
this.isAnimating.set(true);
|
|
3584
|
+
this.isVisible.set(true);
|
|
3585
|
+
// Remove animation class after animation completes
|
|
3586
|
+
setTimeout(() => {
|
|
3587
|
+
this.isAnimating.set(false);
|
|
3588
|
+
}, 300);
|
|
3589
|
+
}
|
|
3590
|
+
/**
|
|
3591
|
+
* Hide with animation
|
|
3592
|
+
*/
|
|
3593
|
+
hideWithAnimation() {
|
|
3594
|
+
this.isAnimating.set(true);
|
|
3595
|
+
// Wait for animation to complete before hiding
|
|
3596
|
+
setTimeout(() => {
|
|
3597
|
+
this.isVisible.set(false);
|
|
3598
|
+
this.isAnimating.set(false);
|
|
3599
|
+
}, 300);
|
|
3600
|
+
}
|
|
3601
|
+
/**
|
|
3602
|
+
* Toggle minimize state
|
|
3603
|
+
*/
|
|
3604
|
+
toggleMinimize() {
|
|
3605
|
+
this.isMinimized.set(!this.isMinimized());
|
|
3606
|
+
}
|
|
3607
|
+
/**
|
|
3608
|
+
* Close the floating uploader
|
|
3609
|
+
*/
|
|
3610
|
+
close() {
|
|
3611
|
+
this.floatingUploadService.clearAllUploads();
|
|
3612
|
+
this.hideWithAnimation();
|
|
3613
|
+
}
|
|
3614
|
+
/**
|
|
3615
|
+
* Handle file upload completion
|
|
3616
|
+
*/
|
|
3617
|
+
onUploadComplete(event) {
|
|
3618
|
+
console.log('✅ [FloatingFileUploader] Upload completed:', event);
|
|
3619
|
+
this.floatingUploadService.updateUploadStatus(event.fileId, 'completed', 100, undefined, event.uploadedFile);
|
|
3620
|
+
}
|
|
3621
|
+
/**
|
|
3622
|
+
* Handle upload error
|
|
3623
|
+
*/
|
|
3624
|
+
onUploadError(event) {
|
|
3625
|
+
console.error('❌ [FloatingFileUploader] Upload error:', event);
|
|
3626
|
+
this.floatingUploadService.updateUploadStatus(event.fileId, 'error', 0, event.error);
|
|
3627
|
+
}
|
|
3628
|
+
/**
|
|
3629
|
+
* Handle upload cancellation
|
|
3630
|
+
*/
|
|
3631
|
+
onUploadCancelled(fileId) {
|
|
3632
|
+
console.log('🚫 [FloatingFileUploader] Upload cancelled:', fileId);
|
|
3633
|
+
this.floatingUploadService.cancelUpload(fileId);
|
|
3634
|
+
}
|
|
3635
|
+
/**
|
|
3636
|
+
* Handle all uploads complete
|
|
3637
|
+
*/
|
|
3638
|
+
onAllUploadsComplete(event) {
|
|
3639
|
+
console.log('🎉 [FloatingFileUploader] All uploads complete:', event);
|
|
3640
|
+
this.floatingUploadService.handleAllUploadsComplete(event);
|
|
3641
|
+
}
|
|
3642
|
+
/**
|
|
3643
|
+
* Get status icon
|
|
3644
|
+
*/
|
|
3645
|
+
getStatusIcon(status) {
|
|
3646
|
+
switch (status) {
|
|
3647
|
+
case 'pending': return 'schedule';
|
|
3648
|
+
case 'uploading': return 'cloud_upload';
|
|
3649
|
+
case 'completed': return 'check_circle';
|
|
3650
|
+
case 'error': return 'error';
|
|
3651
|
+
case 'cancelled': return 'cancel';
|
|
3652
|
+
default: return 'help';
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
/**
|
|
3656
|
+
* Get status class
|
|
3657
|
+
*/
|
|
3658
|
+
getStatusClass(status) {
|
|
3659
|
+
switch (status) {
|
|
3660
|
+
case 'pending': return 'status-pending';
|
|
3661
|
+
case 'uploading': return 'status-uploading';
|
|
3662
|
+
case 'completed': return 'status-completed';
|
|
3663
|
+
case 'error': return 'status-error';
|
|
3664
|
+
case 'cancelled': return 'status-cancelled';
|
|
3665
|
+
default: return 'status-unknown';
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
/**
|
|
3669
|
+
* Get file size display
|
|
3670
|
+
*/
|
|
3671
|
+
getFileSizeDisplay(size) {
|
|
3672
|
+
if (size === 0)
|
|
3673
|
+
return '0 Bytes';
|
|
3674
|
+
const k = 1024;
|
|
3675
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
3676
|
+
const i = Math.floor(Math.log(size) / Math.log(k));
|
|
3677
|
+
return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
3678
|
+
}
|
|
3679
|
+
/**
|
|
3680
|
+
* Get overall progress percentage
|
|
3681
|
+
*/
|
|
3682
|
+
getOverallProgress() {
|
|
3683
|
+
const uploads = this.uploadQueue();
|
|
3684
|
+
if (uploads.length === 0)
|
|
3685
|
+
return 0;
|
|
3686
|
+
const totalProgress = uploads.reduce((sum, upload) => sum + upload.progress, 0);
|
|
3687
|
+
return Math.round(totalProgress / uploads.length);
|
|
3688
|
+
}
|
|
3689
|
+
/**
|
|
3690
|
+
* Get upload summary text
|
|
3691
|
+
*/
|
|
3692
|
+
getUploadSummary() {
|
|
3693
|
+
const active = this.activeUploads().length;
|
|
3694
|
+
const completed = this.completedUploads().length;
|
|
3695
|
+
const failed = this.failedUploads().length;
|
|
3696
|
+
const pending = this.pendingUploads().length;
|
|
3697
|
+
if (active > 0) {
|
|
3698
|
+
return `${active} uploading`;
|
|
3699
|
+
}
|
|
3700
|
+
else if (completed > 0 && failed === 0) {
|
|
3701
|
+
return `${completed} completed`;
|
|
3702
|
+
}
|
|
3703
|
+
else if (failed > 0) {
|
|
3704
|
+
return `${completed} completed, ${failed} failed`;
|
|
3705
|
+
}
|
|
3706
|
+
else if (pending > 0) {
|
|
3707
|
+
return `${pending} pending`;
|
|
3708
|
+
}
|
|
3709
|
+
return 'No uploads';
|
|
3710
|
+
}
|
|
3711
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytFloatingFileUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3712
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideLytFloatingFileUploaderComponent, isStandalone: true, selector: "cide-layout-floating-file-uploader", ngImport: i0, template: "<!-- Floating File Uploader Container -->\n@if (isVisible()) {\n<div class=\"floating-uploader\" \n [class.minimized]=\"isMinimized()\" \n [class.animating]=\"isAnimating()\"\n [class.uploading]=\"isUploading()\">\n\n <!-- Header -->\n <div class=\"uploader-header\">\n <div class=\"header-left\">\n <div class=\"upload-icon\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n </div>\n <div class=\"upload-info\">\n <div class=\"upload-title\">File Upload</div>\n <div class=\"upload-summary\">{{ getUploadSummary() }}</div>\n </div>\n </div>\n \n <div class=\"header-actions\">\n <button class=\"action-btn minimize-btn\" (click)=\"toggleMinimize()\" [title]=\"isMinimized() ? 'Expand' : 'Minimize'\">\n <cide-ele-icon size=\"xs\">{{ isMinimized() ? 'expand_more' : 'expand_less' }}</cide-ele-icon>\n </button>\n <button class=\"action-btn close-btn\" (click)=\"close()\" title=\"Close\">\n <cide-ele-icon size=\"xs\">close</cide-ele-icon>\n </button>\n </div>\n </div>\n\n <!-- Content (hidden when minimized) -->\n @if (!isMinimized()) {\n <div class=\"uploader-content\">\n \n <!-- Overall Progress Bar -->\n @if (isUploading()) {\n <div class=\"overall-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"getOverallProgress()\"></div>\n </div>\n <div class=\"progress-text\">{{ getOverallProgress() }}%</div>\n </div>\n }\n\n <!-- Upload Queue -->\n @if (hasUploads()) {\n <div class=\"upload-queue\">\n @for (upload of uploadQueue(); track upload.fileId) {\n <div class=\"upload-item\" [class]=\"getStatusClass(upload.status)\">\n \n <!-- File Info -->\n <div class=\"file-info\">\n <cide-ele-icon class=\"status-icon\" size=\"xs\">{{ getStatusIcon(upload.status) }}</cide-ele-icon>\n <div class=\"file-details\">\n <div class=\"file-name\">{{ upload.fileName }}</div>\n <div class=\"file-status\">\n @switch (upload.status) {\n @case ('pending') {\n <span class=\"text-yellow-600\">Waiting...</span>\n }\n @case ('uploading') {\n <span class=\"text-blue-600\">Uploading...</span>\n }\n @case ('completed') {\n <span class=\"text-green-600\">Completed</span>\n }\n @case ('error') {\n <span class=\"text-red-600\">{{ upload.error || 'Failed' }}</span>\n }\n @case ('cancelled') {\n <span class=\"text-gray-600\">Cancelled</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (for uploading files) -->\n @if (upload.status === 'uploading') {\n <div class=\"file-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"upload.progress\"></div>\n </div>\n <span class=\"progress-text\">{{ upload.progress }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"upload-actions\">\n @switch (upload.status) {\n @case ('pending') {\n <button class=\"action-btn cancel-btn\" (click)=\"onUploadCancelled(upload.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)=\"onUploadCancelled(upload.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('completed') {\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 }\n\n <!-- Hidden file input for drag & drop -->\n <div class=\"hidden-uploader\">\n <input type=\"file\" multiple style=\"display: none;\" id=\"floating-file-input\">\n </div>\n </div>\n }\n\n <!-- Footer (always visible) -->\n <div class=\"uploader-footer\">\n <div class=\"footer-stats\">\n @if (activeUploads().length > 0) {\n <span class=\"stat uploading\">\n <cide-ele-icon size=\"xs\">cloud_upload</cide-ele-icon>\n {{ activeUploads().length }} uploading\n </span>\n }\n @if (completedUploads().length > 0) {\n <span class=\"stat completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n {{ completedUploads().length }} completed\n </span>\n }\n @if (failedUploads().length > 0) {\n <span class=\"stat failed\">\n <cide-ele-icon size=\"xs\">error</cide-ele-icon>\n {{ failedUploads().length }} failed\n </span>\n }\n </div>\n </div>\n</div>\n}\n", styles: [".floating-uploader{position:fixed;bottom:20px;right:20px;width:320px;max-height:500px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000001f;border:1px solid rgba(0,0,0,.08);z-index:1000;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1);transform:translateY(0);opacity:1}.floating-uploader.animating{transition:all .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.minimized .uploader-content{display:none}.floating-uploader.minimized .uploader-footer{border-top:none}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f626}.floating-uploader .uploader-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-header .header-left{display:flex;align-items:center;gap:8px}.floating-uploader .uploader-header .header-left .upload-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;border-radius:6px;color:#fff}.floating-uploader .uploader-header .header-left .upload-info .upload-title{font-size:14px;font-weight:600;color:#1e293b;margin:0}.floating-uploader .uploader-header .header-left .upload-info .upload-summary{font-size:12px;color:#64748b;margin:0}.floating-uploader .uploader-header .header-actions{display:flex;gap:4px}.floating-uploader .uploader-header .header-actions .action-btn{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:background-color .2s;color:#64748b}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#e2e8f0;color:#1e293b}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content{max-height:400px;overflow-y:auto}.floating-uploader .uploader-content .overall-progress{padding:12px 16px;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-content .overall-progress .progress-bar{width:100%;height:4px;background:#e2e8f0;border-radius:2px;overflow:hidden;margin-bottom:4px}.floating-uploader .uploader-content .overall-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .overall-progress .progress-text{font-size:12px;color:#64748b;text-align:center;display:block}.floating-uploader .uploader-content .upload-queue .upload-item{display:flex;align-items:center;padding:8px 16px;border-bottom:1px solid #f1f5f9;transition:background-color .2s}.floating-uploader .uploader-content .upload-queue .upload-item:last-child{border-bottom:none}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#f0f9ff}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#f0fdf4}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#fef2f2}.floating-uploader .uploader-content .upload-queue .upload-item .file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .status-icon{flex-shrink:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details{min-width:0;flex:1}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{font-size:13px;font-weight:500;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status{font-size:11px;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status span{font-weight:500}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress{display:flex;align-items:center;gap:8px;margin:0 8px;min-width:80px}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{flex:1;height:3px;background:#e2e8f0;border-radius:2px;overflow:hidden}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text{font-size:10px;color:#64748b;min-width:24px;text-align:right}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions{display:flex;gap:4px}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:all .2s;color:#64748b}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#e2e8f0}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#f0f9ff;color:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#16a34a}.floating-uploader .uploader-content .hidden-uploader{display:none}.floating-uploader .uploader-footer{padding:8px 16px;background:#f8fafc;border-top:1px solid #e2e8f0}.floating-uploader .uploader-footer .footer-stats{display:flex;gap:12px;font-size:11px}.floating-uploader .uploader-footer .footer-stats .stat{display:flex;align-items:center;gap:4px;color:#64748b}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#3b82f6}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#16a34a}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#dc2626}@media (max-width: 640px){.floating-uploader{bottom:10px;right:10px;left:10px;width:auto;max-width:none}}@media (prefers-color-scheme: dark){.floating-uploader{background:#1e293b;border-color:#334155;box-shadow:0 8px 32px #0000004d}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f633}.floating-uploader .uploader-header{background:#334155;border-bottom-color:#475569}.floating-uploader .uploader-header .header-left .upload-icon{background:#3b82f6}.floating-uploader .uploader-header .header-left .upload-info .upload-title{color:#f1f5f9}.floating-uploader .uploader-header .header-left .upload-info .upload-summary,.floating-uploader .uploader-header .header-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#475569;color:#f1f5f9}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .overall-progress{border-bottom-color:#475569}.floating-uploader .uploader-content .overall-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .overall-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .overall-progress .progress-text{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item{border-bottom-color:#334155}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#1e3a8a}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#14532d}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#7f1d1d}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{color:#f1f5f9}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text,.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#1e3a8a;color:#60a5fa}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#4ade80}.floating-uploader .uploader-footer{background:#334155;border-top-color:#475569}.floating-uploader .uploader-footer .footer-stats .stat{color:#94a3b8}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#60a5fa}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#4ade80}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#fca5a5}}@keyframes slideInUp{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes slideOutDown{0%{transform:translateY(0);opacity:1}to{transform:translateY(100%);opacity:0}}.floating-uploader.animating{animation:slideInUp .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.animating.hiding{animation:slideOutDown .3s cubic-bezier(.4,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
|
|
3713
|
+
}
|
|
3714
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytFloatingFileUploaderComponent, decorators: [{
|
|
3715
|
+
type: Component,
|
|
3716
|
+
args: [{ selector: 'cide-layout-floating-file-uploader', standalone: true, imports: [
|
|
3717
|
+
CommonModule,
|
|
3718
|
+
CideIconComponent
|
|
3719
|
+
], template: "<!-- Floating File Uploader Container -->\n@if (isVisible()) {\n<div class=\"floating-uploader\" \n [class.minimized]=\"isMinimized()\" \n [class.animating]=\"isAnimating()\"\n [class.uploading]=\"isUploading()\">\n\n <!-- Header -->\n <div class=\"uploader-header\">\n <div class=\"header-left\">\n <div class=\"upload-icon\">\n <cide-ele-icon size=\"sm\">cloud_upload</cide-ele-icon>\n </div>\n <div class=\"upload-info\">\n <div class=\"upload-title\">File Upload</div>\n <div class=\"upload-summary\">{{ getUploadSummary() }}</div>\n </div>\n </div>\n \n <div class=\"header-actions\">\n <button class=\"action-btn minimize-btn\" (click)=\"toggleMinimize()\" [title]=\"isMinimized() ? 'Expand' : 'Minimize'\">\n <cide-ele-icon size=\"xs\">{{ isMinimized() ? 'expand_more' : 'expand_less' }}</cide-ele-icon>\n </button>\n <button class=\"action-btn close-btn\" (click)=\"close()\" title=\"Close\">\n <cide-ele-icon size=\"xs\">close</cide-ele-icon>\n </button>\n </div>\n </div>\n\n <!-- Content (hidden when minimized) -->\n @if (!isMinimized()) {\n <div class=\"uploader-content\">\n \n <!-- Overall Progress Bar -->\n @if (isUploading()) {\n <div class=\"overall-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"getOverallProgress()\"></div>\n </div>\n <div class=\"progress-text\">{{ getOverallProgress() }}%</div>\n </div>\n }\n\n <!-- Upload Queue -->\n @if (hasUploads()) {\n <div class=\"upload-queue\">\n @for (upload of uploadQueue(); track upload.fileId) {\n <div class=\"upload-item\" [class]=\"getStatusClass(upload.status)\">\n \n <!-- File Info -->\n <div class=\"file-info\">\n <cide-ele-icon class=\"status-icon\" size=\"xs\">{{ getStatusIcon(upload.status) }}</cide-ele-icon>\n <div class=\"file-details\">\n <div class=\"file-name\">{{ upload.fileName }}</div>\n <div class=\"file-status\">\n @switch (upload.status) {\n @case ('pending') {\n <span class=\"text-yellow-600\">Waiting...</span>\n }\n @case ('uploading') {\n <span class=\"text-blue-600\">Uploading...</span>\n }\n @case ('completed') {\n <span class=\"text-green-600\">Completed</span>\n }\n @case ('error') {\n <span class=\"text-red-600\">{{ upload.error || 'Failed' }}</span>\n }\n @case ('cancelled') {\n <span class=\"text-gray-600\">Cancelled</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (for uploading files) -->\n @if (upload.status === 'uploading') {\n <div class=\"file-progress\">\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width.%]=\"upload.progress\"></div>\n </div>\n <span class=\"progress-text\">{{ upload.progress }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"upload-actions\">\n @switch (upload.status) {\n @case ('pending') {\n <button class=\"action-btn cancel-btn\" (click)=\"onUploadCancelled(upload.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)=\"onUploadCancelled(upload.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('completed') {\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 }\n\n <!-- Hidden file input for drag & drop -->\n <div class=\"hidden-uploader\">\n <input type=\"file\" multiple style=\"display: none;\" id=\"floating-file-input\">\n </div>\n </div>\n }\n\n <!-- Footer (always visible) -->\n <div class=\"uploader-footer\">\n <div class=\"footer-stats\">\n @if (activeUploads().length > 0) {\n <span class=\"stat uploading\">\n <cide-ele-icon size=\"xs\">cloud_upload</cide-ele-icon>\n {{ activeUploads().length }} uploading\n </span>\n }\n @if (completedUploads().length > 0) {\n <span class=\"stat completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n {{ completedUploads().length }} completed\n </span>\n }\n @if (failedUploads().length > 0) {\n <span class=\"stat failed\">\n <cide-ele-icon size=\"xs\">error</cide-ele-icon>\n {{ failedUploads().length }} failed\n </span>\n }\n </div>\n </div>\n</div>\n}\n", styles: [".floating-uploader{position:fixed;bottom:20px;right:20px;width:320px;max-height:500px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000001f;border:1px solid rgba(0,0,0,.08);z-index:1000;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1);transform:translateY(0);opacity:1}.floating-uploader.animating{transition:all .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.minimized .uploader-content{display:none}.floating-uploader.minimized .uploader-footer{border-top:none}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f626}.floating-uploader .uploader-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-header .header-left{display:flex;align-items:center;gap:8px}.floating-uploader .uploader-header .header-left .upload-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;border-radius:6px;color:#fff}.floating-uploader .uploader-header .header-left .upload-info .upload-title{font-size:14px;font-weight:600;color:#1e293b;margin:0}.floating-uploader .uploader-header .header-left .upload-info .upload-summary{font-size:12px;color:#64748b;margin:0}.floating-uploader .uploader-header .header-actions{display:flex;gap:4px}.floating-uploader .uploader-header .header-actions .action-btn{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:background-color .2s;color:#64748b}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#e2e8f0;color:#1e293b}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content{max-height:400px;overflow-y:auto}.floating-uploader .uploader-content .overall-progress{padding:12px 16px;border-bottom:1px solid #e2e8f0}.floating-uploader .uploader-content .overall-progress .progress-bar{width:100%;height:4px;background:#e2e8f0;border-radius:2px;overflow:hidden;margin-bottom:4px}.floating-uploader .uploader-content .overall-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .overall-progress .progress-text{font-size:12px;color:#64748b;text-align:center;display:block}.floating-uploader .uploader-content .upload-queue .upload-item{display:flex;align-items:center;padding:8px 16px;border-bottom:1px solid #f1f5f9;transition:background-color .2s}.floating-uploader .uploader-content .upload-queue .upload-item:last-child{border-bottom:none}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#f0f9ff}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#f0fdf4}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#fef2f2}.floating-uploader .uploader-content .upload-queue .upload-item .file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .status-icon{flex-shrink:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details{min-width:0;flex:1}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{font-size:13px;font-weight:500;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status{font-size:11px;margin:0}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-status span{font-weight:500}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress{display:flex;align-items:center;gap:8px;margin:0 8px;min-width:80px}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{flex:1;height:3px;background:#e2e8f0;border-radius:2px;overflow:hidden}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{height:100%;background:#3b82f6;transition:width .3s ease}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text{font-size:10px;color:#64748b;min-width:24px;text-align:right}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions{display:flex;gap:4px}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border:none;background:transparent;border-radius:4px;cursor:pointer;transition:all .2s;color:#64748b}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#e2e8f0}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#fef2f2;color:#dc2626}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#f0f9ff;color:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#16a34a}.floating-uploader .uploader-content .hidden-uploader{display:none}.floating-uploader .uploader-footer{padding:8px 16px;background:#f8fafc;border-top:1px solid #e2e8f0}.floating-uploader .uploader-footer .footer-stats{display:flex;gap:12px;font-size:11px}.floating-uploader .uploader-footer .footer-stats .stat{display:flex;align-items:center;gap:4px;color:#64748b}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#3b82f6}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#16a34a}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#dc2626}@media (max-width: 640px){.floating-uploader{bottom:10px;right:10px;left:10px;width:auto;max-width:none}}@media (prefers-color-scheme: dark){.floating-uploader{background:#1e293b;border-color:#334155;box-shadow:0 8px 32px #0000004d}.floating-uploader.uploading{border-color:#3b82f6;box-shadow:0 8px 32px #3b82f633}.floating-uploader .uploader-header{background:#334155;border-bottom-color:#475569}.floating-uploader .uploader-header .header-left .upload-icon{background:#3b82f6}.floating-uploader .uploader-header .header-left .upload-info .upload-title{color:#f1f5f9}.floating-uploader .uploader-header .header-left .upload-info .upload-summary,.floating-uploader .uploader-header .header-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-header .header-actions .action-btn:hover{background:#475569;color:#f1f5f9}.floating-uploader .uploader-header .header-actions .action-btn.close-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .overall-progress{border-bottom-color:#475569}.floating-uploader .uploader-content .overall-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .overall-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .overall-progress .progress-text{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item{border-bottom-color:#334155}.floating-uploader .uploader-content .upload-queue .upload-item.status-uploading{background:#1e3a8a}.floating-uploader .uploader-content .upload-queue .upload-item.status-completed{background:#14532d}.floating-uploader .uploader-content .upload-queue .upload-item.status-error{background:#7f1d1d}.floating-uploader .uploader-content .upload-queue .upload-item .file-info .file-details .file-name{color:#f1f5f9}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-bar .progress-fill{background:#3b82f6}.floating-uploader .uploader-content .upload-queue .upload-item .file-progress .progress-text,.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn{color:#94a3b8}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn:hover{background:#475569}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.cancel-btn:hover{background:#7f1d1d;color:#fca5a5}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.retry-btn:hover{background:#1e3a8a;color:#60a5fa}.floating-uploader .uploader-content .upload-queue .upload-item .upload-actions .action-btn.success-btn{color:#4ade80}.floating-uploader .uploader-footer{background:#334155;border-top-color:#475569}.floating-uploader .uploader-footer .footer-stats .stat{color:#94a3b8}.floating-uploader .uploader-footer .footer-stats .stat.uploading{color:#60a5fa}.floating-uploader .uploader-footer .footer-stats .stat.completed{color:#4ade80}.floating-uploader .uploader-footer .footer-stats .stat.failed{color:#fca5a5}}@keyframes slideInUp{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes slideOutDown{0%{transform:translateY(0);opacity:1}to{transform:translateY(100%);opacity:0}}.floating-uploader.animating{animation:slideInUp .3s cubic-bezier(.4,0,.2,1)}.floating-uploader.animating.hiding{animation:slideOutDown .3s cubic-bezier(.4,0,.2,1)}\n"] }]
|
|
3720
|
+
}], ctorParameters: () => [] });
|
|
3721
|
+
|
|
3722
|
+
class CideLytLayoutWithFloatingUploaderComponent {
|
|
3723
|
+
destroyRef = inject(DestroyRef);
|
|
3724
|
+
floatingUploadService = inject(CideLytFloatingUploadService);
|
|
3725
|
+
// Signals for reactive state
|
|
3726
|
+
isVisible = signal(false, ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
|
|
3727
|
+
uploadCount = signal(0, ...(ngDevMode ? [{ debugName: "uploadCount" }] : []));
|
|
3728
|
+
// Computed values
|
|
3729
|
+
hasUploads = computed(() => this.uploadCount() > 0, ...(ngDevMode ? [{ debugName: "hasUploads" }] : []));
|
|
3730
|
+
constructor() {
|
|
3731
|
+
console.log('🚀 [LayoutWithFloatingUploader] Component initialized');
|
|
3732
|
+
}
|
|
3733
|
+
ngOnInit() {
|
|
3734
|
+
// Subscribe to floating upload service state
|
|
3735
|
+
this.floatingUploadService.isVisible$
|
|
3736
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3737
|
+
.subscribe(visible => {
|
|
3738
|
+
this.isVisible.set(visible);
|
|
3739
|
+
});
|
|
3740
|
+
this.floatingUploadService.uploadQueue$
|
|
3741
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3742
|
+
.subscribe(queue => {
|
|
3743
|
+
this.uploadCount.set(queue.length);
|
|
3744
|
+
});
|
|
3745
|
+
}
|
|
3746
|
+
ngOnDestroy() {
|
|
3747
|
+
console.log('🧹 [LayoutWithFloatingUploader] Component destroyed');
|
|
3748
|
+
}
|
|
3749
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytLayoutWithFloatingUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3750
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.7", type: CideLytLayoutWithFloatingUploaderComponent, isStandalone: true, selector: "cide-layout-with-floating-uploader", ngImport: i0, template: "<!-- Layout with Floating Uploader -->\r\n<div class=\"layout-container\">\r\n <!-- Main Content Slot -->\r\n <ng-content></ng-content>\r\n \r\n <!-- Floating File Uploader -->\r\n <cide-layout-floating-file-uploader></cide-layout-floating-file-uploader>\r\n</div>\r\n\r\n", styles: [".layout-container{position:relative;width:100%;height:100%;min-height:100vh}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideLytFloatingFileUploaderComponent, selector: "cide-layout-floating-file-uploader" }] });
|
|
3751
|
+
}
|
|
3752
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytLayoutWithFloatingUploaderComponent, decorators: [{
|
|
3753
|
+
type: Component,
|
|
3754
|
+
args: [{ selector: 'cide-layout-with-floating-uploader', standalone: true, imports: [
|
|
3755
|
+
CommonModule,
|
|
3756
|
+
CideLytFloatingFileUploaderComponent
|
|
3757
|
+
], template: "<!-- Layout with Floating Uploader -->\r\n<div class=\"layout-container\">\r\n <!-- Main Content Slot -->\r\n <ng-content></ng-content>\r\n \r\n <!-- Floating File Uploader -->\r\n <cide-layout-floating-file-uploader></cide-layout-floating-file-uploader>\r\n</div>\r\n\r\n", styles: [".layout-container{position:relative;width:100%;height:100%;min-height:100vh}\n"] }]
|
|
3758
|
+
}], ctorParameters: () => [] });
|
|
3759
|
+
|
|
3760
|
+
class CideLytFloatingUploadTriggerDirective {
|
|
3761
|
+
elementRef = inject(ElementRef);
|
|
3762
|
+
floatingUploadService = inject(CideLytFloatingUploadService);
|
|
3763
|
+
userId = '';
|
|
3764
|
+
constructor() {
|
|
3765
|
+
console.log('🎯 [FloatingUploadTrigger] Directive initialized');
|
|
3766
|
+
}
|
|
3767
|
+
onFileChange(event) {
|
|
3768
|
+
const input = event.target;
|
|
3769
|
+
const files = input.files;
|
|
3770
|
+
if (files && files.length > 0) {
|
|
3771
|
+
console.log('📁 [FloatingUploadTrigger] Files selected:', files.length);
|
|
3772
|
+
// Set user ID if provided
|
|
3773
|
+
if (this.userId) {
|
|
3774
|
+
this.floatingUploadService.setCurrentUserId(this.userId);
|
|
3775
|
+
}
|
|
3776
|
+
// Add files to floating uploader queue
|
|
3777
|
+
this.floatingUploadService.addFilesToQueue(Array.from(files));
|
|
3778
|
+
// Reset the input to allow selecting the same files again
|
|
3779
|
+
input.value = '';
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
onDragOver(event) {
|
|
3783
|
+
event.preventDefault();
|
|
3784
|
+
event.stopPropagation();
|
|
3785
|
+
}
|
|
3786
|
+
onDragEnter(event) {
|
|
3787
|
+
event.preventDefault();
|
|
3788
|
+
event.stopPropagation();
|
|
3789
|
+
}
|
|
3790
|
+
onDrop(event) {
|
|
3791
|
+
event.preventDefault();
|
|
3792
|
+
event.stopPropagation();
|
|
3793
|
+
const files = event.dataTransfer?.files;
|
|
3794
|
+
if (files && files.length > 0) {
|
|
3795
|
+
console.log('📁 [FloatingUploadTrigger] Files dropped:', files.length);
|
|
3796
|
+
// Set user ID if provided
|
|
3797
|
+
if (this.userId) {
|
|
3798
|
+
this.floatingUploadService.setCurrentUserId(this.userId);
|
|
3799
|
+
}
|
|
3800
|
+
// Add files to floating uploader queue
|
|
3801
|
+
this.floatingUploadService.addFilesToQueue(Array.from(files));
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytFloatingUploadTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3805
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.7", type: CideLytFloatingUploadTriggerDirective, isStandalone: true, selector: "[cideFloatingUploadTrigger]", inputs: { userId: "userId" }, host: { listeners: { "change": "onFileChange($event)", "dragover": "onDragOver($event)", "dragenter": "onDragEnter($event)", "drop": "onDrop($event)" } }, ngImport: i0 });
|
|
3806
|
+
}
|
|
3807
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytFloatingUploadTriggerDirective, decorators: [{
|
|
3808
|
+
type: Directive,
|
|
3809
|
+
args: [{
|
|
3810
|
+
selector: '[cideFloatingUploadTrigger]',
|
|
3811
|
+
standalone: true
|
|
3812
|
+
}]
|
|
3813
|
+
}], ctorParameters: () => [], propDecorators: { userId: [{
|
|
3814
|
+
type: Input
|
|
3815
|
+
}], onFileChange: [{
|
|
3816
|
+
type: HostListener,
|
|
3817
|
+
args: ['change', ['$event']]
|
|
3818
|
+
}], onDragOver: [{
|
|
3819
|
+
type: HostListener,
|
|
3820
|
+
args: ['dragover', ['$event']]
|
|
3821
|
+
}], onDragEnter: [{
|
|
3822
|
+
type: HostListener,
|
|
3823
|
+
args: ['dragenter', ['$event']]
|
|
3824
|
+
}], onDrop: [{
|
|
3825
|
+
type: HostListener,
|
|
3826
|
+
args: ['drop', ['$event']]
|
|
3827
|
+
}] } });
|
|
3828
|
+
|
|
3284
3829
|
/*
|
|
3285
3830
|
* Public API Surface of cloud-ide-layout
|
|
3286
3831
|
*/
|
|
@@ -3289,5 +3834,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
3289
3834
|
* Generated bundle index. Do not edit.
|
|
3290
3835
|
*/
|
|
3291
3836
|
|
|
3292
|
-
export { AppStateHelperService as A, CideLytSharedWrapperComponent as C, ENVIRONMENT_CONFIG as E, CideLytSidebarService as a, CideLytRequestService as b, CideLytSidedrawerService as c, CideLytThemeService as d, CloudIdeLayoutService as e, CloudIdeLayoutComponent as f, CideLytSharedService as g, layoutControlPannelChildRoutes as h, CustomRouteReuseStrategy as i, AppStateService as j, CideLytUserStatusService as k, layoutRoutes as l, CacheManagerService as m, CideLytFileManagerService as n, processThemeVariable as p, setCSSVariable as s, themeFactory as t };
|
|
3293
|
-
//# sourceMappingURL=cloud-ide-layout-cloud-ide-layout-
|
|
3837
|
+
export { AppStateHelperService as A, CideLytSharedWrapperComponent as C, ENVIRONMENT_CONFIG as E, CideLytSidebarService as a, CideLytRequestService as b, CideLytSidedrawerService as c, CideLytThemeService as d, CloudIdeLayoutService as e, CloudIdeLayoutComponent as f, CideLytSharedService as g, layoutControlPannelChildRoutes as h, CustomRouteReuseStrategy as i, AppStateService as j, CideLytUserStatusService as k, layoutRoutes as l, CacheManagerService as m, CideLytFileManagerService as n, CideLytFloatingFileUploaderComponent as o, processThemeVariable as p, CideLytLayoutWithFloatingUploaderComponent as q, CideLytFloatingUploadService as r, setCSSVariable as s, themeFactory as t, CideLytFloatingUploadTriggerDirective as u };
|
|
3838
|
+
//# sourceMappingURL=cloud-ide-layout-cloud-ide-layout-RD9NYgsO.mjs.map
|