osl-base-extended 2.0.37 → 3.0.0
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.
|
@@ -5371,6 +5371,217 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
5371
5371
|
args: ['click', ['$event']]
|
|
5372
5372
|
}] } });
|
|
5373
5373
|
|
|
5374
|
+
class OslDocumentUploader {
|
|
5375
|
+
label = '';
|
|
5376
|
+
required = false;
|
|
5377
|
+
disabled = false;
|
|
5378
|
+
multiple = false;
|
|
5379
|
+
accept = '';
|
|
5380
|
+
maxSize = 0;
|
|
5381
|
+
minFiles = 0;
|
|
5382
|
+
maxFiles = 0;
|
|
5383
|
+
showUploadButton = false;
|
|
5384
|
+
uploadButtonLabel = 'Upload Files';
|
|
5385
|
+
savedDocuments = [];
|
|
5386
|
+
skeletonLoading = false;
|
|
5387
|
+
skeletonTheme = 'light';
|
|
5388
|
+
uploadCallback = new EventEmitter();
|
|
5389
|
+
viewCallback = new EventEmitter();
|
|
5390
|
+
deleteCallback = new EventEmitter();
|
|
5391
|
+
downloadCallback = new EventEmitter();
|
|
5392
|
+
filesChanged = new EventEmitter();
|
|
5393
|
+
pendingFiles = [];
|
|
5394
|
+
isDragOver = false;
|
|
5395
|
+
sizeErrors = [];
|
|
5396
|
+
touched = false;
|
|
5397
|
+
get maxFilesReached() {
|
|
5398
|
+
return this.multiple && this.maxFiles > 0 && this.pendingFiles.length >= this.maxFiles;
|
|
5399
|
+
}
|
|
5400
|
+
get isBelowMin() {
|
|
5401
|
+
return this.minFiles > 0 && this.pendingFiles.length > 0 && this.pendingFiles.length < this.minFiles;
|
|
5402
|
+
}
|
|
5403
|
+
get isInvalid() {
|
|
5404
|
+
if (!this.touched)
|
|
5405
|
+
return false;
|
|
5406
|
+
if (this.required && this.pendingFiles.length === 0)
|
|
5407
|
+
return true;
|
|
5408
|
+
return this.isBelowMin;
|
|
5409
|
+
}
|
|
5410
|
+
get requiredError() {
|
|
5411
|
+
return this.touched && this.required && this.pendingFiles.length === 0;
|
|
5412
|
+
}
|
|
5413
|
+
get minFilesError() {
|
|
5414
|
+
return this.touched && this.isBelowMin;
|
|
5415
|
+
}
|
|
5416
|
+
get maxSizeLabel() {
|
|
5417
|
+
if (!this.maxSize)
|
|
5418
|
+
return '';
|
|
5419
|
+
if (this.maxSize >= 1024 * 1024)
|
|
5420
|
+
return `Max ${(this.maxSize / 1024 / 1024).toFixed(1)} MB`;
|
|
5421
|
+
if (this.maxSize >= 1024)
|
|
5422
|
+
return `Max ${(this.maxSize / 1024).toFixed(0)} KB`;
|
|
5423
|
+
return `Max ${this.maxSize} B`;
|
|
5424
|
+
}
|
|
5425
|
+
getFileSize(bytes) {
|
|
5426
|
+
if (bytes >= 1024 * 1024)
|
|
5427
|
+
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
5428
|
+
if (bytes >= 1024)
|
|
5429
|
+
return `${(bytes / 1024).toFixed(0)} KB`;
|
|
5430
|
+
return `${bytes} B`;
|
|
5431
|
+
}
|
|
5432
|
+
getFileType(name) {
|
|
5433
|
+
const ext = name.split('.').pop()?.toLowerCase() || '';
|
|
5434
|
+
if (['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'bmp', 'ico'].includes(ext))
|
|
5435
|
+
return 'image';
|
|
5436
|
+
if (ext === 'pdf')
|
|
5437
|
+
return 'pdf';
|
|
5438
|
+
if (['doc', 'docx'].includes(ext))
|
|
5439
|
+
return 'word';
|
|
5440
|
+
if (['xls', 'xlsx', 'csv'].includes(ext))
|
|
5441
|
+
return 'excel';
|
|
5442
|
+
if (['zip', 'rar', '7z', 'tar', 'gz'].includes(ext))
|
|
5443
|
+
return 'archive';
|
|
5444
|
+
return 'generic';
|
|
5445
|
+
}
|
|
5446
|
+
formatDate(value) {
|
|
5447
|
+
if (!value)
|
|
5448
|
+
return '';
|
|
5449
|
+
const d = new Date(value);
|
|
5450
|
+
if (isNaN(d.getTime()))
|
|
5451
|
+
return String(value);
|
|
5452
|
+
return d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' });
|
|
5453
|
+
}
|
|
5454
|
+
onFileChange(event) {
|
|
5455
|
+
this.touched = true;
|
|
5456
|
+
const input = event.target;
|
|
5457
|
+
this.processFiles(input.files);
|
|
5458
|
+
input.value = '';
|
|
5459
|
+
}
|
|
5460
|
+
onDragOver(event) {
|
|
5461
|
+
event.preventDefault();
|
|
5462
|
+
if (!this.disabled && !this.maxFilesReached)
|
|
5463
|
+
this.isDragOver = true;
|
|
5464
|
+
}
|
|
5465
|
+
onDragLeave(event) {
|
|
5466
|
+
const target = event.currentTarget;
|
|
5467
|
+
const related = event.relatedTarget;
|
|
5468
|
+
if (!related || !target.contains(related))
|
|
5469
|
+
this.isDragOver = false;
|
|
5470
|
+
}
|
|
5471
|
+
onDrop(event) {
|
|
5472
|
+
event.preventDefault();
|
|
5473
|
+
this.isDragOver = false;
|
|
5474
|
+
if (this.disabled || this.maxFilesReached)
|
|
5475
|
+
return;
|
|
5476
|
+
this.touched = true;
|
|
5477
|
+
this.processFiles(event.dataTransfer?.files ?? null);
|
|
5478
|
+
}
|
|
5479
|
+
processFiles(files) {
|
|
5480
|
+
if (!files || files.length === 0)
|
|
5481
|
+
return;
|
|
5482
|
+
this.sizeErrors = [];
|
|
5483
|
+
const newFiles = [];
|
|
5484
|
+
for (let i = 0; i < files.length; i++) {
|
|
5485
|
+
const file = files[i];
|
|
5486
|
+
if (this.maxSize > 0 && file.size > this.maxSize) {
|
|
5487
|
+
this.sizeErrors.push(`"${file.name}" exceeds the ${this.maxSizeLabel} limit.`);
|
|
5488
|
+
continue;
|
|
5489
|
+
}
|
|
5490
|
+
newFiles.push(file);
|
|
5491
|
+
}
|
|
5492
|
+
if (this.multiple) {
|
|
5493
|
+
const remaining = this.maxFiles > 0 ? this.maxFiles - this.pendingFiles.length : newFiles.length;
|
|
5494
|
+
const toAdd = newFiles.slice(0, remaining);
|
|
5495
|
+
if (newFiles.length > remaining) {
|
|
5496
|
+
this.sizeErrors.push(`Only ${remaining} more file(s) can be added. ${newFiles.length - remaining} skipped.`);
|
|
5497
|
+
}
|
|
5498
|
+
this.pendingFiles = [...this.pendingFiles, ...toAdd];
|
|
5499
|
+
}
|
|
5500
|
+
else {
|
|
5501
|
+
this.pendingFiles = newFiles.slice(0, 1);
|
|
5502
|
+
}
|
|
5503
|
+
this.filesChanged.emit(this.pendingFiles);
|
|
5504
|
+
}
|
|
5505
|
+
removeFile(index) {
|
|
5506
|
+
this.pendingFiles = this.pendingFiles.filter((_, i) => i !== index);
|
|
5507
|
+
this.filesChanged.emit(this.pendingFiles);
|
|
5508
|
+
}
|
|
5509
|
+
triggerInput(fileInput) {
|
|
5510
|
+
if (!this.disabled && !this.maxFilesReached)
|
|
5511
|
+
fileInput.click();
|
|
5512
|
+
}
|
|
5513
|
+
upload() {
|
|
5514
|
+
if (this.pendingFiles.length === 0)
|
|
5515
|
+
return;
|
|
5516
|
+
const formData = new FormData();
|
|
5517
|
+
if (this.multiple) {
|
|
5518
|
+
this.pendingFiles.forEach(file => formData.append('files', file, file.name));
|
|
5519
|
+
}
|
|
5520
|
+
else {
|
|
5521
|
+
formData.append('file', this.pendingFiles[0], this.pendingFiles[0].name);
|
|
5522
|
+
}
|
|
5523
|
+
this.uploadCallback.emit(formData);
|
|
5524
|
+
}
|
|
5525
|
+
onView(doc) { this.viewCallback.emit(doc); }
|
|
5526
|
+
onDelete(doc) { this.deleteCallback.emit(doc); }
|
|
5527
|
+
onDownload(doc) { this.downloadCallback.emit(doc); }
|
|
5528
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslDocumentUploader, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5529
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OslDocumentUploader, isStandalone: false, selector: "osl-document-uploader", inputs: { label: "label", required: "required", disabled: "disabled", multiple: "multiple", accept: "accept", maxSize: "maxSize", minFiles: "minFiles", maxFiles: "maxFiles", showUploadButton: "showUploadButton", uploadButtonLabel: "uploadButtonLabel", savedDocuments: "savedDocuments", skeletonLoading: "skeletonLoading", skeletonTheme: "skeletonTheme" }, outputs: { uploadCallback: "uploadCallback", viewCallback: "viewCallback", deleteCallback: "deleteCallback", downloadCallback: "downloadCallback", filesChanged: "filesChanged" }, ngImport: i0, template: "<div class=\"du-container\" [class.du--disabled]=\"disabled\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\n\n @if (label) {\n <label class=\"du-label\" [class.du-label--error]=\"isInvalid\">\n <span class=\"du-label__text\" [title]=\"label\">{{ label }}</span>\n @if (required) { <span class=\"du-label__req\">*</span> }\n </label>\n }\n\n <input type=\"file\" [accept]=\"accept\" [multiple]=\"multiple\" [disabled]=\"disabled || maxFilesReached\"\n (change)=\"onFileChange($event)\" #fileInput class=\"du-file-input\">\n\n <!-- \u2500\u2500 Drop Zone \u2500\u2500 -->\n <div class=\"du-dropzone\"\n [class.du-dropzone--over]=\"isDragOver\"\n [class.du-dropzone--error]=\"isInvalid\"\n [class.du-dropzone--disabled]=\"disabled\"\n [class.du-dropzone--maxed]=\"maxFilesReached\"\n (click)=\"triggerInput(fileInput)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n\n <div class=\"du-particles\">\n <span class=\"du-p du-p--1\"></span>\n <span class=\"du-p du-p--2\"></span>\n <span class=\"du-p du-p--3\"></span>\n <span class=\"du-p du-p--4\"></span>\n <span class=\"du-p du-p--5\"></span>\n <span class=\"du-p du-p--6\"></span>\n </div>\n\n <div class=\"du-dropzone__inner\">\n\n @if (maxFilesReached) {\n <!-- Max files reached state -->\n <div class=\"du-maxed-icon\">\n <svg viewBox=\"0 0 64 64\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"#f0fdf4\" stroke=\"#86efac\" stroke-width=\"2\"/>\n <path d=\"M20 32l8 8 16-16\" stroke=\"#22c55e\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n <p class=\"du-dropzone__headline\">\n <span class=\"du-gradient-text du-gradient-text--green\">Limit reached</span>\n </p>\n <p class=\"du-maxed-sub\">{{ maxFiles }} / {{ maxFiles }} files added</p>\n } @else {\n\n <!-- Cloud SVG -->\n <div class=\"du-cloud-wrap\" [class.du-cloud-wrap--over]=\"isDragOver\">\n <svg class=\"du-cloud-svg\" viewBox=\"0 0 90 72\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path class=\"du-cloud-body\"\n d=\"M63 42H27C19.8 42 14 36.2 14 29C14 22.2 19.2 16.7 25.8 16.1C25.9 9.4 31.3 4 38 4C42.8 4 47 6.7 49.2 10.7C50.8 9.6 52.8 9 55 9C61 9 65.9 13.9 65.9 19.9V20.1C72.1 20.9 77 26.3 77 33C77 38.1 70.7 42 63 42Z\"\n stroke=\"#667eea\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <line class=\"du-arrow\" x1=\"45\" y1=\"64\" x2=\"45\" y2=\"46\" stroke=\"#764ba2\" stroke-width=\"2.5\" stroke-linecap=\"round\"/>\n <polyline class=\"du-arrow\" points=\"37,55 45,46 53,55\"\n stroke=\"#764ba2\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\"/>\n <circle class=\"du-cloud-glint\" cx=\"30\" cy=\"26\" r=\"3\" fill=\"#a5b4fc\" opacity=\"0.5\"/>\n </svg>\n </div>\n\n @if (!isDragOver) {\n <p class=\"du-dropzone__headline\">\n <span class=\"du-gradient-text\">Click to browse</span><span class=\"du-or\"> or drag & drop</span>\n </p>\n <div class=\"du-dropzone__meta\">\n @if (multiple) {\n @if (maxFiles > 0 && minFiles > 0) {\n <span class=\"du-chip du-chip--info\">{{ minFiles }}\u2013{{ maxFiles }} files</span>\n } @else if (maxFiles > 0) {\n <span class=\"du-chip du-chip--info\">Max {{ maxFiles }} files</span>\n } @else if (minFiles > 0) {\n <span class=\"du-chip du-chip--info\">Min {{ minFiles }} files</span>\n } @else {\n <span class=\"du-chip du-chip--info\">Multiple files</span>\n }\n } @else {\n <span class=\"du-chip du-chip--info\">Single file</span>\n }\n @if (accept) { <span class=\"du-chip\">{{ accept }}</span> }\n @if (maxSize) { <span class=\"du-chip\">{{ maxSizeLabel }}</span> }\n </div>\n } @else {\n <p class=\"du-dropzone__headline du-dropzone__headline--drop\">\n <span class=\"du-gradient-text\">Release to drop!</span>\n </p>\n }\n\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Errors \u2500\u2500 -->\n @for (err of sizeErrors; track err) {\n <div class=\"du-msg du-msg--error\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"2\"/>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <circle cx=\"12\" cy=\"17\" r=\"1.2\" fill=\"currentColor\"/>\n </svg>\n {{ err }}\n </div>\n }\n @if (requiredError) {\n <div class=\"du-msg du-msg--error\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"2\"/>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <circle cx=\"12\" cy=\"17\" r=\"1.2\" fill=\"currentColor\"/>\n </svg>\n {{ label || 'File' }} is required!\n </div>\n }\n @if (minFilesError) {\n <div class=\"du-msg du-msg--error\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"2\"/>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <circle cx=\"12\" cy=\"17\" r=\"1.2\" fill=\"currentColor\"/>\n </svg>\n At least {{ minFiles }} files are required ({{ pendingFiles.length }} added).\n </div>\n }\n\n <!-- \u2500\u2500 Pending Files \u2500\u2500 -->\n @if (pendingFiles.length > 0) {\n <div class=\"du-section\">\n <div class=\"du-section__hdr\">\n <span class=\"du-section__title\">Queued Files</span>\n @if (multiple && maxFiles > 0) {\n <span class=\"du-count-label\" [class.du-count-label--full]=\"maxFilesReached\">\n {{ pendingFiles.length }} / {{ maxFiles }}\n </span>\n } @else {\n <span class=\"du-count du-count--purple\">{{ pendingFiles.length }}</span>\n }\n </div>\n <div class=\"du-file-list\">\n @for (file of pendingFiles; track file.name; let i = $index) {\n <div class=\"du-file-card\" [attr.data-ftype]=\"getFileType(file.name)\" [style.animation-delay]=\"i * 40 + 'ms'\">\n\n <div class=\"du-file-icon\">\n @switch (getFileType(file.name)) {\n @case ('pdf') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#FEE2E2\"/>\n <path d=\"M26 4v10h10\" fill=\"#FECACA\"/>\n <rect x=\"4\" y=\"28\" width=\"32\" height=\"12\" rx=\"2\" fill=\"#EF4444\"/>\n <text x=\"20\" y=\"38\" text-anchor=\"middle\" fill=\"white\" font-size=\"7\" font-weight=\"800\" font-family=\"sans-serif\">PDF</text>\n </svg>\n }\n @case ('word') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#DBEAFE\"/>\n <path d=\"M26 4v10h10\" fill=\"#BFDBFE\"/>\n <rect x=\"4\" y=\"28\" width=\"32\" height=\"12\" rx=\"2\" fill=\"#3B82F6\"/>\n <text x=\"20\" y=\"38\" text-anchor=\"middle\" fill=\"white\" font-size=\"7\" font-weight=\"800\" font-family=\"sans-serif\">DOC</text>\n </svg>\n }\n @case ('excel') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#DCFCE7\"/>\n <path d=\"M26 4v10h10\" fill=\"#BBF7D0\"/>\n <rect x=\"4\" y=\"28\" width=\"32\" height=\"12\" rx=\"2\" fill=\"#22C55E\"/>\n <text x=\"20\" y=\"38\" text-anchor=\"middle\" fill=\"white\" font-size=\"7\" font-weight=\"800\" font-family=\"sans-serif\">XLS</text>\n </svg>\n }\n @case ('image') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#FEF9C3\"/>\n <path d=\"M26 4v10h10\" fill=\"#FEF08A\"/>\n <rect x=\"6\" y=\"18\" width=\"28\" height=\"18\" rx=\"2\" fill=\"#FDE047\"/>\n <circle cx=\"13\" cy=\"24\" r=\"3\" fill=\"#CA8A04\"/>\n <path d=\"M6 36l9-9 5 5 4-4 10 8H6Z\" fill=\"#EAB308\" opacity=\"0.8\"/>\n </svg>\n }\n @case ('archive') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#EDE9FE\"/>\n <path d=\"M26 4v10h10\" fill=\"#DDD6FE\"/>\n <rect x=\"14\" y=\"12\" width=\"12\" height=\"4\" rx=\"1\" fill=\"#A78BFA\"/>\n <rect x=\"14\" y=\"18\" width=\"12\" height=\"4\" rx=\"1\" fill=\"#C4B5FD\"/>\n <rect x=\"14\" y=\"24\" width=\"12\" height=\"4\" rx=\"1\" fill=\"#A78BFA\"/>\n <rect x=\"14\" y=\"30\" width=\"12\" height=\"4\" rx=\"1\" fill=\"#C4B5FD\"/>\n <rect x=\"16\" y=\"26\" width=\"8\" height=\"6\" rx=\"1\" fill=\"#7C3AED\"/>\n </svg>\n }\n @default {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#F1F5F9\"/>\n <path d=\"M26 4v10h10\" fill=\"#E2E8F0\"/>\n <line x1=\"10\" y1=\"24\" x2=\"30\" y2=\"24\" stroke=\"#94A3B8\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <line x1=\"10\" y1=\"30\" x2=\"26\" y2=\"30\" stroke=\"#94A3B8\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <line x1=\"10\" y1=\"36\" x2=\"22\" y2=\"36\" stroke=\"#94A3B8\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n }\n }\n </div>\n\n <div class=\"du-file-info\">\n <span class=\"du-file-name\" [title]=\"file.name\">{{ file.name }}</span>\n <span class=\"du-file-size\">{{ getFileSize(file.size) }}</span>\n </div>\n\n <button type=\"button\" class=\"du-remove-btn\" (click)=\"removeFile(i)\" title=\"Remove\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"2\"/>\n <path d=\"M15 9L9 15M9 9l6 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- \u2500\u2500 Upload Button \u2500\u2500 -->\n @if (showUploadButton && pendingFiles.length > 0) {\n <button type=\"button\" class=\"du-upload-btn\" (click)=\"upload()\" [disabled]=\"disabled\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" width=\"17\" height=\"17\">\n <path d=\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\"/>\n <polyline points=\"17,8 12,3 7,8\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\"/>\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\"/>\n </svg>\n {{ uploadButtonLabel }}\n <span class=\"du-upload-btn__badge\">{{ pendingFiles.length }}</span>\n </button>\n }\n\n <!-- \u2500\u2500 Saved Documents \u2500\u2500 -->\n @if (savedDocuments.length > 0) {\n <div class=\"du-section\">\n <div class=\"du-section__hdr\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"du-section__icon\">\n <path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\" stroke=\"#10b981\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <polyline points=\"14,2 14,8 20,8\" stroke=\"#10b981\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n <span class=\"du-section__title\">Saved Documents</span>\n <span class=\"du-count du-count--green\">{{ savedDocuments.length }}</span>\n </div>\n <div class=\"du-saved-list\">\n @for (doc of savedDocuments; track doc.id; let i = $index) {\n <div class=\"du-saved-card\" [style.animation-delay]=\"i * 50 + 'ms'\">\n\n <div class=\"du-saved-icon\">\n @switch (getFileType(doc.name)) {\n @case ('pdf') {\n <svg viewBox=\"0 0 32 38\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 3h16l8 8v24a1.5 1.5 0 01-1.5 1.5H4A1.5 1.5 0 012.5 35V4.5A1.5 1.5 0 014 3z\" fill=\"#FEE2E2\"/>\n <path d=\"M20 3v8h8\" fill=\"#FECACA\"/>\n <rect x=\"2\" y=\"22\" width=\"28\" height=\"10\" rx=\"2\" fill=\"#EF4444\"/>\n <text x=\"16\" y=\"30\" text-anchor=\"middle\" fill=\"white\" font-size=\"6\" font-weight=\"800\" font-family=\"sans-serif\">PDF</text>\n </svg>\n }\n @case ('word') {\n <svg viewBox=\"0 0 32 38\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 3h16l8 8v24a1.5 1.5 0 01-1.5 1.5H4A1.5 1.5 0 012.5 35V4.5A1.5 1.5 0 014 3z\" fill=\"#DBEAFE\"/>\n <path d=\"M20 3v8h8\" fill=\"#BFDBFE\"/>\n <rect x=\"2\" y=\"22\" width=\"28\" height=\"10\" rx=\"2\" fill=\"#3B82F6\"/>\n <text x=\"16\" y=\"30\" text-anchor=\"middle\" fill=\"white\" font-size=\"6\" font-weight=\"800\" font-family=\"sans-serif\">DOC</text>\n </svg>\n }\n @case ('excel') {\n <svg viewBox=\"0 0 32 38\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 3h16l8 8v24a1.5 1.5 0 01-1.5 1.5H4A1.5 1.5 0 012.5 35V4.5A1.5 1.5 0 014 3z\" fill=\"#DCFCE7\"/>\n <path d=\"M20 3v8h8\" fill=\"#BBF7D0\"/>\n <rect x=\"2\" y=\"22\" width=\"28\" height=\"10\" rx=\"2\" fill=\"#22C55E\"/>\n <text x=\"16\" y=\"30\" text-anchor=\"middle\" fill=\"white\" font-size=\"6\" font-weight=\"800\" font-family=\"sans-serif\">XLS</text>\n </svg>\n }\n @case ('image') {\n <svg viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"32\" height=\"32\" rx=\"6\" fill=\"#FEF9C3\"/>\n <rect x=\"4\" y=\"7\" width=\"24\" height=\"18\" rx=\"2\" fill=\"#FDE047\"/>\n <circle cx=\"10\" cy=\"13\" r=\"2.5\" fill=\"#CA8A04\"/>\n <path d=\"M4 25l8-8 5 5 4-4 11 7H4Z\" fill=\"#EAB308\" opacity=\"0.7\"/>\n </svg>\n }\n @case ('archive') {\n <svg viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"32\" height=\"32\" rx=\"6\" fill=\"#EDE9FE\"/>\n <rect x=\"4\" y=\"8\" width=\"24\" height=\"5\" rx=\"1.5\" fill=\"#A78BFA\"/>\n <rect x=\"4\" y=\"14\" width=\"24\" height=\"14\" rx=\"2\" fill=\"#C4B5FD\"/>\n <rect x=\"11\" y=\"18\" width=\"10\" height=\"6\" rx=\"1.5\" fill=\"#7C3AED\"/>\n <line x1=\"16\" y1=\"18\" x2=\"16\" y2=\"24\" stroke=\"white\" stroke-width=\"1.5\"/>\n </svg>\n }\n @default {\n <svg viewBox=\"0 0 32 38\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 3h16l8 8v24a1.5 1.5 0 01-1.5 1.5H4A1.5 1.5 0 012.5 35V4.5A1.5 1.5 0 014 3z\" fill=\"#F1F5F9\"/>\n <path d=\"M20 3v8h8\" fill=\"#E2E8F0\"/>\n <line x1=\"7\" y1=\"20\" x2=\"25\" y2=\"20\" stroke=\"#94A3B8\" stroke-width=\"1.8\" stroke-linecap=\"round\"/>\n <line x1=\"7\" y1=\"25\" x2=\"21\" y2=\"25\" stroke=\"#94A3B8\" stroke-width=\"1.8\" stroke-linecap=\"round\"/>\n <line x1=\"7\" y1=\"30\" x2=\"17\" y2=\"30\" stroke=\"#94A3B8\" stroke-width=\"1.8\" stroke-linecap=\"round\"/>\n </svg>\n }\n }\n </div>\n\n <div class=\"du-saved-info\">\n <span class=\"du-saved-name\" [title]=\"doc.name\">{{ doc.name }}</span>\n @if (doc.addBy || doc.addOn) {\n <span class=\"du-saved-meta\">\n @if (doc.addBy) { <span class=\"du-saved-by\">{{ doc.addBy }}</span> }\n @if (doc.addBy && doc.addOn) { <span class=\"du-saved-sep\">\u00B7</span> }\n @if (doc.addOn) { <span class=\"du-saved-on\">{{ formatDate(doc.addOn) }}</span> }\n </span>\n }\n </div>\n\n <div class=\"du-saved-actions\">\n <button type=\"button\" class=\"du-act du-act--view\" (click)=\"onView(doc)\" title=\"View\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <circle cx=\"12\" cy=\"12\" r=\"3\" stroke=\"currentColor\" stroke-width=\"2\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"du-act du-act--download\" (click)=\"onDownload(doc)\" title=\"Download\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <polyline points=\"7,10 12,15 17,10\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\"/>\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"du-act du-act--delete\" (click)=\"onDelete(doc)\" title=\"Delete\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <polyline points=\"3,6 5,6 21,6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <path d=\"M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <path d=\"M10 11v6M14 11v6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <path d=\"M9 6V4a1 1 0 011-1h4a1 1 0 011 1v2\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n </div>\n\n </div>\n }\n </div>\n </div>\n }\n\n</div>\n", styles: ["@keyframes du-float{0%,to{transform:translateY(0)}50%{transform:translateY(-9px)}}@keyframes du-arrow-bounce{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}@keyframes du-particle{0%,to{transform:translate(0) scale(1);opacity:.25}33%{transform:translate(4px,-14px) scale(1.15);opacity:.5}66%{transform:translate(-4px,-7px) scale(.88);opacity:.2}}@keyframes du-slide-in{0%{opacity:0;transform:translate(18px)}to{opacity:1;transform:translate(0)}}@keyframes du-fade-up{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes du-pop-in{0%{opacity:0;transform:scale(.8)}70%{transform:scale(1.06)}to{opacity:1;transform:scale(1)}}@keyframes du-glow-pulse{0%,to{box-shadow:0 0 #667eea59}50%{box-shadow:0 0 0 8px #667eea00}}@keyframes du-btn-pulse{0%,to{box-shadow:0 4px 20px #667eea66}50%{box-shadow:0 6px 30px #764ba299}}@keyframes du-gradient-shift{0%{background-position:0% 50%}50%{background-position:100% 50%}to{background-position:0% 50%}}@keyframes du-ripple{0%{transform:scale(.6);opacity:.7}to{transform:scale(2.2);opacity:0}}@keyframes du-glint{0%,80%,to{opacity:0;transform:scale(.5)}40%{opacity:.7;transform:scale(1.4)}}.du-container{display:flex;flex-direction:column;gap:10px;width:100%}.du-container.du--disabled{opacity:.55;pointer-events:none}.du-label{display:flex;align-items:center;gap:2px;font-size:var(--osl-label-font-size, 13px);font-weight:500;color:#374151;overflow:hidden}.du-label--error{color:var(--osl-error-color, #ef4444)}.du-label__text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.du-label__req{color:var(--osl-error-color, #ef4444);flex-shrink:0;font-weight:700}.du-file-input{display:none}.du-dropzone{position:relative;width:100%;min-height:158px;border-radius:18px;border:2px dashed rgba(102,126,234,.35);background:linear-gradient(145deg,#fafbff,#f5f3ff);cursor:pointer;overflow:hidden;transition:border-color .3s ease,background .3s ease,box-shadow .3s ease,transform .25s ease}.du-dropzone:hover:not(.du-dropzone--disabled){border-color:#667eeab3;background:linear-gradient(145deg,#f5f3ff,#ede9fe);transform:translateY(-2px);box-shadow:0 10px 30px #667eea1f}.du-dropzone--over{border:2px solid #667eea!important;background:linear-gradient(145deg,#ede9fe,#ddd6fe)!important;transform:scale(1.012) translateY(-3px)!important;box-shadow:0 18px 40px #667eea38,inset 0 0 0 1px #667eea4d!important}.du-dropzone--over .du-cloud-body{stroke:#764ba2}.du-dropzone--over .du-cloud-glint{animation:du-glint .6s ease infinite}.du-dropzone--error{border-color:#ef444480;background:linear-gradient(145deg,#fff5f5,#fee2e2);animation:du-glow-pulse 1.8s ease infinite}.du-dropzone--disabled{cursor:not-allowed;background:#f9fafb!important;border-color:#e5e7eb!important;box-shadow:none!important;transform:none!important}.du-particles{position:absolute;inset:0;pointer-events:none;overflow:hidden}.du-p{position:absolute;border-radius:50%;background:radial-gradient(circle,#667eea38,#764ba21f);animation:du-particle var(--dur, 4s) ease-in-out infinite}.du-p--1{width:22px;height:22px;top:12%;left:6%;--dur: 4.2s;animation-delay:0s}.du-p--2{width:14px;height:14px;top:65%;left:88%;--dur: 5.1s;animation-delay:.9s}.du-p--3{width:18px;height:18px;top:18%;left:82%;--dur: 3.8s;animation-delay:1.6s}.du-p--4{width:10px;height:10px;top:75%;left:12%;--dur: 6.3s;animation-delay:.4s}.du-p--5{width:16px;height:16px;top:50%;left:48%;--dur: 4.7s;animation-delay:2.1s}.du-p--6{width:8px;height:8px;top:30%;left:38%;--dur: 5.5s;animation-delay:1.1s}.du-dropzone__inner{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:26px 20px;min-height:158px}.du-cloud-wrap{width:80px;height:64px;animation:du-float 3.2s ease-in-out infinite;filter:drop-shadow(0 4px 10px rgba(102,126,234,.2));transition:filter .3s ease;flex-shrink:0}.du-cloud-wrap--over{animation-duration:1.2s;filter:drop-shadow(0 6px 18px rgba(102,126,234,.45))}.du-cloud-svg{width:100%;height:100%}.du-cloud-body{transition:stroke .3s ease}.du-cloud-glint{transform-origin:center}.du-arrow{animation:du-arrow-bounce 1.6s ease-in-out infinite}.du-dropzone__headline{margin:0;font-size:14px;color:#6b7280;line-height:1.5;text-align:center}.du-dropzone__headline--drop .du-gradient-text{animation:du-glow-pulse .7s ease infinite}.du-gradient-text{background:linear-gradient(135deg,#667eea,#764ba2);background-size:200% 200%;-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;font-weight:700;animation:du-gradient-shift 3s ease infinite}.du-or{color:#9ca3af;font-size:13px}.du-dropzone__meta{display:flex;flex-wrap:wrap;justify-content:center;gap:6px}.du-chip{border-radius:20px;padding:2px 10px;font-size:11px;font-weight:500;background:#667eea14;color:#7c6fcd;border:1px solid rgba(102,126,234,.18);transition:background .2s}.du-chip--info{background:#10b98114;color:#059669;border-color:#10b98133}.du-msg{display:flex;align-items:center;gap:6px;font-size:var(--osl-hint-font-size, 11px);animation:du-fade-up .2s ease}.du-msg svg{flex-shrink:0}.du-msg--error{color:var(--osl-error-color, #ef4444)}.du-section{display:flex;flex-direction:column;gap:8px;animation:du-fade-up .3s ease}.du-section__hdr{display:flex;align-items:center;gap:7px}.du-section__icon{flex-shrink:0}.du-section__title{font-size:11px;font-weight:700;color:#9ca3af;text-transform:uppercase;letter-spacing:.07em}.du-count{width:19px;height:19px;border-radius:50%;font-size:10px;font-weight:800;color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;animation:du-pop-in .3s ease}.du-count--purple{background:linear-gradient(135deg,#667eea,#764ba2)}.du-count--green{background:linear-gradient(135deg,#10b981,#059669)}.du-file-list{display:flex;flex-direction:column;gap:7px}.du-file-card{display:flex;align-items:center;gap:11px;padding:10px 14px 10px 16px;background:#fff;border-radius:13px;border:1px solid #e9ecf1;animation:du-slide-in .28s ease both;transition:border-color .2s ease,box-shadow .2s ease,transform .2s ease;position:relative}.du-file-card:before{content:\"\";position:absolute;left:0;top:50%;transform:translateY(-50%);width:4px;height:60%;border-radius:0 4px 4px 0;transition:height .2s ease}.du-file-card[data-ftype=pdf]:before{background:#ef4444}.du-file-card[data-ftype=word]:before{background:#3b82f6}.du-file-card[data-ftype=excel]:before{background:#22c55e}.du-file-card[data-ftype=image]:before{background:#f59e0b}.du-file-card[data-ftype=archive]:before{background:#8b5cf6}.du-file-card[data-ftype=generic]:before{background:#94a3b8}.du-file-card:hover{border-color:#c4b5fd;box-shadow:0 3px 14px #667eea1a;transform:translate(3px)}.du-file-card:hover:before{height:75%}.du-file-icon{width:38px;height:46px;flex-shrink:0}.du-file-icon svg{width:100%;height:100%}.du-file-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}.du-file-name{font-size:13px;font-weight:600;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.du-file-size{font-size:11px;color:#94a3b8;font-weight:500}.du-remove-btn{width:30px;height:30px;flex-shrink:0;border-radius:50%;border:1.5px solid #fecaca;background:#fef2f2;color:#fca5a5;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:6px;transition:all .22s ease}.du-remove-btn svg{width:100%;height:100%}.du-remove-btn:hover{background:#fee2e2;border-color:#ef4444;color:#ef4444;transform:rotate(90deg) scale(1.1);box-shadow:0 3px 10px #ef444440}.du-upload-btn{display:flex;align-items:center;justify-content:center;gap:8px;padding:12px 24px;width:100%;border:none;border-radius:13px;background:linear-gradient(135deg,#667eea,#764ba2);background-size:200% 200%;color:#fff;font-size:14px;font-weight:700;letter-spacing:.03em;cursor:pointer;transition:transform .25s ease,box-shadow .25s ease;animation:du-btn-pulse 2.5s ease-in-out infinite,du-gradient-shift 4s ease infinite}.du-upload-btn svg{flex-shrink:0;transition:transform .25s ease}.du-upload-btn:hover:not([disabled]){transform:translateY(-3px);box-shadow:0 10px 28px #667eea80;animation:du-gradient-shift 1.5s ease infinite}.du-upload-btn:hover:not([disabled]) svg{transform:translateY(-3px)}.du-upload-btn:active:not([disabled]){transform:translateY(-1px)}.du-upload-btn[disabled]{opacity:.45;cursor:not-allowed;animation:none}.du-upload-btn__badge{min-width:22px;height:22px;padding:0 6px;border-radius:11px;background:#ffffff38;font-size:11px;font-weight:800;display:flex;align-items:center;justify-content:center;animation:du-pop-in .3s ease}.du-saved-list{display:flex;flex-direction:column;gap:7px}.du-saved-card{display:flex;align-items:center;gap:11px;padding:10px 12px;background:linear-gradient(135deg,#fff,#f8faff);border-radius:13px;border:1px solid #e9ecf1;opacity:0;animation:du-fade-up .32s ease forwards;transition:border-color .2s ease,box-shadow .2s ease,transform .2s ease}.du-saved-card:hover{border-color:#a5b4fc;box-shadow:0 4px 18px #667eea1a;transform:translateY(-1px)}.du-saved-icon{width:32px;height:38px;flex-shrink:0}.du-saved-icon svg{width:100%;height:100%}.du-saved-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}.du-saved-name{font-size:13px;font-weight:600;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.du-saved-size{font-size:11px;color:#94a3b8;font-weight:500}.du-saved-actions{display:flex;align-items:center;gap:5px;flex-shrink:0}.du-act{width:32px;height:32px;border-radius:9px;border:1.5px solid transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:7px;transition:all .22s ease;position:relative;overflow:hidden}.du-act svg{width:100%;height:100%;transition:transform .22s ease}.du-act:after{content:\"\";position:absolute;inset:50%;border-radius:50%;transition:all 0s;pointer-events:none}.du-act:active:after{inset:0;border-radius:9px;background:#ffffff59;animation:du-ripple .4s ease}.du-act--view{background:#eff6ff;color:#3b82f6;border-color:#bfdbfe}.du-act--view:hover{background:#dbeafe;border-color:#93c5fd;box-shadow:0 3px 12px #3b82f64d}.du-act--view:hover svg{transform:scale(1.12)}.du-act--download{background:#f0fdf4;color:#22c55e;border-color:#bbf7d0}.du-act--download:hover{background:#dcfce7;border-color:#86efac;box-shadow:0 3px 12px #22c55e4d}.du-act--download:hover svg{transform:translateY(2px) scale(1.08)}.du-act--delete{background:#fef2f2;color:#ef4444;border-color:#fecaca}.du-act--delete:hover{background:#fee2e2;border-color:#fca5a5;box-shadow:0 3px 12px #ef44444d}.du-act--delete:hover svg{transform:scale(1.1) rotate(-5deg)}.du-dropzone--maxed{cursor:default;border-color:#22c55e66!important;background:linear-gradient(145deg,#f0fdf4,#dcfce7)!important;pointer-events:none}.du-dropzone--maxed .du-particles .du-p{background:radial-gradient(circle,#22c55e2e,#10b9811a)}.du-maxed-icon{width:56px;height:56px;animation:du-pop-in .4s cubic-bezier(.34,1.56,.64,1)}.du-maxed-icon svg{width:100%;height:100%}.du-gradient-text--green{background:linear-gradient(135deg,#22c55e,#059669)!important;background-size:200% 200%!important;-webkit-background-clip:text!important;-webkit-text-fill-color:transparent!important;background-clip:text!important}.du-maxed-sub{margin:0;font-size:12px;color:#6b7280;font-weight:500}.du-count-label{font-size:11px;font-weight:700;padding:2px 9px;border-radius:20px;background:#667eea1a;color:#667eea;border:1px solid rgba(102,126,234,.2);transition:all .25s ease;animation:du-pop-in .3s ease}.du-count-label--full{background:#22c55e1a;color:#16a34a;border-color:#22c55e40}.du-saved-meta{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.du-saved-by{font-size:11px;font-weight:600;color:#667eea}.du-saved-sep{font-size:11px;color:#d1d5db}.du-saved-on{font-size:11px;color:#94a3b8}\n"], dependencies: [{ kind: "directive", type: OslSkeletonDirective, selector: "[oslSkeleton]", inputs: ["oslSkeleton", "oslSkeletonType", "oslSkeletonAnimation", "oslSkeletonTheme", "oslSkeletonColor", "oslSkeletonHighlight", "oslSkeletonRadius", "oslSkeletonRows", "oslSkeletonRowGap", "oslSkeletonZIndex", "oslSkeletonDelay", "oslSkeletonDuration", "oslSkeletonMinHeight", "oslSkeletonForceReread", "oslSkeletonCircleSize", "oslSkeletonListItems", "oslSkeletonTableRows", "oslSkeletonTableCols", "oslSkeletonCardLines", "oslSkeletonBgColor"] }] });
|
|
5530
|
+
}
|
|
5531
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OslDocumentUploader, decorators: [{
|
|
5532
|
+
type: Component,
|
|
5533
|
+
args: [{ selector: 'osl-document-uploader', standalone: false, template: "<div class=\"du-container\" [class.du--disabled]=\"disabled\" [oslSkeleton]=\"skeletonLoading\" [oslSkeletonTheme]=\"skeletonTheme\">\n\n @if (label) {\n <label class=\"du-label\" [class.du-label--error]=\"isInvalid\">\n <span class=\"du-label__text\" [title]=\"label\">{{ label }}</span>\n @if (required) { <span class=\"du-label__req\">*</span> }\n </label>\n }\n\n <input type=\"file\" [accept]=\"accept\" [multiple]=\"multiple\" [disabled]=\"disabled || maxFilesReached\"\n (change)=\"onFileChange($event)\" #fileInput class=\"du-file-input\">\n\n <!-- \u2500\u2500 Drop Zone \u2500\u2500 -->\n <div class=\"du-dropzone\"\n [class.du-dropzone--over]=\"isDragOver\"\n [class.du-dropzone--error]=\"isInvalid\"\n [class.du-dropzone--disabled]=\"disabled\"\n [class.du-dropzone--maxed]=\"maxFilesReached\"\n (click)=\"triggerInput(fileInput)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n\n <div class=\"du-particles\">\n <span class=\"du-p du-p--1\"></span>\n <span class=\"du-p du-p--2\"></span>\n <span class=\"du-p du-p--3\"></span>\n <span class=\"du-p du-p--4\"></span>\n <span class=\"du-p du-p--5\"></span>\n <span class=\"du-p du-p--6\"></span>\n </div>\n\n <div class=\"du-dropzone__inner\">\n\n @if (maxFilesReached) {\n <!-- Max files reached state -->\n <div class=\"du-maxed-icon\">\n <svg viewBox=\"0 0 64 64\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"#f0fdf4\" stroke=\"#86efac\" stroke-width=\"2\"/>\n <path d=\"M20 32l8 8 16-16\" stroke=\"#22c55e\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n <p class=\"du-dropzone__headline\">\n <span class=\"du-gradient-text du-gradient-text--green\">Limit reached</span>\n </p>\n <p class=\"du-maxed-sub\">{{ maxFiles }} / {{ maxFiles }} files added</p>\n } @else {\n\n <!-- Cloud SVG -->\n <div class=\"du-cloud-wrap\" [class.du-cloud-wrap--over]=\"isDragOver\">\n <svg class=\"du-cloud-svg\" viewBox=\"0 0 90 72\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path class=\"du-cloud-body\"\n d=\"M63 42H27C19.8 42 14 36.2 14 29C14 22.2 19.2 16.7 25.8 16.1C25.9 9.4 31.3 4 38 4C42.8 4 47 6.7 49.2 10.7C50.8 9.6 52.8 9 55 9C61 9 65.9 13.9 65.9 19.9V20.1C72.1 20.9 77 26.3 77 33C77 38.1 70.7 42 63 42Z\"\n stroke=\"#667eea\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <line class=\"du-arrow\" x1=\"45\" y1=\"64\" x2=\"45\" y2=\"46\" stroke=\"#764ba2\" stroke-width=\"2.5\" stroke-linecap=\"round\"/>\n <polyline class=\"du-arrow\" points=\"37,55 45,46 53,55\"\n stroke=\"#764ba2\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\"/>\n <circle class=\"du-cloud-glint\" cx=\"30\" cy=\"26\" r=\"3\" fill=\"#a5b4fc\" opacity=\"0.5\"/>\n </svg>\n </div>\n\n @if (!isDragOver) {\n <p class=\"du-dropzone__headline\">\n <span class=\"du-gradient-text\">Click to browse</span><span class=\"du-or\"> or drag & drop</span>\n </p>\n <div class=\"du-dropzone__meta\">\n @if (multiple) {\n @if (maxFiles > 0 && minFiles > 0) {\n <span class=\"du-chip du-chip--info\">{{ minFiles }}\u2013{{ maxFiles }} files</span>\n } @else if (maxFiles > 0) {\n <span class=\"du-chip du-chip--info\">Max {{ maxFiles }} files</span>\n } @else if (minFiles > 0) {\n <span class=\"du-chip du-chip--info\">Min {{ minFiles }} files</span>\n } @else {\n <span class=\"du-chip du-chip--info\">Multiple files</span>\n }\n } @else {\n <span class=\"du-chip du-chip--info\">Single file</span>\n }\n @if (accept) { <span class=\"du-chip\">{{ accept }}</span> }\n @if (maxSize) { <span class=\"du-chip\">{{ maxSizeLabel }}</span> }\n </div>\n } @else {\n <p class=\"du-dropzone__headline du-dropzone__headline--drop\">\n <span class=\"du-gradient-text\">Release to drop!</span>\n </p>\n }\n\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Errors \u2500\u2500 -->\n @for (err of sizeErrors; track err) {\n <div class=\"du-msg du-msg--error\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"2\"/>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <circle cx=\"12\" cy=\"17\" r=\"1.2\" fill=\"currentColor\"/>\n </svg>\n {{ err }}\n </div>\n }\n @if (requiredError) {\n <div class=\"du-msg du-msg--error\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"2\"/>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <circle cx=\"12\" cy=\"17\" r=\"1.2\" fill=\"currentColor\"/>\n </svg>\n {{ label || 'File' }} is required!\n </div>\n }\n @if (minFilesError) {\n <div class=\"du-msg du-msg--error\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"2\"/>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <circle cx=\"12\" cy=\"17\" r=\"1.2\" fill=\"currentColor\"/>\n </svg>\n At least {{ minFiles }} files are required ({{ pendingFiles.length }} added).\n </div>\n }\n\n <!-- \u2500\u2500 Pending Files \u2500\u2500 -->\n @if (pendingFiles.length > 0) {\n <div class=\"du-section\">\n <div class=\"du-section__hdr\">\n <span class=\"du-section__title\">Queued Files</span>\n @if (multiple && maxFiles > 0) {\n <span class=\"du-count-label\" [class.du-count-label--full]=\"maxFilesReached\">\n {{ pendingFiles.length }} / {{ maxFiles }}\n </span>\n } @else {\n <span class=\"du-count du-count--purple\">{{ pendingFiles.length }}</span>\n }\n </div>\n <div class=\"du-file-list\">\n @for (file of pendingFiles; track file.name; let i = $index) {\n <div class=\"du-file-card\" [attr.data-ftype]=\"getFileType(file.name)\" [style.animation-delay]=\"i * 40 + 'ms'\">\n\n <div class=\"du-file-icon\">\n @switch (getFileType(file.name)) {\n @case ('pdf') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#FEE2E2\"/>\n <path d=\"M26 4v10h10\" fill=\"#FECACA\"/>\n <rect x=\"4\" y=\"28\" width=\"32\" height=\"12\" rx=\"2\" fill=\"#EF4444\"/>\n <text x=\"20\" y=\"38\" text-anchor=\"middle\" fill=\"white\" font-size=\"7\" font-weight=\"800\" font-family=\"sans-serif\">PDF</text>\n </svg>\n }\n @case ('word') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#DBEAFE\"/>\n <path d=\"M26 4v10h10\" fill=\"#BFDBFE\"/>\n <rect x=\"4\" y=\"28\" width=\"32\" height=\"12\" rx=\"2\" fill=\"#3B82F6\"/>\n <text x=\"20\" y=\"38\" text-anchor=\"middle\" fill=\"white\" font-size=\"7\" font-weight=\"800\" font-family=\"sans-serif\">DOC</text>\n </svg>\n }\n @case ('excel') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#DCFCE7\"/>\n <path d=\"M26 4v10h10\" fill=\"#BBF7D0\"/>\n <rect x=\"4\" y=\"28\" width=\"32\" height=\"12\" rx=\"2\" fill=\"#22C55E\"/>\n <text x=\"20\" y=\"38\" text-anchor=\"middle\" fill=\"white\" font-size=\"7\" font-weight=\"800\" font-family=\"sans-serif\">XLS</text>\n </svg>\n }\n @case ('image') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#FEF9C3\"/>\n <path d=\"M26 4v10h10\" fill=\"#FEF08A\"/>\n <rect x=\"6\" y=\"18\" width=\"28\" height=\"18\" rx=\"2\" fill=\"#FDE047\"/>\n <circle cx=\"13\" cy=\"24\" r=\"3\" fill=\"#CA8A04\"/>\n <path d=\"M6 36l9-9 5 5 4-4 10 8H6Z\" fill=\"#EAB308\" opacity=\"0.8\"/>\n </svg>\n }\n @case ('archive') {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#EDE9FE\"/>\n <path d=\"M26 4v10h10\" fill=\"#DDD6FE\"/>\n <rect x=\"14\" y=\"12\" width=\"12\" height=\"4\" rx=\"1\" fill=\"#A78BFA\"/>\n <rect x=\"14\" y=\"18\" width=\"12\" height=\"4\" rx=\"1\" fill=\"#C4B5FD\"/>\n <rect x=\"14\" y=\"24\" width=\"12\" height=\"4\" rx=\"1\" fill=\"#A78BFA\"/>\n <rect x=\"14\" y=\"30\" width=\"12\" height=\"4\" rx=\"1\" fill=\"#C4B5FD\"/>\n <rect x=\"16\" y=\"26\" width=\"8\" height=\"6\" rx=\"1\" fill=\"#7C3AED\"/>\n </svg>\n }\n @default {\n <svg viewBox=\"0 0 40 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 4h20l10 10v30a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2z\" fill=\"#F1F5F9\"/>\n <path d=\"M26 4v10h10\" fill=\"#E2E8F0\"/>\n <line x1=\"10\" y1=\"24\" x2=\"30\" y2=\"24\" stroke=\"#94A3B8\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <line x1=\"10\" y1=\"30\" x2=\"26\" y2=\"30\" stroke=\"#94A3B8\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <line x1=\"10\" y1=\"36\" x2=\"22\" y2=\"36\" stroke=\"#94A3B8\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n }\n }\n </div>\n\n <div class=\"du-file-info\">\n <span class=\"du-file-name\" [title]=\"file.name\">{{ file.name }}</span>\n <span class=\"du-file-size\">{{ getFileSize(file.size) }}</span>\n </div>\n\n <button type=\"button\" class=\"du-remove-btn\" (click)=\"removeFile(i)\" title=\"Remove\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"2\"/>\n <path d=\"M15 9L9 15M9 9l6 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- \u2500\u2500 Upload Button \u2500\u2500 -->\n @if (showUploadButton && pendingFiles.length > 0) {\n <button type=\"button\" class=\"du-upload-btn\" (click)=\"upload()\" [disabled]=\"disabled\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" width=\"17\" height=\"17\">\n <path d=\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\"/>\n <polyline points=\"17,8 12,3 7,8\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\"/>\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\"/>\n </svg>\n {{ uploadButtonLabel }}\n <span class=\"du-upload-btn__badge\">{{ pendingFiles.length }}</span>\n </button>\n }\n\n <!-- \u2500\u2500 Saved Documents \u2500\u2500 -->\n @if (savedDocuments.length > 0) {\n <div class=\"du-section\">\n <div class=\"du-section__hdr\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"du-section__icon\">\n <path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\" stroke=\"#10b981\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <polyline points=\"14,2 14,8 20,8\" stroke=\"#10b981\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n <span class=\"du-section__title\">Saved Documents</span>\n <span class=\"du-count du-count--green\">{{ savedDocuments.length }}</span>\n </div>\n <div class=\"du-saved-list\">\n @for (doc of savedDocuments; track doc.id; let i = $index) {\n <div class=\"du-saved-card\" [style.animation-delay]=\"i * 50 + 'ms'\">\n\n <div class=\"du-saved-icon\">\n @switch (getFileType(doc.name)) {\n @case ('pdf') {\n <svg viewBox=\"0 0 32 38\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 3h16l8 8v24a1.5 1.5 0 01-1.5 1.5H4A1.5 1.5 0 012.5 35V4.5A1.5 1.5 0 014 3z\" fill=\"#FEE2E2\"/>\n <path d=\"M20 3v8h8\" fill=\"#FECACA\"/>\n <rect x=\"2\" y=\"22\" width=\"28\" height=\"10\" rx=\"2\" fill=\"#EF4444\"/>\n <text x=\"16\" y=\"30\" text-anchor=\"middle\" fill=\"white\" font-size=\"6\" font-weight=\"800\" font-family=\"sans-serif\">PDF</text>\n </svg>\n }\n @case ('word') {\n <svg viewBox=\"0 0 32 38\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 3h16l8 8v24a1.5 1.5 0 01-1.5 1.5H4A1.5 1.5 0 012.5 35V4.5A1.5 1.5 0 014 3z\" fill=\"#DBEAFE\"/>\n <path d=\"M20 3v8h8\" fill=\"#BFDBFE\"/>\n <rect x=\"2\" y=\"22\" width=\"28\" height=\"10\" rx=\"2\" fill=\"#3B82F6\"/>\n <text x=\"16\" y=\"30\" text-anchor=\"middle\" fill=\"white\" font-size=\"6\" font-weight=\"800\" font-family=\"sans-serif\">DOC</text>\n </svg>\n }\n @case ('excel') {\n <svg viewBox=\"0 0 32 38\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 3h16l8 8v24a1.5 1.5 0 01-1.5 1.5H4A1.5 1.5 0 012.5 35V4.5A1.5 1.5 0 014 3z\" fill=\"#DCFCE7\"/>\n <path d=\"M20 3v8h8\" fill=\"#BBF7D0\"/>\n <rect x=\"2\" y=\"22\" width=\"28\" height=\"10\" rx=\"2\" fill=\"#22C55E\"/>\n <text x=\"16\" y=\"30\" text-anchor=\"middle\" fill=\"white\" font-size=\"6\" font-weight=\"800\" font-family=\"sans-serif\">XLS</text>\n </svg>\n }\n @case ('image') {\n <svg viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"32\" height=\"32\" rx=\"6\" fill=\"#FEF9C3\"/>\n <rect x=\"4\" y=\"7\" width=\"24\" height=\"18\" rx=\"2\" fill=\"#FDE047\"/>\n <circle cx=\"10\" cy=\"13\" r=\"2.5\" fill=\"#CA8A04\"/>\n <path d=\"M4 25l8-8 5 5 4-4 11 7H4Z\" fill=\"#EAB308\" opacity=\"0.7\"/>\n </svg>\n }\n @case ('archive') {\n <svg viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"32\" height=\"32\" rx=\"6\" fill=\"#EDE9FE\"/>\n <rect x=\"4\" y=\"8\" width=\"24\" height=\"5\" rx=\"1.5\" fill=\"#A78BFA\"/>\n <rect x=\"4\" y=\"14\" width=\"24\" height=\"14\" rx=\"2\" fill=\"#C4B5FD\"/>\n <rect x=\"11\" y=\"18\" width=\"10\" height=\"6\" rx=\"1.5\" fill=\"#7C3AED\"/>\n <line x1=\"16\" y1=\"18\" x2=\"16\" y2=\"24\" stroke=\"white\" stroke-width=\"1.5\"/>\n </svg>\n }\n @default {\n <svg viewBox=\"0 0 32 38\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 3h16l8 8v24a1.5 1.5 0 01-1.5 1.5H4A1.5 1.5 0 012.5 35V4.5A1.5 1.5 0 014 3z\" fill=\"#F1F5F9\"/>\n <path d=\"M20 3v8h8\" fill=\"#E2E8F0\"/>\n <line x1=\"7\" y1=\"20\" x2=\"25\" y2=\"20\" stroke=\"#94A3B8\" stroke-width=\"1.8\" stroke-linecap=\"round\"/>\n <line x1=\"7\" y1=\"25\" x2=\"21\" y2=\"25\" stroke=\"#94A3B8\" stroke-width=\"1.8\" stroke-linecap=\"round\"/>\n <line x1=\"7\" y1=\"30\" x2=\"17\" y2=\"30\" stroke=\"#94A3B8\" stroke-width=\"1.8\" stroke-linecap=\"round\"/>\n </svg>\n }\n }\n </div>\n\n <div class=\"du-saved-info\">\n <span class=\"du-saved-name\" [title]=\"doc.name\">{{ doc.name }}</span>\n @if (doc.addBy || doc.addOn) {\n <span class=\"du-saved-meta\">\n @if (doc.addBy) { <span class=\"du-saved-by\">{{ doc.addBy }}</span> }\n @if (doc.addBy && doc.addOn) { <span class=\"du-saved-sep\">\u00B7</span> }\n @if (doc.addOn) { <span class=\"du-saved-on\">{{ formatDate(doc.addOn) }}</span> }\n </span>\n }\n </div>\n\n <div class=\"du-saved-actions\">\n <button type=\"button\" class=\"du-act du-act--view\" (click)=\"onView(doc)\" title=\"View\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <circle cx=\"12\" cy=\"12\" r=\"3\" stroke=\"currentColor\" stroke-width=\"2\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"du-act du-act--download\" (click)=\"onDownload(doc)\" title=\"Download\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <polyline points=\"7,10 12,15 17,10\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\"/>\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"du-act du-act--delete\" (click)=\"onDelete(doc)\" title=\"Delete\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <polyline points=\"3,6 5,6 21,6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <path d=\"M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <path d=\"M10 11v6M14 11v6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <path d=\"M9 6V4a1 1 0 011-1h4a1 1 0 011 1v2\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n </div>\n\n </div>\n }\n </div>\n </div>\n }\n\n</div>\n", styles: ["@keyframes du-float{0%,to{transform:translateY(0)}50%{transform:translateY(-9px)}}@keyframes du-arrow-bounce{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}@keyframes du-particle{0%,to{transform:translate(0) scale(1);opacity:.25}33%{transform:translate(4px,-14px) scale(1.15);opacity:.5}66%{transform:translate(-4px,-7px) scale(.88);opacity:.2}}@keyframes du-slide-in{0%{opacity:0;transform:translate(18px)}to{opacity:1;transform:translate(0)}}@keyframes du-fade-up{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes du-pop-in{0%{opacity:0;transform:scale(.8)}70%{transform:scale(1.06)}to{opacity:1;transform:scale(1)}}@keyframes du-glow-pulse{0%,to{box-shadow:0 0 #667eea59}50%{box-shadow:0 0 0 8px #667eea00}}@keyframes du-btn-pulse{0%,to{box-shadow:0 4px 20px #667eea66}50%{box-shadow:0 6px 30px #764ba299}}@keyframes du-gradient-shift{0%{background-position:0% 50%}50%{background-position:100% 50%}to{background-position:0% 50%}}@keyframes du-ripple{0%{transform:scale(.6);opacity:.7}to{transform:scale(2.2);opacity:0}}@keyframes du-glint{0%,80%,to{opacity:0;transform:scale(.5)}40%{opacity:.7;transform:scale(1.4)}}.du-container{display:flex;flex-direction:column;gap:10px;width:100%}.du-container.du--disabled{opacity:.55;pointer-events:none}.du-label{display:flex;align-items:center;gap:2px;font-size:var(--osl-label-font-size, 13px);font-weight:500;color:#374151;overflow:hidden}.du-label--error{color:var(--osl-error-color, #ef4444)}.du-label__text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.du-label__req{color:var(--osl-error-color, #ef4444);flex-shrink:0;font-weight:700}.du-file-input{display:none}.du-dropzone{position:relative;width:100%;min-height:158px;border-radius:18px;border:2px dashed rgba(102,126,234,.35);background:linear-gradient(145deg,#fafbff,#f5f3ff);cursor:pointer;overflow:hidden;transition:border-color .3s ease,background .3s ease,box-shadow .3s ease,transform .25s ease}.du-dropzone:hover:not(.du-dropzone--disabled){border-color:#667eeab3;background:linear-gradient(145deg,#f5f3ff,#ede9fe);transform:translateY(-2px);box-shadow:0 10px 30px #667eea1f}.du-dropzone--over{border:2px solid #667eea!important;background:linear-gradient(145deg,#ede9fe,#ddd6fe)!important;transform:scale(1.012) translateY(-3px)!important;box-shadow:0 18px 40px #667eea38,inset 0 0 0 1px #667eea4d!important}.du-dropzone--over .du-cloud-body{stroke:#764ba2}.du-dropzone--over .du-cloud-glint{animation:du-glint .6s ease infinite}.du-dropzone--error{border-color:#ef444480;background:linear-gradient(145deg,#fff5f5,#fee2e2);animation:du-glow-pulse 1.8s ease infinite}.du-dropzone--disabled{cursor:not-allowed;background:#f9fafb!important;border-color:#e5e7eb!important;box-shadow:none!important;transform:none!important}.du-particles{position:absolute;inset:0;pointer-events:none;overflow:hidden}.du-p{position:absolute;border-radius:50%;background:radial-gradient(circle,#667eea38,#764ba21f);animation:du-particle var(--dur, 4s) ease-in-out infinite}.du-p--1{width:22px;height:22px;top:12%;left:6%;--dur: 4.2s;animation-delay:0s}.du-p--2{width:14px;height:14px;top:65%;left:88%;--dur: 5.1s;animation-delay:.9s}.du-p--3{width:18px;height:18px;top:18%;left:82%;--dur: 3.8s;animation-delay:1.6s}.du-p--4{width:10px;height:10px;top:75%;left:12%;--dur: 6.3s;animation-delay:.4s}.du-p--5{width:16px;height:16px;top:50%;left:48%;--dur: 4.7s;animation-delay:2.1s}.du-p--6{width:8px;height:8px;top:30%;left:38%;--dur: 5.5s;animation-delay:1.1s}.du-dropzone__inner{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:26px 20px;min-height:158px}.du-cloud-wrap{width:80px;height:64px;animation:du-float 3.2s ease-in-out infinite;filter:drop-shadow(0 4px 10px rgba(102,126,234,.2));transition:filter .3s ease;flex-shrink:0}.du-cloud-wrap--over{animation-duration:1.2s;filter:drop-shadow(0 6px 18px rgba(102,126,234,.45))}.du-cloud-svg{width:100%;height:100%}.du-cloud-body{transition:stroke .3s ease}.du-cloud-glint{transform-origin:center}.du-arrow{animation:du-arrow-bounce 1.6s ease-in-out infinite}.du-dropzone__headline{margin:0;font-size:14px;color:#6b7280;line-height:1.5;text-align:center}.du-dropzone__headline--drop .du-gradient-text{animation:du-glow-pulse .7s ease infinite}.du-gradient-text{background:linear-gradient(135deg,#667eea,#764ba2);background-size:200% 200%;-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;font-weight:700;animation:du-gradient-shift 3s ease infinite}.du-or{color:#9ca3af;font-size:13px}.du-dropzone__meta{display:flex;flex-wrap:wrap;justify-content:center;gap:6px}.du-chip{border-radius:20px;padding:2px 10px;font-size:11px;font-weight:500;background:#667eea14;color:#7c6fcd;border:1px solid rgba(102,126,234,.18);transition:background .2s}.du-chip--info{background:#10b98114;color:#059669;border-color:#10b98133}.du-msg{display:flex;align-items:center;gap:6px;font-size:var(--osl-hint-font-size, 11px);animation:du-fade-up .2s ease}.du-msg svg{flex-shrink:0}.du-msg--error{color:var(--osl-error-color, #ef4444)}.du-section{display:flex;flex-direction:column;gap:8px;animation:du-fade-up .3s ease}.du-section__hdr{display:flex;align-items:center;gap:7px}.du-section__icon{flex-shrink:0}.du-section__title{font-size:11px;font-weight:700;color:#9ca3af;text-transform:uppercase;letter-spacing:.07em}.du-count{width:19px;height:19px;border-radius:50%;font-size:10px;font-weight:800;color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;animation:du-pop-in .3s ease}.du-count--purple{background:linear-gradient(135deg,#667eea,#764ba2)}.du-count--green{background:linear-gradient(135deg,#10b981,#059669)}.du-file-list{display:flex;flex-direction:column;gap:7px}.du-file-card{display:flex;align-items:center;gap:11px;padding:10px 14px 10px 16px;background:#fff;border-radius:13px;border:1px solid #e9ecf1;animation:du-slide-in .28s ease both;transition:border-color .2s ease,box-shadow .2s ease,transform .2s ease;position:relative}.du-file-card:before{content:\"\";position:absolute;left:0;top:50%;transform:translateY(-50%);width:4px;height:60%;border-radius:0 4px 4px 0;transition:height .2s ease}.du-file-card[data-ftype=pdf]:before{background:#ef4444}.du-file-card[data-ftype=word]:before{background:#3b82f6}.du-file-card[data-ftype=excel]:before{background:#22c55e}.du-file-card[data-ftype=image]:before{background:#f59e0b}.du-file-card[data-ftype=archive]:before{background:#8b5cf6}.du-file-card[data-ftype=generic]:before{background:#94a3b8}.du-file-card:hover{border-color:#c4b5fd;box-shadow:0 3px 14px #667eea1a;transform:translate(3px)}.du-file-card:hover:before{height:75%}.du-file-icon{width:38px;height:46px;flex-shrink:0}.du-file-icon svg{width:100%;height:100%}.du-file-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}.du-file-name{font-size:13px;font-weight:600;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.du-file-size{font-size:11px;color:#94a3b8;font-weight:500}.du-remove-btn{width:30px;height:30px;flex-shrink:0;border-radius:50%;border:1.5px solid #fecaca;background:#fef2f2;color:#fca5a5;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:6px;transition:all .22s ease}.du-remove-btn svg{width:100%;height:100%}.du-remove-btn:hover{background:#fee2e2;border-color:#ef4444;color:#ef4444;transform:rotate(90deg) scale(1.1);box-shadow:0 3px 10px #ef444440}.du-upload-btn{display:flex;align-items:center;justify-content:center;gap:8px;padding:12px 24px;width:100%;border:none;border-radius:13px;background:linear-gradient(135deg,#667eea,#764ba2);background-size:200% 200%;color:#fff;font-size:14px;font-weight:700;letter-spacing:.03em;cursor:pointer;transition:transform .25s ease,box-shadow .25s ease;animation:du-btn-pulse 2.5s ease-in-out infinite,du-gradient-shift 4s ease infinite}.du-upload-btn svg{flex-shrink:0;transition:transform .25s ease}.du-upload-btn:hover:not([disabled]){transform:translateY(-3px);box-shadow:0 10px 28px #667eea80;animation:du-gradient-shift 1.5s ease infinite}.du-upload-btn:hover:not([disabled]) svg{transform:translateY(-3px)}.du-upload-btn:active:not([disabled]){transform:translateY(-1px)}.du-upload-btn[disabled]{opacity:.45;cursor:not-allowed;animation:none}.du-upload-btn__badge{min-width:22px;height:22px;padding:0 6px;border-radius:11px;background:#ffffff38;font-size:11px;font-weight:800;display:flex;align-items:center;justify-content:center;animation:du-pop-in .3s ease}.du-saved-list{display:flex;flex-direction:column;gap:7px}.du-saved-card{display:flex;align-items:center;gap:11px;padding:10px 12px;background:linear-gradient(135deg,#fff,#f8faff);border-radius:13px;border:1px solid #e9ecf1;opacity:0;animation:du-fade-up .32s ease forwards;transition:border-color .2s ease,box-shadow .2s ease,transform .2s ease}.du-saved-card:hover{border-color:#a5b4fc;box-shadow:0 4px 18px #667eea1a;transform:translateY(-1px)}.du-saved-icon{width:32px;height:38px;flex-shrink:0}.du-saved-icon svg{width:100%;height:100%}.du-saved-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}.du-saved-name{font-size:13px;font-weight:600;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.du-saved-size{font-size:11px;color:#94a3b8;font-weight:500}.du-saved-actions{display:flex;align-items:center;gap:5px;flex-shrink:0}.du-act{width:32px;height:32px;border-radius:9px;border:1.5px solid transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:7px;transition:all .22s ease;position:relative;overflow:hidden}.du-act svg{width:100%;height:100%;transition:transform .22s ease}.du-act:after{content:\"\";position:absolute;inset:50%;border-radius:50%;transition:all 0s;pointer-events:none}.du-act:active:after{inset:0;border-radius:9px;background:#ffffff59;animation:du-ripple .4s ease}.du-act--view{background:#eff6ff;color:#3b82f6;border-color:#bfdbfe}.du-act--view:hover{background:#dbeafe;border-color:#93c5fd;box-shadow:0 3px 12px #3b82f64d}.du-act--view:hover svg{transform:scale(1.12)}.du-act--download{background:#f0fdf4;color:#22c55e;border-color:#bbf7d0}.du-act--download:hover{background:#dcfce7;border-color:#86efac;box-shadow:0 3px 12px #22c55e4d}.du-act--download:hover svg{transform:translateY(2px) scale(1.08)}.du-act--delete{background:#fef2f2;color:#ef4444;border-color:#fecaca}.du-act--delete:hover{background:#fee2e2;border-color:#fca5a5;box-shadow:0 3px 12px #ef44444d}.du-act--delete:hover svg{transform:scale(1.1) rotate(-5deg)}.du-dropzone--maxed{cursor:default;border-color:#22c55e66!important;background:linear-gradient(145deg,#f0fdf4,#dcfce7)!important;pointer-events:none}.du-dropzone--maxed .du-particles .du-p{background:radial-gradient(circle,#22c55e2e,#10b9811a)}.du-maxed-icon{width:56px;height:56px;animation:du-pop-in .4s cubic-bezier(.34,1.56,.64,1)}.du-maxed-icon svg{width:100%;height:100%}.du-gradient-text--green{background:linear-gradient(135deg,#22c55e,#059669)!important;background-size:200% 200%!important;-webkit-background-clip:text!important;-webkit-text-fill-color:transparent!important;background-clip:text!important}.du-maxed-sub{margin:0;font-size:12px;color:#6b7280;font-weight:500}.du-count-label{font-size:11px;font-weight:700;padding:2px 9px;border-radius:20px;background:#667eea1a;color:#667eea;border:1px solid rgba(102,126,234,.2);transition:all .25s ease;animation:du-pop-in .3s ease}.du-count-label--full{background:#22c55e1a;color:#16a34a;border-color:#22c55e40}.du-saved-meta{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.du-saved-by{font-size:11px;font-weight:600;color:#667eea}.du-saved-sep{font-size:11px;color:#d1d5db}.du-saved-on{font-size:11px;color:#94a3b8}\n"] }]
|
|
5534
|
+
}], propDecorators: { label: [{
|
|
5535
|
+
type: Input,
|
|
5536
|
+
args: ['label']
|
|
5537
|
+
}], required: [{
|
|
5538
|
+
type: Input,
|
|
5539
|
+
args: ['required']
|
|
5540
|
+
}], disabled: [{
|
|
5541
|
+
type: Input,
|
|
5542
|
+
args: ['disabled']
|
|
5543
|
+
}], multiple: [{
|
|
5544
|
+
type: Input,
|
|
5545
|
+
args: ['multiple']
|
|
5546
|
+
}], accept: [{
|
|
5547
|
+
type: Input,
|
|
5548
|
+
args: ['accept']
|
|
5549
|
+
}], maxSize: [{
|
|
5550
|
+
type: Input,
|
|
5551
|
+
args: ['maxSize']
|
|
5552
|
+
}], minFiles: [{
|
|
5553
|
+
type: Input,
|
|
5554
|
+
args: ['minFiles']
|
|
5555
|
+
}], maxFiles: [{
|
|
5556
|
+
type: Input,
|
|
5557
|
+
args: ['maxFiles']
|
|
5558
|
+
}], showUploadButton: [{
|
|
5559
|
+
type: Input,
|
|
5560
|
+
args: ['showUploadButton']
|
|
5561
|
+
}], uploadButtonLabel: [{
|
|
5562
|
+
type: Input,
|
|
5563
|
+
args: ['uploadButtonLabel']
|
|
5564
|
+
}], savedDocuments: [{
|
|
5565
|
+
type: Input,
|
|
5566
|
+
args: ['savedDocuments']
|
|
5567
|
+
}], skeletonLoading: [{
|
|
5568
|
+
type: Input,
|
|
5569
|
+
args: ['skeletonLoading']
|
|
5570
|
+
}], skeletonTheme: [{
|
|
5571
|
+
type: Input,
|
|
5572
|
+
args: ['skeletonTheme']
|
|
5573
|
+
}], uploadCallback: [{
|
|
5574
|
+
type: Output
|
|
5575
|
+
}], viewCallback: [{
|
|
5576
|
+
type: Output
|
|
5577
|
+
}], deleteCallback: [{
|
|
5578
|
+
type: Output
|
|
5579
|
+
}], downloadCallback: [{
|
|
5580
|
+
type: Output
|
|
5581
|
+
}], filesChanged: [{
|
|
5582
|
+
type: Output
|
|
5583
|
+
}] } });
|
|
5584
|
+
|
|
5374
5585
|
class FormStructureModule {
|
|
5375
5586
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FormStructureModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
5376
5587
|
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: FormStructureModule, declarations: [DynamicForm,
|
|
@@ -5394,7 +5605,8 @@ class FormStructureModule {
|
|
|
5394
5605
|
OslReportForm,
|
|
5395
5606
|
OslUserLog,
|
|
5396
5607
|
OslMenu,
|
|
5397
|
-
OslMenuTriggerFor
|
|
5608
|
+
OslMenuTriggerFor,
|
|
5609
|
+
OslDocumentUploader], imports: [NgTemplateOutlet,
|
|
5398
5610
|
NgStyle,
|
|
5399
5611
|
NgClass,
|
|
5400
5612
|
DatePipe,
|
|
@@ -5430,7 +5642,7 @@ class FormStructureModule {
|
|
|
5430
5642
|
OslButton,
|
|
5431
5643
|
OslSetup,
|
|
5432
5644
|
OslSearchbar, OslAutocompleteLister, OslReportGrid, OslReportForm,
|
|
5433
|
-
OslMenu, OslMenuTriggerFor] });
|
|
5645
|
+
OslMenu, OslMenuTriggerFor, OslDocumentUploader] });
|
|
5434
5646
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FormStructureModule, providers: [
|
|
5435
5647
|
{ provide: AUTOCOMPLETE_LISTER_COMPONENT, useValue: OslAutocompleteLister },
|
|
5436
5648
|
], imports: [FormsModule,
|
|
@@ -5476,6 +5688,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
5476
5688
|
OslUserLog,
|
|
5477
5689
|
OslMenu,
|
|
5478
5690
|
OslMenuTriggerFor,
|
|
5691
|
+
OslDocumentUploader,
|
|
5479
5692
|
],
|
|
5480
5693
|
imports: [
|
|
5481
5694
|
NgTemplateOutlet,
|
|
@@ -5516,7 +5729,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
5516
5729
|
OslButton,
|
|
5517
5730
|
OslSetup,
|
|
5518
5731
|
OslSearchbar, OslAutocompleteLister, OslReportGrid, OslReportForm,
|
|
5519
|
-
OslMenu, OslMenuTriggerFor],
|
|
5732
|
+
OslMenu, OslMenuTriggerFor, OslDocumentUploader],
|
|
5520
5733
|
providers: [
|
|
5521
5734
|
{ provide: AUTOCOMPLETE_LISTER_COMPONENT, useValue: OslAutocompleteLister },
|
|
5522
5735
|
],
|
|
@@ -6781,5 +6994,5 @@ var validation_util = /*#__PURE__*/Object.freeze({
|
|
|
6781
6994
|
* Generated bundle index. Do not edit.
|
|
6782
6995
|
*/
|
|
6783
6996
|
|
|
6784
|
-
export { array_util as ArrayUtil, date_util as DateUtil, DeleteConfirmation, DeleteConfirmationData, Dialog, DialogWrapper, DynamicForm, FormStructureModule, Httpbase, number_util as NumberUtil, object_util as ObjectUtil, OslAutocomplete, OslAutocompleteLister, OslBaseExtended, OslButton, OslCheckbox, OslDatepicker, OslDatetimepicker, OslFileUpload, OslFormGrid, OslGrid, OslMenu, OslMenuTriggerFor, OslRadio, OslReportForm, OslReportGrid, OslSearchbar, OslSelect, OslSetup, OslSkeletonDirective, OslSkeletonModule, OslSkeletonThemeService, OslSlideToggle, OslUserLog, Oslinput, Osltextarea, storage_util as StorageUtil, string_util as StringUtil, validation_util as ValidationUtil, baseComponent };
|
|
6997
|
+
export { array_util as ArrayUtil, date_util as DateUtil, DeleteConfirmation, DeleteConfirmationData, Dialog, DialogWrapper, DynamicForm, FormStructureModule, Httpbase, number_util as NumberUtil, object_util as ObjectUtil, OslAutocomplete, OslAutocompleteLister, OslBaseExtended, OslButton, OslCheckbox, OslDatepicker, OslDatetimepicker, OslDocumentUploader, OslFileUpload, OslFormGrid, OslGrid, OslMenu, OslMenuTriggerFor, OslRadio, OslReportForm, OslReportGrid, OslSearchbar, OslSelect, OslSetup, OslSkeletonDirective, OslSkeletonModule, OslSkeletonThemeService, OslSlideToggle, OslUserLog, Oslinput, Osltextarea, storage_util as StorageUtil, string_util as StringUtil, validation_util as ValidationUtil, baseComponent };
|
|
6785
6998
|
//# sourceMappingURL=osl-base-extended.mjs.map
|