@maro-tech/card 0.1.17 → 0.2.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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as i1
|
|
1
|
+
import * as i1 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { input, inject, DestroyRef, signal, Component, computed, viewChild, viewChildren, output, effect, HostListener, Input, InjectionToken, forwardRef, Injectable, ViewChild, untracked } from '@angular/core';
|
|
@@ -6,14 +6,13 @@ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
|
6
6
|
import { EventBus, UiButtonComponent, UiToastService, UiModalComponent, UiConfirmService } from '@maro-tech/core';
|
|
7
7
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
8
8
|
import Panzoom from '@panzoom/panzoom';
|
|
9
|
-
import
|
|
10
|
-
import { Download, LucideAngularModule, Eye, FileText, Plus, Sparkles, Trash } from 'lucide-angular';
|
|
9
|
+
import { LucideDownload, LucideDynamicIcon, LucideEye, LucideFileText, LucidePlus, LucideSparkles, LucideTrash } from '@lucide/angular';
|
|
11
10
|
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
|
|
12
11
|
import { map, shareReplay, forkJoin, switchMap, timer, of, firstValueFrom } from 'rxjs';
|
|
13
12
|
import { UiTableComponent } from '@maro-tech/table';
|
|
14
13
|
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
|
15
14
|
import { map as map$1, exhaustMap, catchError, takeWhile, takeUntil, finalize } from 'rxjs/operators';
|
|
16
|
-
import * as i1$
|
|
15
|
+
import * as i1$1 from '@angular/forms';
|
|
17
16
|
import { FormsModule } from '@angular/forms';
|
|
18
17
|
import { InputSelectComponent } from '@maro-tech/form';
|
|
19
18
|
|
|
@@ -117,8 +116,8 @@ class CardSectionHeaderComponent {
|
|
|
117
116
|
return this.actions().some((action) => action.context?.entity === context.entity
|
|
118
117
|
&& (!context.recordId || action.context?.recordId === context.recordId));
|
|
119
118
|
}
|
|
120
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
121
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
119
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardSectionHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
120
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: CardSectionHeaderComponent, isStandalone: true, selector: "app-card-section-header", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
122
121
|
@if (variant() === 'tabs') {
|
|
123
122
|
<header class="mb-4 flex justify-end">
|
|
124
123
|
<div class="flex flex-wrap gap-2 md:justify-end">
|
|
@@ -170,7 +169,7 @@ class CardSectionHeaderComponent {
|
|
|
170
169
|
}
|
|
171
170
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }] });
|
|
172
171
|
}
|
|
173
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
172
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardSectionHeaderComponent, decorators: [{
|
|
174
173
|
type: Component,
|
|
175
174
|
args: [{
|
|
176
175
|
selector: 'app-card-section-header',
|
|
@@ -281,16 +280,16 @@ class CardHtmlTabComponent {
|
|
|
281
280
|
return null;
|
|
282
281
|
}
|
|
283
282
|
}
|
|
284
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
285
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
283
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardHtmlTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
284
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: CardHtmlTabComponent, isStandalone: true, selector: "app-card-html-tab", inputs: { html: { classPropertyName: "html", publicName: "html", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<section\n (click)=\"onClick($event)\"\n (keydown.enter)=\"onKeydown($event)\"\n (keydown.space)=\"onKeydown($event)\"\n>\n <div [innerHTML]=\"safeHtml()\"></div>\n</section>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
286
285
|
}
|
|
287
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
286
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardHtmlTabComponent, decorators: [{
|
|
288
287
|
type: Component,
|
|
289
288
|
args: [{ selector: 'app-card-html-tab', standalone: true, imports: [CommonModule], template: "<section\n (click)=\"onClick($event)\"\n (keydown.enter)=\"onKeydown($event)\"\n (keydown.space)=\"onKeydown($event)\"\n>\n <div [innerHTML]=\"safeHtml()\"></div>\n</section>\n" }]
|
|
290
289
|
}], propDecorators: { html: [{ type: i0.Input, args: [{ isSignal: true, alias: "html", required: false }] }] } });
|
|
291
290
|
|
|
292
291
|
class ImagesViewerComponent {
|
|
293
|
-
downloadIcon =
|
|
292
|
+
downloadIcon = LucideDownload;
|
|
294
293
|
urls = input([], ...(ngDevMode ? [{ debugName: "urls" }] : /* istanbul ignore next */ []));
|
|
295
294
|
initialIndex = input(0, ...(ngDevMode ? [{ debugName: "initialIndex" }] : /* istanbul ignore next */ []));
|
|
296
295
|
currentIndex = signal(0, ...(ngDevMode ? [{ debugName: "currentIndex" }] : /* istanbul ignore next */ []));
|
|
@@ -482,12 +481,12 @@ class ImagesViewerComponent {
|
|
|
482
481
|
getOriginalUrl(url) {
|
|
483
482
|
return String(url || '').replace(/\/preview(?:\?[^#]*)?$/i, '');
|
|
484
483
|
}
|
|
485
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
486
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ImagesViewerComponent, isStandalone: true, selector: "app-images-viewer", inputs: { urls: { classPropertyName: "urls", publicName: "urls", isSignal: true, isRequired: false, transformFunction: null }, initialIndex: { classPropertyName: "initialIndex", publicName: "initialIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { listeners: { "document:keydown.escape": "onEscape()", "document:keydown.arrowleft": "onArrowLeft()", "document:keydown.arrowright": "onArrowRight()" } }, viewQueries: [{ propertyName: "currentImage", first: true, predicate: ["currentImage"], descendants: true, isSignal: true }, { propertyName: "thumbnailButtons", predicate: ["thumbnailButton"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"fixed inset-0 z-[2300] flex items-center justify-center bg-black/80 p-3 md:p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0444\u043E\u0442\u043E\">\n <button type=\"button\" class=\"absolute inset-0\" aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\" (click)=\"closeViewer()\"></button>\n <div class=\"relative z-[1] flex h-full w-full max-w-[1500px] flex-col items-center justify-center gap-4\" (click)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n class=\"absolute right-2 top-2 z-20 inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white md:right-3 md:top-3\"\n aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438\"\n (click)=\"closeViewer()\">\n \u2715\n </button>\n\n <div\n class=\"relative flex min-h-0 w-full flex-1 items-center justify-center overflow-hidden rounded-[18px]\"\n (touchstart)=\"onTouchStart($event)\"\n (touchend)=\"onTouchEnd($event)\">\n <div class=\"h-full w-full overflow-hidden rounded-[18px]\">\n <div\n class=\"flex h-full w-full\"\n style=\"will-change: transform; backface-visibility: hidden;\"\n [style.transition]=\"imageViewerTransitionStyle\"\n [style.transform]=\"imageViewerTransform\">\n @for (url of urls(); track $index; let idx = $index) {\n <div class=\"flex h-full w-full min-w-full shrink-0 items-center justify-center overflow-hidden\" (wheel)=\"onWheel($event)\">\n @if (isPreloadIndex(idx)) {\n @if (idx === currentIndex() && isOriginalVisible() && originalPreviewUnavailable()) {\n <div class=\"max-w-md rounded-2xl bg-white/95 px-6 py-5 text-center text-sm text-slate-700 shadow-xl\">\n <p class=\"font-semibold text-slate-900\">\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u0443 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0438\u0439</p>\n <p class=\"mt-1\">\u0426\u0435\u0439 \u0444\u0430\u0439\u043B \u043C\u043E\u0436\u043D\u0430 \u043B\u0438\u0448\u0435 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438.</p>\n </div>\n } @else {\n @if (idx === currentIndex()) {\n <img\n #currentImage\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"eager\"\n decoding=\"async\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError(idx)\"\n (dblclick)=\"toggleZoom()\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n } @else {\n <img\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"lazy\"\n decoding=\"async\"\n (error)=\"onImageError(idx)\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n }\n }\n }\n </div>\n }\n </div>\n </div>\n\n @if (urls().length > 1) {\n <button type=\"button\" class=\"absolute left-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:left-3\" aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0454 \u0444\u043E\u0442\u043E\" (click)=\"showPreviousImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u2039</span>\n </button>\n <button type=\"button\" class=\"absolute right-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:right-3\" aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0435 \u0444\u043E\u0442\u043E\" (click)=\"showNextImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u203A</span>\n </button>\n }\n\n @if (currentUrl) {\n <div class=\"absolute bottom-3 right-3 z-20 inline-flex max-w-[calc(100%-1.5rem)] items-center gap-1.5 rounded-2xl bg-black/55 p-1.5 text-white shadow-[0_12px_28px_rgba(15,23,42,0.24)] backdrop-blur-md md:bottom-4 md:right-4\">\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u0431\u0456\u043B\u044C\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomIn()\">+</button>\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u043C\u0435\u043D\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomOut()\">\u2212</button>\n <button type=\"button\" class=\"inline-flex h-9 items-center justify-center rounded-xl px-2 text-xs font-semibold transition hover:bg-white/10\" aria-label=\"\u0421\u043A\u0438\u043D\u0443\u0442\u0438 \u043C\u0430\u0441\u0448\u0442\u0430\u0431\" (click)=\"resetZoom()\">100%</button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 items-center gap-2 rounded-xl px-2.5 text-xs font-semibold transition hover:bg-white/10\"\n [class.bg-emerald-500\\/20]=\"isOriginalVisible()\"\n [class.text-emerald-100]=\"isOriginalVisible()\"\n [attr.aria-pressed]=\"isOriginalVisible()\"\n aria-label=\"\u041F\u0435\u0440\u0435\u043C\u043A\u043D\u0443\u0442\u0438 \u043C\u0456\u0436 \u043F\u0440\u0435\u0432\u2019\u044E \u0442\u0430 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u043E\u043C\"\n (click)=\"toggleOriginal()\">\n <span>\u041E\u0440\u0438\u0433\u0456\u043D\u0430\u043B</span>\n <span\n class=\"relative inline-flex h-5 w-9 items-center rounded-full border p-0.5 transition-colors\"\n [class.bg-emerald-500]=\"isOriginalVisible()\"\n [class.bg-white\\/15]=\"!isOriginalVisible()\"\n [class.border-emerald-200]=\"isOriginalVisible()\"\n [class.border-white\\/45]=\"!isOriginalVisible()\"\n [class.ring-2]=\"isOriginalVisible()\"\n [class.ring-emerald-300\\/70]=\"isOriginalVisible()\">\n <span\n class=\"h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200\"\n [class.translate-x-4]=\"isOriginalVisible()\">\n </span>\n </span>\n </button>\n <a\n class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl transition hover:bg-white/10\"\n [href]=\"getOriginalUrl(currentUrl)\"\n download\n aria-label=\"\u0421\u043A\u0430\u0447\u0430\u0442\u0438 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B \u0444\u043E\u0442\u043E\">\n <lucide-icon [img]=\"downloadIcon\" [size]=\"19\" [strokeWidth]=\"2.25\"></lucide-icon>\n </a>\n </div>\n }\n </div>\n\n @if (urls().length > 1) {\n <div class=\"flex w-full flex-col items-center gap-3 pb-1 md:pb-2\">\n <div class=\"flex w-full max-w-[92vw] flex-nowrap justify-start gap-2 overflow-x-auto overflow-y-hidden overscroll-x-contain px-2 py-3 md:max-w-[80vw]\">\n @for (url of urls(); track url; let idx = $index) {\n <button\n #thumbnailButton\n type=\"button\"\n class=\"h-14 w-14 shrink-0 overflow-hidden rounded-xl border-2 border-transparent bg-white p-1 transition-transform duration-200\"\n [class.border-slate-900]=\"idx === currentIndex()\"\n [class.mx-2]=\"idx === currentIndex()\"\n [style.transform]=\"idx === currentIndex() ? 'scale(1.4)' : 'scale(1)'\"\n [class.origin-center]=\"idx === currentIndex()\"\n [class.relative]=\"idx === currentIndex()\"\n [class.z-10]=\"idx === currentIndex()\"\n [attr.aria-current]=\"idx === currentIndex() ? 'true' : null\"\n [attr.aria-label]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n (click)=\"selectImage(idx, $event)\">\n <img class=\"block aspect-square w-full rounded-lg object-contain\" [src]=\"getThumbnailUrl(url)\" [attr.alt]=\"'\u041C\u0456\u043D\u0456\u0430\u0442\u044E\u0440\u0430 ' + (idx + 1)\" loading=\"lazy\" decoding=\"async\">\n </button>\n }\n </div>\n <div class=\"rounded-full bg-white/95 px-3 py-1.5 text-xs font-semibold text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.2)]\">\n {{ currentIndex() + 1 }} / {{ urls().length }}\n </div>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
|
|
484
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: ImagesViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
485
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: ImagesViewerComponent, isStandalone: true, selector: "app-images-viewer", inputs: { urls: { classPropertyName: "urls", publicName: "urls", isSignal: true, isRequired: false, transformFunction: null }, initialIndex: { classPropertyName: "initialIndex", publicName: "initialIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { listeners: { "document:keydown.escape": "onEscape()", "document:keydown.arrowleft": "onArrowLeft()", "document:keydown.arrowright": "onArrowRight()" } }, viewQueries: [{ propertyName: "currentImage", first: true, predicate: ["currentImage"], descendants: true, isSignal: true }, { propertyName: "thumbnailButtons", predicate: ["thumbnailButton"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"fixed inset-0 z-[2300] flex items-center justify-center bg-black/80 p-3 md:p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0444\u043E\u0442\u043E\">\n <button type=\"button\" class=\"absolute inset-0\" aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\" (click)=\"closeViewer()\"></button>\n <div class=\"relative z-[1] flex h-full w-full max-w-[1500px] flex-col items-center justify-center gap-4\" (click)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n class=\"absolute right-2 top-2 z-20 inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white md:right-3 md:top-3\"\n aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438\"\n (click)=\"closeViewer()\">\n \u2715\n </button>\n\n <div\n class=\"relative flex min-h-0 w-full flex-1 items-center justify-center overflow-hidden rounded-[18px]\"\n (touchstart)=\"onTouchStart($event)\"\n (touchend)=\"onTouchEnd($event)\">\n <div class=\"h-full w-full overflow-hidden rounded-[18px]\">\n <div\n class=\"flex h-full w-full\"\n style=\"will-change: transform; backface-visibility: hidden;\"\n [style.transition]=\"imageViewerTransitionStyle\"\n [style.transform]=\"imageViewerTransform\">\n @for (url of urls(); track $index; let idx = $index) {\n <div class=\"flex h-full w-full min-w-full shrink-0 items-center justify-center overflow-hidden\" (wheel)=\"onWheel($event)\">\n @if (isPreloadIndex(idx)) {\n @if (idx === currentIndex() && isOriginalVisible() && originalPreviewUnavailable()) {\n <div class=\"max-w-md rounded-2xl bg-white/95 px-6 py-5 text-center text-sm text-slate-700 shadow-xl\">\n <p class=\"font-semibold text-slate-900\">\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u0443 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0438\u0439</p>\n <p class=\"mt-1\">\u0426\u0435\u0439 \u0444\u0430\u0439\u043B \u043C\u043E\u0436\u043D\u0430 \u043B\u0438\u0448\u0435 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438.</p>\n </div>\n } @else {\n @if (idx === currentIndex()) {\n <img\n #currentImage\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"eager\"\n decoding=\"async\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError(idx)\"\n (dblclick)=\"toggleZoom()\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n } @else {\n <img\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"lazy\"\n decoding=\"async\"\n (error)=\"onImageError(idx)\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n }\n }\n }\n </div>\n }\n </div>\n </div>\n\n @if (urls().length > 1) {\n <button type=\"button\" class=\"absolute left-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:left-3\" aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0454 \u0444\u043E\u0442\u043E\" (click)=\"showPreviousImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u2039</span>\n </button>\n <button type=\"button\" class=\"absolute right-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:right-3\" aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0435 \u0444\u043E\u0442\u043E\" (click)=\"showNextImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u203A</span>\n </button>\n }\n\n @if (currentUrl) {\n <div class=\"absolute bottom-3 right-3 z-20 inline-flex max-w-[calc(100%-1.5rem)] items-center gap-1.5 rounded-2xl bg-black/55 p-1.5 text-white shadow-[0_12px_28px_rgba(15,23,42,0.24)] backdrop-blur-md md:bottom-4 md:right-4\">\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u0431\u0456\u043B\u044C\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomIn()\">+</button>\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u043C\u0435\u043D\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomOut()\">\u2212</button>\n <button type=\"button\" class=\"inline-flex h-9 items-center justify-center rounded-xl px-2 text-xs font-semibold transition hover:bg-white/10\" aria-label=\"\u0421\u043A\u0438\u043D\u0443\u0442\u0438 \u043C\u0430\u0441\u0448\u0442\u0430\u0431\" (click)=\"resetZoom()\">100%</button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 items-center gap-2 rounded-xl px-2.5 text-xs font-semibold transition hover:bg-white/10\"\n [class.bg-emerald-500\\/20]=\"isOriginalVisible()\"\n [class.text-emerald-100]=\"isOriginalVisible()\"\n [attr.aria-pressed]=\"isOriginalVisible()\"\n aria-label=\"\u041F\u0435\u0440\u0435\u043C\u043A\u043D\u0443\u0442\u0438 \u043C\u0456\u0436 \u043F\u0440\u0435\u0432\u2019\u044E \u0442\u0430 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u043E\u043C\"\n (click)=\"toggleOriginal()\">\n <span>\u041E\u0440\u0438\u0433\u0456\u043D\u0430\u043B</span>\n <span\n class=\"relative inline-flex h-5 w-9 items-center rounded-full border p-0.5 transition-colors\"\n [class.bg-emerald-500]=\"isOriginalVisible()\"\n [class.bg-white\\/15]=\"!isOriginalVisible()\"\n [class.border-emerald-200]=\"isOriginalVisible()\"\n [class.border-white\\/45]=\"!isOriginalVisible()\"\n [class.ring-2]=\"isOriginalVisible()\"\n [class.ring-emerald-300\\/70]=\"isOriginalVisible()\">\n <span\n class=\"h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200\"\n [class.translate-x-4]=\"isOriginalVisible()\">\n </span>\n </span>\n </button>\n <a\n class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl transition hover:bg-white/10\"\n [href]=\"getOriginalUrl(currentUrl)\"\n download\n aria-label=\"\u0421\u043A\u0430\u0447\u0430\u0442\u0438 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B \u0444\u043E\u0442\u043E\">\n <svg [lucideIcon]=\"downloadIcon\" [size]=\"19\" [strokeWidth]=\"2.25\"></svg>\n </a>\n </div>\n }\n </div>\n\n @if (urls().length > 1) {\n <div class=\"flex w-full flex-col items-center gap-3 pb-1 md:pb-2\">\n <div class=\"flex w-full max-w-[92vw] flex-nowrap justify-start gap-2 overflow-x-auto overflow-y-hidden overscroll-x-contain px-2 py-3 md:max-w-[80vw]\">\n @for (url of urls(); track url; let idx = $index) {\n <button\n #thumbnailButton\n type=\"button\"\n class=\"h-14 w-14 shrink-0 overflow-hidden rounded-xl border-2 border-transparent bg-white p-1 transition-transform duration-200\"\n [class.border-slate-900]=\"idx === currentIndex()\"\n [class.mx-2]=\"idx === currentIndex()\"\n [style.transform]=\"idx === currentIndex() ? 'scale(1.4)' : 'scale(1)'\"\n [class.origin-center]=\"idx === currentIndex()\"\n [class.relative]=\"idx === currentIndex()\"\n [class.z-10]=\"idx === currentIndex()\"\n [attr.aria-current]=\"idx === currentIndex() ? 'true' : null\"\n [attr.aria-label]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n (click)=\"selectImage(idx, $event)\">\n <img class=\"block aspect-square w-full rounded-lg object-contain\" [src]=\"getThumbnailUrl(url)\" [attr.alt]=\"'\u041C\u0456\u043D\u0456\u0430\u0442\u044E\u0440\u0430 ' + (idx + 1)\" loading=\"lazy\" decoding=\"async\">\n </button>\n }\n </div>\n <div class=\"rounded-full bg-white/95 px-3 py-1.5 text-xs font-semibold text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.2)]\">\n {{ currentIndex() + 1 }} / {{ urls().length }}\n </div>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }] });
|
|
487
486
|
}
|
|
488
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
487
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: ImagesViewerComponent, decorators: [{
|
|
489
488
|
type: Component,
|
|
490
|
-
args: [{ selector: 'app-images-viewer', standalone: true, imports: [CommonModule,
|
|
489
|
+
args: [{ selector: 'app-images-viewer', standalone: true, imports: [CommonModule, LucideDynamicIcon], template: "<div class=\"fixed inset-0 z-[2300] flex items-center justify-center bg-black/80 p-3 md:p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0444\u043E\u0442\u043E\">\n <button type=\"button\" class=\"absolute inset-0\" aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\" (click)=\"closeViewer()\"></button>\n <div class=\"relative z-[1] flex h-full w-full max-w-[1500px] flex-col items-center justify-center gap-4\" (click)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n class=\"absolute right-2 top-2 z-20 inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white md:right-3 md:top-3\"\n aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438\"\n (click)=\"closeViewer()\">\n \u2715\n </button>\n\n <div\n class=\"relative flex min-h-0 w-full flex-1 items-center justify-center overflow-hidden rounded-[18px]\"\n (touchstart)=\"onTouchStart($event)\"\n (touchend)=\"onTouchEnd($event)\">\n <div class=\"h-full w-full overflow-hidden rounded-[18px]\">\n <div\n class=\"flex h-full w-full\"\n style=\"will-change: transform; backface-visibility: hidden;\"\n [style.transition]=\"imageViewerTransitionStyle\"\n [style.transform]=\"imageViewerTransform\">\n @for (url of urls(); track $index; let idx = $index) {\n <div class=\"flex h-full w-full min-w-full shrink-0 items-center justify-center overflow-hidden\" (wheel)=\"onWheel($event)\">\n @if (isPreloadIndex(idx)) {\n @if (idx === currentIndex() && isOriginalVisible() && originalPreviewUnavailable()) {\n <div class=\"max-w-md rounded-2xl bg-white/95 px-6 py-5 text-center text-sm text-slate-700 shadow-xl\">\n <p class=\"font-semibold text-slate-900\">\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u0443 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0438\u0439</p>\n <p class=\"mt-1\">\u0426\u0435\u0439 \u0444\u0430\u0439\u043B \u043C\u043E\u0436\u043D\u0430 \u043B\u0438\u0448\u0435 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438.</p>\n </div>\n } @else {\n @if (idx === currentIndex()) {\n <img\n #currentImage\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"eager\"\n decoding=\"async\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError(idx)\"\n (dblclick)=\"toggleZoom()\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n } @else {\n <img\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"lazy\"\n decoding=\"async\"\n (error)=\"onImageError(idx)\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n }\n }\n }\n </div>\n }\n </div>\n </div>\n\n @if (urls().length > 1) {\n <button type=\"button\" class=\"absolute left-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:left-3\" aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0454 \u0444\u043E\u0442\u043E\" (click)=\"showPreviousImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u2039</span>\n </button>\n <button type=\"button\" class=\"absolute right-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:right-3\" aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0435 \u0444\u043E\u0442\u043E\" (click)=\"showNextImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u203A</span>\n </button>\n }\n\n @if (currentUrl) {\n <div class=\"absolute bottom-3 right-3 z-20 inline-flex max-w-[calc(100%-1.5rem)] items-center gap-1.5 rounded-2xl bg-black/55 p-1.5 text-white shadow-[0_12px_28px_rgba(15,23,42,0.24)] backdrop-blur-md md:bottom-4 md:right-4\">\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u0431\u0456\u043B\u044C\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomIn()\">+</button>\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u043C\u0435\u043D\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomOut()\">\u2212</button>\n <button type=\"button\" class=\"inline-flex h-9 items-center justify-center rounded-xl px-2 text-xs font-semibold transition hover:bg-white/10\" aria-label=\"\u0421\u043A\u0438\u043D\u0443\u0442\u0438 \u043C\u0430\u0441\u0448\u0442\u0430\u0431\" (click)=\"resetZoom()\">100%</button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 items-center gap-2 rounded-xl px-2.5 text-xs font-semibold transition hover:bg-white/10\"\n [class.bg-emerald-500\\/20]=\"isOriginalVisible()\"\n [class.text-emerald-100]=\"isOriginalVisible()\"\n [attr.aria-pressed]=\"isOriginalVisible()\"\n aria-label=\"\u041F\u0435\u0440\u0435\u043C\u043A\u043D\u0443\u0442\u0438 \u043C\u0456\u0436 \u043F\u0440\u0435\u0432\u2019\u044E \u0442\u0430 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u043E\u043C\"\n (click)=\"toggleOriginal()\">\n <span>\u041E\u0440\u0438\u0433\u0456\u043D\u0430\u043B</span>\n <span\n class=\"relative inline-flex h-5 w-9 items-center rounded-full border p-0.5 transition-colors\"\n [class.bg-emerald-500]=\"isOriginalVisible()\"\n [class.bg-white\\/15]=\"!isOriginalVisible()\"\n [class.border-emerald-200]=\"isOriginalVisible()\"\n [class.border-white\\/45]=\"!isOriginalVisible()\"\n [class.ring-2]=\"isOriginalVisible()\"\n [class.ring-emerald-300\\/70]=\"isOriginalVisible()\">\n <span\n class=\"h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200\"\n [class.translate-x-4]=\"isOriginalVisible()\">\n </span>\n </span>\n </button>\n <a\n class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl transition hover:bg-white/10\"\n [href]=\"getOriginalUrl(currentUrl)\"\n download\n aria-label=\"\u0421\u043A\u0430\u0447\u0430\u0442\u0438 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B \u0444\u043E\u0442\u043E\">\n <svg [lucideIcon]=\"downloadIcon\" [size]=\"19\" [strokeWidth]=\"2.25\"></svg>\n </a>\n </div>\n }\n </div>\n\n @if (urls().length > 1) {\n <div class=\"flex w-full flex-col items-center gap-3 pb-1 md:pb-2\">\n <div class=\"flex w-full max-w-[92vw] flex-nowrap justify-start gap-2 overflow-x-auto overflow-y-hidden overscroll-x-contain px-2 py-3 md:max-w-[80vw]\">\n @for (url of urls(); track url; let idx = $index) {\n <button\n #thumbnailButton\n type=\"button\"\n class=\"h-14 w-14 shrink-0 overflow-hidden rounded-xl border-2 border-transparent bg-white p-1 transition-transform duration-200\"\n [class.border-slate-900]=\"idx === currentIndex()\"\n [class.mx-2]=\"idx === currentIndex()\"\n [style.transform]=\"idx === currentIndex() ? 'scale(1.4)' : 'scale(1)'\"\n [class.origin-center]=\"idx === currentIndex()\"\n [class.relative]=\"idx === currentIndex()\"\n [class.z-10]=\"idx === currentIndex()\"\n [attr.aria-current]=\"idx === currentIndex() ? 'true' : null\"\n [attr.aria-label]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n (click)=\"selectImage(idx, $event)\">\n <img class=\"block aspect-square w-full rounded-lg object-contain\" [src]=\"getThumbnailUrl(url)\" [attr.alt]=\"'\u041C\u0456\u043D\u0456\u0430\u0442\u044E\u0440\u0430 ' + (idx + 1)\" loading=\"lazy\" decoding=\"async\">\n </button>\n }\n </div>\n <div class=\"rounded-full bg-white/95 px-3 py-1.5 text-xs font-semibold text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.2)]\">\n {{ currentIndex() + 1 }} / {{ urls().length }}\n </div>\n </div>\n }\n </div>\n</div>\n" }]
|
|
491
490
|
}], ctorParameters: () => [], propDecorators: { urls: [{ type: i0.Input, args: [{ isSignal: true, alias: "urls", required: false }] }], initialIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialIndex", required: false }] }], currentImage: [{ type: i0.ViewChild, args: ['currentImage', { isSignal: true }] }], thumbnailButtons: [{ type: i0.ViewChildren, args: ['thumbnailButton', { isSignal: true }] }], closed: [{ type: i0.Output, args: ["closed"] }], onEscape: [{
|
|
492
491
|
type: HostListener,
|
|
493
492
|
args: ['document:keydown.escape']
|
|
@@ -611,10 +610,10 @@ class DetailsGridComponent {
|
|
|
611
610
|
? { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }
|
|
612
611
|
: { day: '2-digit', month: '2-digit', year: 'numeric' }).format(date);
|
|
613
612
|
}
|
|
614
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
615
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
613
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DetailsGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
614
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DetailsGridComponent, isStandalone: true, selector: "app-details-grid", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"grid gap-4\" [class.grid-cols-1]=\"!hasExplicitColumns()\" [class.sm:grid-cols-3]=\"!hasExplicitColumns()\" [class.sm:grid-cols-12]=\"hasExplicitColumns()\">\n @for (field of displayFields(); track $index) {\n <div class=\"rounded-2xl border border-slate-100 bg-slate-200 p-4\" [ngClass]=\"getFieldColumnClass(field)\" [class.flex]=\"field.type === 'image'\" [class.flex-col]=\"field.type === 'image'\" [class.min-h-64]=\"field.type === 'image'\">\n <p class=\"text-xs uppercase tracking-[0.18em] text-slate-500\">{{ field.label }}</p>\n @if (field.type === 'image') {\n @if (field.imageSrc) {\n <button type=\"button\" class=\"mt-2 block flex-1 cursor-zoom-in overflow-hidden rounded-xl border border-slate-200 bg-white\" [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 ' + field.label\" (click)=\"openViewer(field.imageSrc)\">\n <img [src]=\"field.imageSrc\" [alt]=\"field.label\" class=\"h-full w-full object-cover\" />\n </button>\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">-</p>\n }\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">{{ field.displayValue ?? '-' }}</p>\n }\n </div>\n }\n</div>\n\n@if (selectedImageSrc(); as imageSrc) {\n <app-images-viewer [urls]=\"[imageSrc]\" (closed)=\"closeViewer()\" />\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }] });
|
|
616
615
|
}
|
|
617
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
616
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DetailsGridComponent, decorators: [{
|
|
618
617
|
type: Component,
|
|
619
618
|
args: [{ selector: 'app-details-grid', standalone: true, imports: [CommonModule, ImagesViewerComponent], template: "<div class=\"grid gap-4\" [class.grid-cols-1]=\"!hasExplicitColumns()\" [class.sm:grid-cols-3]=\"!hasExplicitColumns()\" [class.sm:grid-cols-12]=\"hasExplicitColumns()\">\n @for (field of displayFields(); track $index) {\n <div class=\"rounded-2xl border border-slate-100 bg-slate-200 p-4\" [ngClass]=\"getFieldColumnClass(field)\" [class.flex]=\"field.type === 'image'\" [class.flex-col]=\"field.type === 'image'\" [class.min-h-64]=\"field.type === 'image'\">\n <p class=\"text-xs uppercase tracking-[0.18em] text-slate-500\">{{ field.label }}</p>\n @if (field.type === 'image') {\n @if (field.imageSrc) {\n <button type=\"button\" class=\"mt-2 block flex-1 cursor-zoom-in overflow-hidden rounded-xl border border-slate-200 bg-white\" [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 ' + field.label\" (click)=\"openViewer(field.imageSrc)\">\n <img [src]=\"field.imageSrc\" [alt]=\"field.label\" class=\"h-full w-full object-cover\" />\n </button>\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">-</p>\n }\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">{{ field.displayValue ?? '-' }}</p>\n }\n </div>\n }\n</div>\n\n@if (selectedImageSrc(); as imageSrc) {\n <app-images-viewer [urls]=\"[imageSrc]\" (closed)=\"closeViewer()\" />\n}\n" }]
|
|
620
619
|
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
|
|
@@ -659,10 +658,10 @@ class ImagesComponent {
|
|
|
659
658
|
.map((item) => String(item || '').trim())
|
|
660
659
|
.filter(Boolean)));
|
|
661
660
|
}
|
|
662
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
663
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
661
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: ImagesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
662
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: ImagesComponent, isStandalone: true, selector: "app-images", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (resolvedImageUrls().length === 0) {\n <p class=\"text-sm text-slate-500\">\u0424\u043E\u0442\u043E \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456</p>\n} @else {\n <div\n class=\"grid gap-3 lg:h-[400px] lg:max-h-[400px]\"\n [ngClass]=\"resolvedImageUrls().length === 1 ? 'grid-cols-1' : 'grid-cols-1 lg:grid-cols-2'\"\n >\n @let previewUrls = resolvedImagePreviewUrls();\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E 1'\"\n (click)=\"openViewer(0)\"\n >\n <img\n [src]=\"previewUrls[0]\"\n [alt]=\"'\u0424\u043E\u0442\u043E 1'\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-56 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n </button>\n\n @if (previewUrls.length > 1) {\n <div class=\"grid grid-cols-2 grid-rows-2 gap-3 lg:h-full lg:min-h-0\">\n @for (image of previewUrls.slice(1, 5); track image; let i = $index) {\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E ' + (i + 2)\"\n (click)=\"openViewer(i + 1)\"\n >\n <img\n [src]=\"image\"\n [alt]=\"'\u0424\u043E\u0442\u043E ' + (i + 2)\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-28 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n @if (i === 3 && resolvedImageUrls().length > 5) {\n <span class=\"absolute inset-0 flex items-center justify-center bg-slate-950/55 text-2xl font-semibold text-white transition group-hover:bg-slate-950/65\">\n +{{ resolvedImageUrls().length - 5 }}\n </span>\n }\n </button>\n }\n </div>\n }\n </div>\n\n @if (isViewerOpen()) {\n <app-images-viewer\n [urls]=\"resolvedImageUrls()\"\n [initialIndex]=\"viewerStartIndex()\"\n (closed)=\"closeViewer()\"\n ></app-images-viewer>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }] });
|
|
664
663
|
}
|
|
665
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
664
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: ImagesComponent, decorators: [{
|
|
666
665
|
type: Component,
|
|
667
666
|
args: [{ selector: 'app-images', standalone: true, imports: [CommonModule, ImagesViewerComponent], template: "@if (resolvedImageUrls().length === 0) {\n <p class=\"text-sm text-slate-500\">\u0424\u043E\u0442\u043E \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456</p>\n} @else {\n <div\n class=\"grid gap-3 lg:h-[400px] lg:max-h-[400px]\"\n [ngClass]=\"resolvedImageUrls().length === 1 ? 'grid-cols-1' : 'grid-cols-1 lg:grid-cols-2'\"\n >\n @let previewUrls = resolvedImagePreviewUrls();\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E 1'\"\n (click)=\"openViewer(0)\"\n >\n <img\n [src]=\"previewUrls[0]\"\n [alt]=\"'\u0424\u043E\u0442\u043E 1'\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-56 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n </button>\n\n @if (previewUrls.length > 1) {\n <div class=\"grid grid-cols-2 grid-rows-2 gap-3 lg:h-full lg:min-h-0\">\n @for (image of previewUrls.slice(1, 5); track image; let i = $index) {\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E ' + (i + 2)\"\n (click)=\"openViewer(i + 1)\"\n >\n <img\n [src]=\"image\"\n [alt]=\"'\u0424\u043E\u0442\u043E ' + (i + 2)\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-28 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n @if (i === 3 && resolvedImageUrls().length > 5) {\n <span class=\"absolute inset-0 flex items-center justify-center bg-slate-950/55 text-2xl font-semibold text-white transition group-hover:bg-slate-950/65\">\n +{{ resolvedImageUrls().length - 5 }}\n </span>\n }\n </button>\n }\n </div>\n }\n </div>\n\n @if (isViewerOpen()) {\n <app-images-viewer\n [urls]=\"resolvedImageUrls()\"\n [initialIndex]=\"viewerStartIndex()\"\n (closed)=\"closeViewer()\"\n ></app-images-viewer>\n }\n}\n" }]
|
|
668
667
|
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
|
|
@@ -838,6 +837,15 @@ class TableComponent {
|
|
|
838
837
|
}, { id: String(raw[0] || '') })
|
|
839
838
|
: { ...(raw || {}) };
|
|
840
839
|
row['id'] = String(row['id'] || '');
|
|
840
|
+
for (const column of columns) {
|
|
841
|
+
const type = String(column['type'] || '').toLowerCase();
|
|
842
|
+
if (type !== 'date' && type !== 'datetime')
|
|
843
|
+
continue;
|
|
844
|
+
const key = String(column['id'] || '').trim();
|
|
845
|
+
if (!key || row[key] == null || row[key] === '')
|
|
846
|
+
continue;
|
|
847
|
+
row[key] = this.formatDate(String(row[key]), type === 'datetime');
|
|
848
|
+
}
|
|
841
849
|
if (!Array.isArray(row['actions'])) {
|
|
842
850
|
const actions = configured.filter((action) => this.matchesRowCondition(action, row));
|
|
843
851
|
const actionIds = new Set(actions.map((action) => String(action.id || '').trim()).filter(Boolean));
|
|
@@ -868,6 +876,14 @@ class TableComponent {
|
|
|
868
876
|
return false;
|
|
869
877
|
}
|
|
870
878
|
}
|
|
879
|
+
formatDate(value, withTime) {
|
|
880
|
+
const date = new Date(value);
|
|
881
|
+
if (Number.isNaN(date.getTime()))
|
|
882
|
+
return value;
|
|
883
|
+
return new Intl.DateTimeFormat('uk-UA', withTime
|
|
884
|
+
? { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }
|
|
885
|
+
: { day: '2-digit', month: '2-digit', year: 'numeric' }).format(date);
|
|
886
|
+
}
|
|
871
887
|
tableName() {
|
|
872
888
|
return String(this.config?.props?.['table'] || this.config?.props?.['entity'] || '').trim();
|
|
873
889
|
}
|
|
@@ -913,10 +929,10 @@ class TableComponent {
|
|
|
913
929
|
return this.resolveObject(value, row);
|
|
914
930
|
return value;
|
|
915
931
|
}
|
|
916
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
917
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
932
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
933
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: TableComponent, isStandalone: true, selector: "app-card-table", inputs: { config: "config", data: "data" }, usesOnChanges: true, ngImport: i0, template: "<section class=\"space-y-4\">\n @if (headerActions().length) {\n <div class=\"flex justify-end gap-2\">\n @for (action of headerActions(); track action.id) {\n <button type=\"button\" class=\"rounded-lg border border-slate-200 px-3 py-1.5 text-sm\" (click)=\"onHeaderAction(action)\">\n {{ action.label }}\n </button>\n }\n </div>\n }\n\n <app-ui-table\n class=\"flex min-h-0 max-h-[80dvh] flex-col overflow-hidden\"\n [data]=\"tableData()\"\n [columns]=\"columns()\"\n [pageSizeOptions]=\"pageSizeOptionsSignal()\"\n [isLoading]=\"isLoading()\"\n [disablePaging]=\"disablePaging\"\n (pageChange)=\"onPageChange($event)\"\n (actionClick)=\"onAction($event)\"\n (cellChange)=\"onCellChange($event)\"\n ></app-ui-table>\n</section>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiTableComponent, selector: "app-ui-table", inputs: ["pageSizeOptions", "columns", "isLoading", "data", "disablePaging", "rowClickable", "imageResolver"], outputs: ["pageChange", "rowClick", "actionClick", "cellChange"] }] });
|
|
918
934
|
}
|
|
919
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
935
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: TableComponent, decorators: [{
|
|
920
936
|
type: Component,
|
|
921
937
|
args: [{ selector: 'app-card-table', standalone: true, imports: [CommonModule, UiTableComponent], template: "<section class=\"space-y-4\">\n @if (headerActions().length) {\n <div class=\"flex justify-end gap-2\">\n @for (action of headerActions(); track action.id) {\n <button type=\"button\" class=\"rounded-lg border border-slate-200 px-3 py-1.5 text-sm\" (click)=\"onHeaderAction(action)\">\n {{ action.label }}\n </button>\n }\n </div>\n }\n\n <app-ui-table\n class=\"flex min-h-0 max-h-[80dvh] flex-col overflow-hidden\"\n [data]=\"tableData()\"\n [columns]=\"columns()\"\n [pageSizeOptions]=\"pageSizeOptionsSignal()\"\n [isLoading]=\"isLoading()\"\n [disablePaging]=\"disablePaging\"\n (pageChange)=\"onPageChange($event)\"\n (actionClick)=\"onAction($event)\"\n (cellChange)=\"onCellChange($event)\"\n ></app-ui-table>\n</section>\n" }]
|
|
922
938
|
}], ctorParameters: () => [], propDecorators: { config: [{
|
|
@@ -1005,10 +1021,10 @@ class UiCardPanelsLayoutComponent {
|
|
|
1005
1021
|
return { tab };
|
|
1006
1022
|
return found.resolveInputs(tab, this.data());
|
|
1007
1023
|
}
|
|
1008
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1009
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1024
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiCardPanelsLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1025
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: UiCardPanelsLayoutComponent, isStandalone: true, selector: "app-ui-card-panels-layout", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (tabs().length) {\n <div class=\"grid grid-cols-1 gap-4 md:grid-cols-12\">\n @for (tab of tabs(); track tab.id) {\n <section\n [class.rounded-3xl]=\"!embedded()\"\n [class.border]=\"!embedded()\"\n [class.border-slate-200]=\"!embedded()\"\n [class.bg-white]=\"!embedded()\"\n [class.p-6]=\"!embedded()\"\n [class.min-w-0]=\"embedded()\"\n [ngClass]=\"getColSpanClass(tab)\"\n [attr.data-card-panel-id]=\"tab.id\"\n >\n @if (shouldShowPanelHeader(tab)) {\n <app-card-section-header\n [data]=\"data()\"\n [title]=\"tab.title\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (getNestedCardConfig(tab); as nestedCard) {\n <app-card [tabs]=\"nestedCard.tabs\" [data]=\"data()\" [layout]=\"nestedCard.layout\"></app-card>\n } @else if (getNestedPanels(tab); as nestedPanels) {\n <app-card [tabs]=\"nestedPanels\" [data]=\"data()\" layout=\"panels\" [embedded]=\"true\"></app-card>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'images') {\n <app-images [config]=\"tab\" [data]=\"data()\"></app-images>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1.NgClass), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgComponentOutlet), selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: i0.forwardRef(() => CardComponent), selector: "app-card", inputs: ["tabs", "data", "layout", "embedded"] }, { kind: "component", type: i0.forwardRef(() => CardSectionHeaderComponent), selector: "app-card-section-header", inputs: ["variant", "title", "actions", "data"] }, { kind: "component", type: i0.forwardRef(() => CardHtmlTabComponent), selector: "app-card-html-tab", inputs: ["html"] }, { kind: "component", type: i0.forwardRef(() => DetailsGridComponent), selector: "app-details-grid", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => ImagesComponent), selector: "app-images", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => TableComponent), selector: "app-card-table", inputs: ["config", "data"] }] });
|
|
1010
1026
|
}
|
|
1011
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1027
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiCardPanelsLayoutComponent, decorators: [{
|
|
1012
1028
|
type: Component,
|
|
1013
1029
|
args: [{ selector: 'app-ui-card-panels-layout', standalone: true, imports: [CommonModule, forwardRef(() => CardComponent), CardSectionHeaderComponent, CardHtmlTabComponent, DetailsGridComponent, ImagesComponent, TableComponent], template: "@if (tabs().length) {\n <div class=\"grid grid-cols-1 gap-4 md:grid-cols-12\">\n @for (tab of tabs(); track tab.id) {\n <section\n [class.rounded-3xl]=\"!embedded()\"\n [class.border]=\"!embedded()\"\n [class.border-slate-200]=\"!embedded()\"\n [class.bg-white]=\"!embedded()\"\n [class.p-6]=\"!embedded()\"\n [class.min-w-0]=\"embedded()\"\n [ngClass]=\"getColSpanClass(tab)\"\n [attr.data-card-panel-id]=\"tab.id\"\n >\n @if (shouldShowPanelHeader(tab)) {\n <app-card-section-header\n [data]=\"data()\"\n [title]=\"tab.title\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (getNestedCardConfig(tab); as nestedCard) {\n <app-card [tabs]=\"nestedCard.tabs\" [data]=\"data()\" [layout]=\"nestedCard.layout\"></app-card>\n } @else if (getNestedPanels(tab); as nestedPanels) {\n <app-card [tabs]=\"nestedPanels\" [data]=\"data()\" layout=\"panels\" [embedded]=\"true\"></app-card>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'images') {\n <app-images [config]=\"tab\" [data]=\"data()\"></app-images>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </div>\n}\n" }]
|
|
1014
1030
|
}], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }] } });
|
|
@@ -1075,10 +1091,10 @@ class UiCardTabsLayoutComponent {
|
|
|
1075
1091
|
return { tab };
|
|
1076
1092
|
return found.resolveInputs(tab, this.data());
|
|
1077
1093
|
}
|
|
1078
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1079
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1094
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiCardTabsLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1095
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: UiCardTabsLayoutComponent, isStandalone: true, selector: "app-ui-card-tabs-layout", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (tabs().length) {\n <section class=\"space-y-4\">\n <nav class=\"flex flex-wrap gap-2\" aria-label=\"Card tabs\">\n @for (tab of tabs(); track tab.id) {\n <button\n type=\"button\"\n class=\"rounded-xl border px-4 py-2 text-sm font-medium transition\"\n [class.border-slate-900]=\"activeTab()?.id === tab.id\"\n [class.bg-slate-900]=\"activeTab()?.id === tab.id\"\n [class.text-white]=\"activeTab()?.id === tab.id\"\n [class.border-slate-200]=\"activeTab()?.id !== tab.id\"\n [class.bg-white]=\"activeTab()?.id !== tab.id\"\n [class.text-slate-700]=\"activeTab()?.id !== tab.id\"\n (click)=\"setActiveTab(tab.id)\"\n >\n {{ tab.title }}\n </button>\n }\n </nav>\n\n @if (activeTab(); as tab) {\n <section\n [attr.data-card-tab-id]=\"tab.id\"\n >\n @if (getVisibleActions(tab).length) {\n <app-card-section-header\n variant=\"tabs\"\n [data]=\"data()\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (tab.tabs?.length) {\n <app-card [tabs]=\"tab.tabs || []\" [data]=\"data()\" [layout]=\"tab.layout || 'panels'\"></app-card>\n } @else if (tab.component === 'images') {\n <app-images\n [config]=\"tab\"\n [data]=\"data()\"\n ></app-images>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </section>\n}\n", dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1.NgComponentOutlet), selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: i0.forwardRef(() => CardComponent), selector: "app-card", inputs: ["tabs", "data", "layout", "embedded"] }, { kind: "component", type: i0.forwardRef(() => CardSectionHeaderComponent), selector: "app-card-section-header", inputs: ["variant", "title", "actions", "data"] }, { kind: "component", type: i0.forwardRef(() => CardHtmlTabComponent), selector: "app-card-html-tab", inputs: ["html"] }, { kind: "component", type: i0.forwardRef(() => ImagesComponent), selector: "app-images", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => DetailsGridComponent), selector: "app-details-grid", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => TableComponent), selector: "app-card-table", inputs: ["config", "data"] }] });
|
|
1080
1096
|
}
|
|
1081
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1097
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiCardTabsLayoutComponent, decorators: [{
|
|
1082
1098
|
type: Component,
|
|
1083
1099
|
args: [{ selector: 'app-ui-card-tabs-layout', standalone: true, imports: [CommonModule, forwardRef(() => CardComponent), CardSectionHeaderComponent, CardHtmlTabComponent, ImagesComponent, DetailsGridComponent, TableComponent], template: "@if (tabs().length) {\n <section class=\"space-y-4\">\n <nav class=\"flex flex-wrap gap-2\" aria-label=\"Card tabs\">\n @for (tab of tabs(); track tab.id) {\n <button\n type=\"button\"\n class=\"rounded-xl border px-4 py-2 text-sm font-medium transition\"\n [class.border-slate-900]=\"activeTab()?.id === tab.id\"\n [class.bg-slate-900]=\"activeTab()?.id === tab.id\"\n [class.text-white]=\"activeTab()?.id === tab.id\"\n [class.border-slate-200]=\"activeTab()?.id !== tab.id\"\n [class.bg-white]=\"activeTab()?.id !== tab.id\"\n [class.text-slate-700]=\"activeTab()?.id !== tab.id\"\n (click)=\"setActiveTab(tab.id)\"\n >\n {{ tab.title }}\n </button>\n }\n </nav>\n\n @if (activeTab(); as tab) {\n <section\n [attr.data-card-tab-id]=\"tab.id\"\n >\n @if (getVisibleActions(tab).length) {\n <app-card-section-header\n variant=\"tabs\"\n [data]=\"data()\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (tab.tabs?.length) {\n <app-card [tabs]=\"tab.tabs || []\" [data]=\"data()\" [layout]=\"tab.layout || 'panels'\"></app-card>\n } @else if (tab.component === 'images') {\n <app-images\n [config]=\"tab\"\n [data]=\"data()\"\n ></app-images>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </section>\n}\n" }]
|
|
1084
1100
|
}], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
|
|
@@ -1088,10 +1104,10 @@ class CardComponent {
|
|
|
1088
1104
|
data = input(null, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
1089
1105
|
layout = input('panels', ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
|
|
1090
1106
|
embedded = input(false, ...(ngDevMode ? [{ debugName: "embedded" }] : /* istanbul ignore next */ []));
|
|
1091
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1092
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1107
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1108
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: CardComponent, isStandalone: true, selector: "app-card", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (layout() === 'panels') {\n <app-ui-card-panels-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n [embedded]=\"embedded()\"\n ></app-ui-card-panels-layout>\n} @else {\n <app-ui-card-tabs-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n ></app-ui-card-tabs-layout>\n}\n", dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "component", type: i0.forwardRef(() => UiCardTabsLayoutComponent), selector: "app-ui-card-tabs-layout", inputs: ["tabs", "data"] }, { kind: "component", type: i0.forwardRef(() => UiCardPanelsLayoutComponent), selector: "app-ui-card-panels-layout", inputs: ["tabs", "data", "embedded"] }] });
|
|
1093
1109
|
}
|
|
1094
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1110
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardComponent, decorators: [{
|
|
1095
1111
|
type: Component,
|
|
1096
1112
|
args: [{ selector: 'app-card', standalone: true, imports: [CommonModule, forwardRef(() => UiCardTabsLayoutComponent), forwardRef(() => UiCardPanelsLayoutComponent)], template: "@if (layout() === 'panels') {\n <app-ui-card-panels-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n [embedded]=\"embedded()\"\n ></app-ui-card-panels-layout>\n} @else {\n <app-ui-card-tabs-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n ></app-ui-card-tabs-layout>\n}\n" }]
|
|
1097
1113
|
}], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }] } });
|
|
@@ -1106,10 +1122,10 @@ class CardDictionaryService {
|
|
|
1106
1122
|
getSuggestByName(name) {
|
|
1107
1123
|
return this.http.get(apiUrl(this.baseUrl, `/api/suggest/${encodeURIComponent(name)}`));
|
|
1108
1124
|
}
|
|
1109
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1110
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1125
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardDictionaryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1126
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardDictionaryService, providedIn: 'root' });
|
|
1111
1127
|
}
|
|
1112
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1128
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardDictionaryService, decorators: [{
|
|
1113
1129
|
type: Injectable,
|
|
1114
1130
|
args: [{ providedIn: 'root' }]
|
|
1115
1131
|
}] });
|
|
@@ -1118,10 +1134,10 @@ class CardCurrentUserService {
|
|
|
1118
1134
|
baseUrl = inject(UI_CARD_API_BASE_URL);
|
|
1119
1135
|
user$ = this.http.get(apiUrl(this.baseUrl, '/api/users/me'), { withCredentials: true }).pipe(shareReplay(1));
|
|
1120
1136
|
getCurrentUser() { return this.user$; }
|
|
1121
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1122
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1137
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardCurrentUserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1138
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardCurrentUserService, providedIn: 'root' });
|
|
1123
1139
|
}
|
|
1124
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1140
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardCurrentUserService, decorators: [{
|
|
1125
1141
|
type: Injectable,
|
|
1126
1142
|
args: [{ providedIn: 'root' }]
|
|
1127
1143
|
}] });
|
|
@@ -1130,10 +1146,10 @@ class CardImageService {
|
|
|
1130
1146
|
getPhotoLink(id) {
|
|
1131
1147
|
return id ? apiUrl(this.baseUrl, `/api/files/${encodeURIComponent(id)}/preview?scale=25`) : undefined;
|
|
1132
1148
|
}
|
|
1133
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1134
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1149
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1150
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardImageService, providedIn: 'root' });
|
|
1135
1151
|
}
|
|
1136
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1152
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardImageService, decorators: [{
|
|
1137
1153
|
type: Injectable,
|
|
1138
1154
|
args: [{ providedIn: 'root' }]
|
|
1139
1155
|
}] });
|
|
@@ -1171,10 +1187,10 @@ class UiEntityDocumentsService {
|
|
|
1171
1187
|
resolveDownloadUrl(fileId) {
|
|
1172
1188
|
return cardApiResourceUrl(this.baseUrl, `/api/files/${encodeURIComponent(fileId)}`);
|
|
1173
1189
|
}
|
|
1174
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1175
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1190
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiEntityDocumentsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1191
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiEntityDocumentsService, providedIn: 'root' });
|
|
1176
1192
|
}
|
|
1177
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1193
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiEntityDocumentsService, decorators: [{
|
|
1178
1194
|
type: Injectable,
|
|
1179
1195
|
args: [{ providedIn: 'root' }]
|
|
1180
1196
|
}] });
|
|
@@ -1248,12 +1264,12 @@ class DocumentsUploadModalComponent {
|
|
|
1248
1264
|
this.uploadFileInput.nativeElement.value = '';
|
|
1249
1265
|
}
|
|
1250
1266
|
}
|
|
1251
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1252
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1267
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsUploadModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1268
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DocumentsUploadModalComponent, isStandalone: true, selector: "app-documents-upload-modal", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", saved: "saved" }, viewQueries: [{ propertyName: "uploadFileInput", first: true, predicate: ["uploadFileInput"], descendants: true }], ngImport: i0, template: "<core-modal\n title=\"\u0414\u043E\u0434\u0430\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-4\">\n <input-select\n [data]=\"'doc_type'\"\n name=\"uploadDocumentTypeId\"\n label=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n hint=\"\u041D\u0435\u043E\u0431\u043E\u0432'\u044F\u0437\u043A\u043E\u0432\u043E\"\n [ngModel]=\"documentTypeId()\"\n (ngModelChange)=\"onDocumentTypeChange($event)\"\n placeholder=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n [searchable]=\"true\"\n ></input-select>\n\n <div class=\"space-y-2\">\n <label class=\"block text-sm font-medium text-slate-700\" for=\"document-files\">\u0424\u0430\u0439\u043B\u0438</label>\n <input\n #uploadFileInput\n id=\"document-files\"\n type=\"file\"\n class=\"block w-full rounded-xl border border-slate-200 bg-white px-3 py-2.5 text-sm text-slate-900 outline-none transition file:mr-3 file:rounded-lg file:border-0 file:bg-slate-900 file:px-3 file:py-2 file:text-sm file:font-medium file:text-white focus:border-slate-400 focus:ring-2 focus:ring-slate-200\"\n multiple\n (change)=\"onFilesSelected($event)\"\n />\n @if (fileNames().length) {\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-600\">\n @for (fileName of fileNames(); track fileName) {\n <div class=\"truncate\">{{ fileName }}</div>\n }\n </div>\n } @else {\n <p class=\"text-xs text-slate-500\">\u041C\u043E\u0436\u043D\u0430 \u043E\u0431\u0440\u0430\u0442\u0438 \u043E\u0434\u0438\u043D \u0430\u0431\u043E \u0434\u0435\u043A\u0456\u043B\u044C\u043A\u0430 \u0444\u0430\u0439\u043B\u0456\u0432.</p>\n }\n </div>\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"ghost\" [disabled]=\"isUploading()\" (click)=\"close()\">\u0421\u043A\u0430\u0441\u0443\u0432\u0430\u0442\u0438</ui-button>\n <ui-button variant=\"primary\" [disabled]=\"isUploading()\" (click)=\"submitUpload()\">\n {{ isUploading() ? '\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...' : '\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438' }}\n </ui-button>\n </div>\n</core-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiModalComponent, selector: "core-modal", inputs: ["isOpen", "title", "size", "position", "closable", "closeOnBackdrop", "closeOnEscape"], outputs: ["closed"] }, { kind: "component", type: InputSelectComponent, selector: "input-select", inputs: ["label", "hint", "error", "placeholder", "name", "data", "dataParams", "required", "disabled", "multiple", "emptyStateLabel", "searchable", "options", "triggerClass", "panelClass"], outputs: ["valueChange", "searchChange"] }] });
|
|
1253
1269
|
}
|
|
1254
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1270
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsUploadModalComponent, decorators: [{
|
|
1255
1271
|
type: Component,
|
|
1256
|
-
args: [{ selector: 'app-documents-upload-modal', standalone: true, imports: [CommonModule, FormsModule,
|
|
1272
|
+
args: [{ selector: 'app-documents-upload-modal', standalone: true, imports: [CommonModule, FormsModule, LucideDynamicIcon, UiButtonComponent, UiModalComponent, InputSelectComponent], template: "<core-modal\n title=\"\u0414\u043E\u0434\u0430\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-4\">\n <input-select\n [data]=\"'doc_type'\"\n name=\"uploadDocumentTypeId\"\n label=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n hint=\"\u041D\u0435\u043E\u0431\u043E\u0432'\u044F\u0437\u043A\u043E\u0432\u043E\"\n [ngModel]=\"documentTypeId()\"\n (ngModelChange)=\"onDocumentTypeChange($event)\"\n placeholder=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n [searchable]=\"true\"\n ></input-select>\n\n <div class=\"space-y-2\">\n <label class=\"block text-sm font-medium text-slate-700\" for=\"document-files\">\u0424\u0430\u0439\u043B\u0438</label>\n <input\n #uploadFileInput\n id=\"document-files\"\n type=\"file\"\n class=\"block w-full rounded-xl border border-slate-200 bg-white px-3 py-2.5 text-sm text-slate-900 outline-none transition file:mr-3 file:rounded-lg file:border-0 file:bg-slate-900 file:px-3 file:py-2 file:text-sm file:font-medium file:text-white focus:border-slate-400 focus:ring-2 focus:ring-slate-200\"\n multiple\n (change)=\"onFilesSelected($event)\"\n />\n @if (fileNames().length) {\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-600\">\n @for (fileName of fileNames(); track fileName) {\n <div class=\"truncate\">{{ fileName }}</div>\n }\n </div>\n } @else {\n <p class=\"text-xs text-slate-500\">\u041C\u043E\u0436\u043D\u0430 \u043E\u0431\u0440\u0430\u0442\u0438 \u043E\u0434\u0438\u043D \u0430\u0431\u043E \u0434\u0435\u043A\u0456\u043B\u044C\u043A\u0430 \u0444\u0430\u0439\u043B\u0456\u0432.</p>\n }\n </div>\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"ghost\" [disabled]=\"isUploading()\" (click)=\"close()\">\u0421\u043A\u0430\u0441\u0443\u0432\u0430\u0442\u0438</ui-button>\n <ui-button variant=\"primary\" [disabled]=\"isUploading()\" (click)=\"submitUpload()\">\n {{ isUploading() ? '\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...' : '\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438' }}\n </ui-button>\n </div>\n</core-modal>\n" }]
|
|
1257
1273
|
}], propDecorators: { isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], saved: [{ type: i0.Output, args: ["saved"] }], uploadFileInput: [{
|
|
1258
1274
|
type: ViewChild,
|
|
1259
1275
|
args: ['uploadFileInput']
|
|
@@ -1297,10 +1313,10 @@ class DocumentsTextModalComponent {
|
|
|
1297
1313
|
.replace(/"/g, '"')
|
|
1298
1314
|
.replace(/'/g, ''');
|
|
1299
1315
|
}
|
|
1300
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1301
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1316
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsTextModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1317
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DocumentsTextModalComponent, isStandalone: true, selector: "app-documents-text-modal", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, document: { classPropertyName: "document", publicName: "document", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", recognizeRequested: "recognizeRequested" }, ngImport: i0, template: "<core-modal\n title=\"\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456 \u0434\u0430\u043D\u0456\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-3\">\n @if (hasDocumentHtml()) {\n <div\n class=\"max-h-[32rem] overflow-auto rounded-xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm text-slate-900\"\n [innerHTML]=\"getDocumentHtml()\"\n ></div>\n } @else {\n <div class=\"rounded-xl border border-dashed border-slate-200 bg-slate-50 px-4 py-6 text-sm text-slate-500\">\n \u0414\u0430\u043D\u0456 \u0449\u0435 \u043D\u0435 \u0440\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456. \u041D\u0430\u0442\u0438\u0441\u043D\u0438 \u201C\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456\u201D.\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n @if (isImage()) {\n <ui-button variant=\"secondary\" (click)=\"requestRecognize()\">\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0449\u0435 \u0440\u0430\u0437</ui-button>\n }\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiModalComponent, selector: "core-modal", inputs: ["isOpen", "title", "size", "position", "closable", "closeOnBackdrop", "closeOnEscape"], outputs: ["closed"] }] });
|
|
1302
1318
|
}
|
|
1303
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsTextModalComponent, decorators: [{
|
|
1304
1320
|
type: Component,
|
|
1305
1321
|
args: [{ selector: 'app-documents-text-modal', standalone: true, imports: [CommonModule, UiButtonComponent, UiModalComponent], template: "<core-modal\n title=\"\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456 \u0434\u0430\u043D\u0456\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-3\">\n @if (hasDocumentHtml()) {\n <div\n class=\"max-h-[32rem] overflow-auto rounded-xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm text-slate-900\"\n [innerHTML]=\"getDocumentHtml()\"\n ></div>\n } @else {\n <div class=\"rounded-xl border border-dashed border-slate-200 bg-slate-50 px-4 py-6 text-sm text-slate-500\">\n \u0414\u0430\u043D\u0456 \u0449\u0435 \u043D\u0435 \u0440\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456. \u041D\u0430\u0442\u0438\u0441\u043D\u0438 \u201C\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456\u201D.\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n @if (isImage()) {\n <ui-button variant=\"secondary\" (click)=\"requestRecognize()\">\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0449\u0435 \u0440\u0430\u0437</ui-button>\n }\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n" }]
|
|
1306
1322
|
}], propDecorators: { isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], document: [{ type: i0.Input, args: [{ isSignal: true, alias: "document", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], recognizeRequested: [{ type: i0.Output, args: ["recognizeRequested"] }] } });
|
|
@@ -1316,10 +1332,10 @@ class DocumentsImagePreviewModalComponent {
|
|
|
1316
1332
|
const match = String(url || '').match(/^(.*\/api\/files\/[^/?#]+)(?:\?.*)?$/i);
|
|
1317
1333
|
return match ? `${match[1]}/preview?scale=25` : url;
|
|
1318
1334
|
}
|
|
1319
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1320
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1335
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsImagePreviewModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1336
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DocumentsImagePreviewModalComponent, isStandalone: true, selector: "app-documents-image-preview-modal", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, document: { classPropertyName: "document", publicName: "document", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: "<core-modal\n [title]=\"document()?.name || '\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430'\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n @if (document()) {\n <div class=\"overflow-hidden rounded-2xl bg-slate-100\">\n <img\n [src]=\"getPreviewUrl(document()!.downloadUrl)\"\n [alt]=\"document()!.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\"\n decoding=\"async\"\n class=\"max-h-[75vh] w-full object-contain\"\n >\n </div>\n }\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiModalComponent, selector: "core-modal", inputs: ["isOpen", "title", "size", "position", "closable", "closeOnBackdrop", "closeOnEscape"], outputs: ["closed"] }] });
|
|
1321
1337
|
}
|
|
1322
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1338
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsImagePreviewModalComponent, decorators: [{
|
|
1323
1339
|
type: Component,
|
|
1324
1340
|
args: [{ selector: 'app-documents-image-preview-modal', standalone: true, imports: [CommonModule, UiButtonComponent, UiModalComponent], template: "<core-modal\n [title]=\"document()?.name || '\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430'\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n @if (document()) {\n <div class=\"overflow-hidden rounded-2xl bg-slate-100\">\n <img\n [src]=\"getPreviewUrl(document()!.downloadUrl)\"\n [alt]=\"document()!.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\"\n decoding=\"async\"\n class=\"max-h-[75vh] w-full object-contain\"\n >\n </div>\n }\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n" }]
|
|
1325
1341
|
}], propDecorators: { isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], document: [{ type: i0.Input, args: [{ isSignal: true, alias: "document", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
@@ -1340,11 +1356,11 @@ class DocumentsComponent {
|
|
|
1340
1356
|
textTarget = signal(null, ...(ngDevMode ? [{ debugName: "textTarget" }] : /* istanbul ignore next */ []));
|
|
1341
1357
|
imagePreviewTarget = signal(null, ...(ngDevMode ? [{ debugName: "imagePreviewTarget" }] : /* istanbul ignore next */ []));
|
|
1342
1358
|
deletingDocumentId = signal(null, ...(ngDevMode ? [{ debugName: "deletingDocumentId" }] : /* istanbul ignore next */ []));
|
|
1343
|
-
eyeIcon =
|
|
1344
|
-
fileIcon =
|
|
1345
|
-
plusIcon =
|
|
1346
|
-
sparkleIcon =
|
|
1347
|
-
deleteIcon =
|
|
1359
|
+
eyeIcon = LucideEye;
|
|
1360
|
+
fileIcon = LucideFileText;
|
|
1361
|
+
plusIcon = LucidePlus;
|
|
1362
|
+
sparkleIcon = LucideSparkles;
|
|
1363
|
+
deleteIcon = LucideTrash;
|
|
1348
1364
|
isAdmin = toSignal(inject(CardCurrentUserService).getCurrentUser().pipe(map$1((user) => String(user.role || '').trim().toUpperCase() === 'ADMIN')), { initialValue: false });
|
|
1349
1365
|
documentsService = inject(UiEntityDocumentsService);
|
|
1350
1366
|
dictionaryService = inject(CardDictionaryService);
|
|
@@ -1596,19 +1612,19 @@ class DocumentsComponent {
|
|
|
1596
1612
|
}))
|
|
1597
1613
|
.subscribe();
|
|
1598
1614
|
}
|
|
1599
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1600
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DocumentsComponent, isStandalone: true, selector: "app-documents", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"space-y-4\">\n <div>\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432...\n </div>\n } @else if (documents().length === 0) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456\n </div>\n } @else {\n <div class=\"grid gap-3\">\n @for (document of documents(); track trackDocument($index, document)) {\n <article class=\"flex flex-col gap-4 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between\">\n @if (isImage(document)) {\n <button\n type=\"button\"\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100 h-28 w-40\"\n (click)=\"openImagePreview(document)\"\n >\n <img [src]=\"getImagePreviewUrl(document)\" [alt]=\"document.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\" loading=\"lazy\" decoding=\"async\" class=\"h-full w-full object-cover\">\n </button>\n } @else {\n <a\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [class.h-28]=\"isPdf(document)\"\n [class.w-40]=\"isPdf(document)\"\n [class.h-20]=\"!isPdf(document)\"\n [class.w-24]=\"!isPdf(document)\"\n >\n @if (isPdf(document)) {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <lucide-icon [img]=\"fileIcon\"></lucide-icon>\n </div>\n <span class=\"text-xs font-semibold uppercase tracking-[0.18em] text-slate-600\">PDF</span>\n </div>\n } @else {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <lucide-icon [img]=\"fileIcon\"></lucide-icon>\n </div>\n <span class=\"text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500\">\n {{ getFileBadge(document) }}\n </span>\n </div>\n }\n </a>\n }\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex flex-col gap-2 lg:flex-row lg:items-start lg:justify-between\">\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <h4 class=\"truncate text-sm font-semibold text-slate-900\">\n {{ document.name || '\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0438' }}\n </h4>\n @if (getDocumentTypeLabel(document)) {\n <span class=\"inline-flex shrink-0 items-center rounded-full border border-sky-200 bg-sky-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.18em] text-sky-700\">\n {{ getDocumentTypeLabel(document) }}\n </span>\n }\n </div>\n <p class=\"mt-1 text-xs text-slate-500\">\n {{ formatSize(document.size) }} \u00B7 {{ document.type }}\n </p>\n </div>\n\n <div class=\"flex flex-wrap items-center gap-2\">\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"openTextModal(document)\">\n <lucide-icon [img]=\"eyeIcon\"></lucide-icon>\n \u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\n </ui-button>\n @if (isImage(document)) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"isDocumentRecognizing(document) || isRecognitionPending(document) || isRecognitionCompleted(document)\" (click)=\"recognizeText(document)\">\n <lucide-icon [img]=\"sparkleIcon\"></lucide-icon>\n {{ isDocumentRecognizing(document) ? '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0432\u0430\u043D\u043D\u044F...' : '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456' }}\n </ui-button>\n }\n @if (isAdmin()) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"deletingDocumentId() === document.id\" (click)=\"removeDocument(document)\">\n <lucide-icon [img]=\"deleteIcon\"></lucide-icon>\n {{ deletingDocumentId() === document.id ? '\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043D\u044F...' : '\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438' }}\n </ui-button>\n }\n </div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <a\n class=\"inline-flex items-center rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-medium text-slate-700 transition hover:border-slate-300 hover:bg-slate-50\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438\n </a>\n @if (isImage(document) && getRecognitionStatusLabel(document)) {\n <span\n class=\"inline-flex items-center rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em]\"\n [class.border-amber-200]=\"isRecognitionPending(document)\"\n [class.bg-amber-50]=\"isRecognitionPending(document)\"\n [class.text-amber-700]=\"isRecognitionPending(document)\"\n [class.border-rose-200]=\"document.recognitionStatus === 'FAILED'\"\n [class.bg-rose-50]=\"document.recognitionStatus === 'FAILED'\"\n [class.text-rose-700]=\"document.recognitionStatus === 'FAILED'\"\n [class.border-emerald-200]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.bg-emerald-50]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.text-emerald-700]=\"document.recognitionStatus === 'COMPLETED'\"\n >\n {{ getRecognitionStatusLabel(document) }}\n </span>\n }\n </div>\n </div>\n </article>\n }\n </div>\n }\n </div>\n\n <div class=\"flex flex-col gap-3 rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-4\">\n <div>\n <h4 class=\"text-sm font-semibold text-slate-900\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432 \u0443 \u0444\u0430\u0439\u043B\u043E\u0432\u0435 \u0441\u0445\u043E\u0432\u0438\u0449\u0435</h4>\n <p class=\"mt-1 text-xs text-slate-500\">\u0414\u043E\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u0432\u0456 \u0444\u0430\u0439\u043B\u0438 \u0434\u043E \u043A\u0430\u0440\u0442\u043A\u0438 \u0431\u0435\u0437\u043F\u043E\u0441\u0435\u0440\u0435\u0434\u043D\u044C\u043E \u0442\u0443\u0442.</p>\n </div>\n\n <div class=\"flex w-full flex-col gap-2 sm:w-auto\">\n <ui-button variant=\"secondary\" size=\"sm\" (click)=\"openUploadModal()\">\n <lucide-icon [img]=\"plusIcon\"></lucide-icon>\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\n </ui-button>\n </div>\n </div>\n</div>\n\n<app-documents-text-modal\n [isOpen]=\"isTextOpen()\"\n [document]=\"textTarget()\"\n (closed)=\"closeTextModal()\"\n (recognizeRequested)=\"textTarget() && recognizeText(textTarget()!)\"\n></app-documents-text-modal>\n\n<app-documents-upload-modal\n [isOpen]=\"isUploadOpen()\"\n [entity]=\"entity()\"\n [id]=\"id()\"\n (closed)=\"closeUploadModal()\"\n (saved)=\"reloadDocuments()\"\n></app-documents-upload-modal>\n\n<app-documents-image-preview-modal\n [isOpen]=\"isImagePreviewOpen()\"\n [document]=\"imagePreviewTarget()\"\n (closed)=\"closeImagePreview()\"\n></app-documents-image-preview-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: DocumentsUploadModalComponent, selector: "app-documents-upload-modal", inputs: ["isOpen", "entity", "id"], outputs: ["closed", "saved"] }, { kind: "component", type: DocumentsTextModalComponent, selector: "app-documents-text-modal", inputs: ["isOpen", "document"], outputs: ["closed", "recognizeRequested"] }, { kind: "component", type: DocumentsImagePreviewModalComponent, selector: "app-documents-image-preview-modal", inputs: ["isOpen", "document"], outputs: ["closed"] }] });
|
|
1615
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1616
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DocumentsComponent, isStandalone: true, selector: "app-documents", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"space-y-4\">\n <div>\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432...\n </div>\n } @else if (documents().length === 0) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456\n </div>\n } @else {\n <div class=\"grid gap-3\">\n @for (document of documents(); track trackDocument($index, document)) {\n <article class=\"flex flex-col gap-4 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between\">\n @if (isImage(document)) {\n <button\n type=\"button\"\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100 h-28 w-40\"\n (click)=\"openImagePreview(document)\"\n >\n <img [src]=\"getImagePreviewUrl(document)\" [alt]=\"document.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\" loading=\"lazy\" decoding=\"async\" class=\"h-full w-full object-cover\">\n </button>\n } @else {\n <a\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [class.h-28]=\"isPdf(document)\"\n [class.w-40]=\"isPdf(document)\"\n [class.h-20]=\"!isPdf(document)\"\n [class.w-24]=\"!isPdf(document)\"\n >\n @if (isPdf(document)) {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <svg [lucideIcon]=\"fileIcon\"></svg>\n </div>\n <span class=\"text-xs font-semibold uppercase tracking-[0.18em] text-slate-600\">PDF</span>\n </div>\n } @else {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <svg [lucideIcon]=\"fileIcon\"></svg>\n </div>\n <span class=\"text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500\">\n {{ getFileBadge(document) }}\n </span>\n </div>\n }\n </a>\n }\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex flex-col gap-2 lg:flex-row lg:items-start lg:justify-between\">\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <h4 class=\"truncate text-sm font-semibold text-slate-900\">\n {{ document.name || '\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0438' }}\n </h4>\n @if (getDocumentTypeLabel(document)) {\n <span class=\"inline-flex shrink-0 items-center rounded-full border border-sky-200 bg-sky-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.18em] text-sky-700\">\n {{ getDocumentTypeLabel(document) }}\n </span>\n }\n </div>\n <p class=\"mt-1 text-xs text-slate-500\">\n {{ formatSize(document.size) }} \u00B7 {{ document.type }}\n </p>\n </div>\n\n <div class=\"flex flex-wrap items-center gap-2\">\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"openTextModal(document)\">\n <svg [lucideIcon]=\"eyeIcon\"></svg>\n \u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\n </ui-button>\n @if (isImage(document)) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"isDocumentRecognizing(document) || isRecognitionPending(document) || isRecognitionCompleted(document)\" (click)=\"recognizeText(document)\">\n <svg [lucideIcon]=\"sparkleIcon\"></svg>\n {{ isDocumentRecognizing(document) ? '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0432\u0430\u043D\u043D\u044F...' : '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456' }}\n </ui-button>\n }\n @if (isAdmin()) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"deletingDocumentId() === document.id\" (click)=\"removeDocument(document)\">\n <svg [lucideIcon]=\"deleteIcon\"></svg>\n {{ deletingDocumentId() === document.id ? '\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043D\u044F...' : '\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438' }}\n </ui-button>\n }\n </div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <a\n class=\"inline-flex items-center rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-medium text-slate-700 transition hover:border-slate-300 hover:bg-slate-50\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438\n </a>\n @if (isImage(document) && getRecognitionStatusLabel(document)) {\n <span\n class=\"inline-flex items-center rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em]\"\n [class.border-amber-200]=\"isRecognitionPending(document)\"\n [class.bg-amber-50]=\"isRecognitionPending(document)\"\n [class.text-amber-700]=\"isRecognitionPending(document)\"\n [class.border-rose-200]=\"document.recognitionStatus === 'FAILED'\"\n [class.bg-rose-50]=\"document.recognitionStatus === 'FAILED'\"\n [class.text-rose-700]=\"document.recognitionStatus === 'FAILED'\"\n [class.border-emerald-200]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.bg-emerald-50]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.text-emerald-700]=\"document.recognitionStatus === 'COMPLETED'\"\n >\n {{ getRecognitionStatusLabel(document) }}\n </span>\n }\n </div>\n </div>\n </article>\n }\n </div>\n }\n </div>\n\n <div class=\"flex flex-col gap-3 rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-4\">\n <div>\n <h4 class=\"text-sm font-semibold text-slate-900\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432 \u0443 \u0444\u0430\u0439\u043B\u043E\u0432\u0435 \u0441\u0445\u043E\u0432\u0438\u0449\u0435</h4>\n <p class=\"mt-1 text-xs text-slate-500\">\u0414\u043E\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u0432\u0456 \u0444\u0430\u0439\u043B\u0438 \u0434\u043E \u043A\u0430\u0440\u0442\u043A\u0438 \u0431\u0435\u0437\u043F\u043E\u0441\u0435\u0440\u0435\u0434\u043D\u044C\u043E \u0442\u0443\u0442.</p>\n </div>\n\n <div class=\"flex w-full flex-col gap-2 sm:w-auto\">\n <ui-button variant=\"secondary\" size=\"sm\" (click)=\"openUploadModal()\">\n <svg [lucideIcon]=\"plusIcon\"></svg>\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\n </ui-button>\n </div>\n </div>\n</div>\n\n<app-documents-text-modal\n [isOpen]=\"isTextOpen()\"\n [document]=\"textTarget()\"\n (closed)=\"closeTextModal()\"\n (recognizeRequested)=\"textTarget() && recognizeText(textTarget()!)\"\n></app-documents-text-modal>\n\n<app-documents-upload-modal\n [isOpen]=\"isUploadOpen()\"\n [entity]=\"entity()\"\n [id]=\"id()\"\n (closed)=\"closeUploadModal()\"\n (saved)=\"reloadDocuments()\"\n></app-documents-upload-modal>\n\n<app-documents-image-preview-modal\n [isOpen]=\"isImagePreviewOpen()\"\n [document]=\"imagePreviewTarget()\"\n (closed)=\"closeImagePreview()\"\n></app-documents-image-preview-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: DocumentsUploadModalComponent, selector: "app-documents-upload-modal", inputs: ["isOpen", "entity", "id"], outputs: ["closed", "saved"] }, { kind: "component", type: DocumentsTextModalComponent, selector: "app-documents-text-modal", inputs: ["isOpen", "document"], outputs: ["closed", "recognizeRequested"] }, { kind: "component", type: DocumentsImagePreviewModalComponent, selector: "app-documents-image-preview-modal", inputs: ["isOpen", "document"], outputs: ["closed"] }] });
|
|
1601
1617
|
}
|
|
1602
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1618
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsComponent, decorators: [{
|
|
1603
1619
|
type: Component,
|
|
1604
1620
|
args: [{ selector: 'app-documents', standalone: true, imports: [
|
|
1605
1621
|
CommonModule,
|
|
1606
|
-
|
|
1622
|
+
LucideDynamicIcon,
|
|
1607
1623
|
UiButtonComponent,
|
|
1608
1624
|
DocumentsUploadModalComponent,
|
|
1609
1625
|
DocumentsTextModalComponent,
|
|
1610
1626
|
DocumentsImagePreviewModalComponent,
|
|
1611
|
-
], template: "<div class=\"space-y-4\">\n <div>\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432...\n </div>\n } @else if (documents().length === 0) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456\n </div>\n } @else {\n <div class=\"grid gap-3\">\n @for (document of documents(); track trackDocument($index, document)) {\n <article class=\"flex flex-col gap-4 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between\">\n @if (isImage(document)) {\n <button\n type=\"button\"\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100 h-28 w-40\"\n (click)=\"openImagePreview(document)\"\n >\n <img [src]=\"getImagePreviewUrl(document)\" [alt]=\"document.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\" loading=\"lazy\" decoding=\"async\" class=\"h-full w-full object-cover\">\n </button>\n } @else {\n <a\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [class.h-28]=\"isPdf(document)\"\n [class.w-40]=\"isPdf(document)\"\n [class.h-20]=\"!isPdf(document)\"\n [class.w-24]=\"!isPdf(document)\"\n >\n @if (isPdf(document)) {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <
|
|
1627
|
+
], template: "<div class=\"space-y-4\">\n <div>\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432...\n </div>\n } @else if (documents().length === 0) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456\n </div>\n } @else {\n <div class=\"grid gap-3\">\n @for (document of documents(); track trackDocument($index, document)) {\n <article class=\"flex flex-col gap-4 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between\">\n @if (isImage(document)) {\n <button\n type=\"button\"\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100 h-28 w-40\"\n (click)=\"openImagePreview(document)\"\n >\n <img [src]=\"getImagePreviewUrl(document)\" [alt]=\"document.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\" loading=\"lazy\" decoding=\"async\" class=\"h-full w-full object-cover\">\n </button>\n } @else {\n <a\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [class.h-28]=\"isPdf(document)\"\n [class.w-40]=\"isPdf(document)\"\n [class.h-20]=\"!isPdf(document)\"\n [class.w-24]=\"!isPdf(document)\"\n >\n @if (isPdf(document)) {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <svg [lucideIcon]=\"fileIcon\"></svg>\n </div>\n <span class=\"text-xs font-semibold uppercase tracking-[0.18em] text-slate-600\">PDF</span>\n </div>\n } @else {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <svg [lucideIcon]=\"fileIcon\"></svg>\n </div>\n <span class=\"text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500\">\n {{ getFileBadge(document) }}\n </span>\n </div>\n }\n </a>\n }\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex flex-col gap-2 lg:flex-row lg:items-start lg:justify-between\">\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <h4 class=\"truncate text-sm font-semibold text-slate-900\">\n {{ document.name || '\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0438' }}\n </h4>\n @if (getDocumentTypeLabel(document)) {\n <span class=\"inline-flex shrink-0 items-center rounded-full border border-sky-200 bg-sky-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.18em] text-sky-700\">\n {{ getDocumentTypeLabel(document) }}\n </span>\n }\n </div>\n <p class=\"mt-1 text-xs text-slate-500\">\n {{ formatSize(document.size) }} \u00B7 {{ document.type }}\n </p>\n </div>\n\n <div class=\"flex flex-wrap items-center gap-2\">\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"openTextModal(document)\">\n <svg [lucideIcon]=\"eyeIcon\"></svg>\n \u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\n </ui-button>\n @if (isImage(document)) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"isDocumentRecognizing(document) || isRecognitionPending(document) || isRecognitionCompleted(document)\" (click)=\"recognizeText(document)\">\n <svg [lucideIcon]=\"sparkleIcon\"></svg>\n {{ isDocumentRecognizing(document) ? '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0432\u0430\u043D\u043D\u044F...' : '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456' }}\n </ui-button>\n }\n @if (isAdmin()) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"deletingDocumentId() === document.id\" (click)=\"removeDocument(document)\">\n <svg [lucideIcon]=\"deleteIcon\"></svg>\n {{ deletingDocumentId() === document.id ? '\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043D\u044F...' : '\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438' }}\n </ui-button>\n }\n </div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <a\n class=\"inline-flex items-center rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-medium text-slate-700 transition hover:border-slate-300 hover:bg-slate-50\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438\n </a>\n @if (isImage(document) && getRecognitionStatusLabel(document)) {\n <span\n class=\"inline-flex items-center rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em]\"\n [class.border-amber-200]=\"isRecognitionPending(document)\"\n [class.bg-amber-50]=\"isRecognitionPending(document)\"\n [class.text-amber-700]=\"isRecognitionPending(document)\"\n [class.border-rose-200]=\"document.recognitionStatus === 'FAILED'\"\n [class.bg-rose-50]=\"document.recognitionStatus === 'FAILED'\"\n [class.text-rose-700]=\"document.recognitionStatus === 'FAILED'\"\n [class.border-emerald-200]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.bg-emerald-50]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.text-emerald-700]=\"document.recognitionStatus === 'COMPLETED'\"\n >\n {{ getRecognitionStatusLabel(document) }}\n </span>\n }\n </div>\n </div>\n </article>\n }\n </div>\n }\n </div>\n\n <div class=\"flex flex-col gap-3 rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-4\">\n <div>\n <h4 class=\"text-sm font-semibold text-slate-900\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432 \u0443 \u0444\u0430\u0439\u043B\u043E\u0432\u0435 \u0441\u0445\u043E\u0432\u0438\u0449\u0435</h4>\n <p class=\"mt-1 text-xs text-slate-500\">\u0414\u043E\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u0432\u0456 \u0444\u0430\u0439\u043B\u0438 \u0434\u043E \u043A\u0430\u0440\u0442\u043A\u0438 \u0431\u0435\u0437\u043F\u043E\u0441\u0435\u0440\u0435\u0434\u043D\u044C\u043E \u0442\u0443\u0442.</p>\n </div>\n\n <div class=\"flex w-full flex-col gap-2 sm:w-auto\">\n <ui-button variant=\"secondary\" size=\"sm\" (click)=\"openUploadModal()\">\n <svg [lucideIcon]=\"plusIcon\"></svg>\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\n </ui-button>\n </div>\n </div>\n</div>\n\n<app-documents-text-modal\n [isOpen]=\"isTextOpen()\"\n [document]=\"textTarget()\"\n (closed)=\"closeTextModal()\"\n (recognizeRequested)=\"textTarget() && recognizeText(textTarget()!)\"\n></app-documents-text-modal>\n\n<app-documents-upload-modal\n [isOpen]=\"isUploadOpen()\"\n [entity]=\"entity()\"\n [id]=\"id()\"\n (closed)=\"closeUploadModal()\"\n (saved)=\"reloadDocuments()\"\n></app-documents-upload-modal>\n\n<app-documents-image-preview-modal\n [isOpen]=\"isImagePreviewOpen()\"\n [document]=\"imagePreviewTarget()\"\n (closed)=\"closeImagePreview()\"\n></app-documents-image-preview-modal>\n" }]
|
|
1612
1628
|
}], propDecorators: { entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
|
|
1613
1629
|
|
|
1614
1630
|
class HistoryTabComponent {
|
|
@@ -1870,10 +1886,10 @@ class HistoryTabComponent {
|
|
|
1870
1886
|
? (operation.changes || []).filter((change) => !primaryTypes.has(change.entityType))
|
|
1871
1887
|
: operation.changes || [];
|
|
1872
1888
|
}
|
|
1873
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1874
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: HistoryTabComponent, isStandalone: true, selector: "app-history-tab", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<section class=\"space-y-4\">\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0456\u0441\u0442\u043E\u0440\u0456\u0457\u2026\n </div>\n } @else if (hasError()) {\n <div class=\"rounded-2xl border border-red-200 bg-red-50 p-6 text-sm text-red-700\">\n \u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0456\u0441\u0442\u043E\u0440\u0456\u044E \u0437\u043C\u0456\u043D.\n </div>\n } @else if (!operations().length) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0406\u0441\u0442\u043E\u0440\u0456\u044F \u0437\u043C\u0456\u043D \u043F\u043E\u043A\u0438 \u043F\u043E\u0440\u043E\u0436\u043D\u044F.\n </div>\n } @else {\n <div class=\"space-y-3\">\n @for (operation of operations(); track operation.id) {\n <article class=\"rounded-2xl border border-slate-200 bg-white p-5 shadow-sm\">\n <div class=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h3 class=\"text-sm font-semibold text-slate-900\">{{ operation.description }}</h3>\n @if (operation.actorName) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ operation.actorName }}</p>\n }\n </div>\n <time class=\"text-xs text-slate-400\" [dateTime]=\"operation.createdAt\">\n {{ operation.createdAt | date: 'dd.MM.yyyy HH:mm' }}\n </time>\n </div>\n\n @if (getPrimaryChanges(operation).length) {\n <div class=\"mt-4 space-y-2 border-t border-slate-100 pt-4\">\n @for (change of getPrimaryChanges(operation); track change.entityId + change.entityType) {\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n }\n </div>\n }\n\n @if (getRelatedChanges(operation).length) {\n <div class=\"mt-4 border-t border-slate-100 pt-4\">\n <button\n type=\"button\"\n class=\"flex w-full items-center justify-between gap-3 text-left text-sm text-slate-600\"\n [attr.aria-expanded]=\"isExpanded(operation.id)\"\n (click)=\"toggleOperation(operation.id)\"\n >\n <span>\n \u0414\u0435\u0442\u0430\u043B\u0456 \u0437\u043C\u0456\u043D:\n <span class=\"font-medium text-slate-900\">{{ getAffectedSummary(operation) }}</span>\n </span>\n <span class=\"text-lg leading-none text-slate-400\">{{ isExpanded(operation.id) ? '\u2212' : '+' }}</span>\n </button>\n\n @if (isExpanded(operation.id)) {\n <div class=\"mt-4 space-y-4\">\n @for (change of getRelatedChanges(operation); track change.entityId + change.entityType) {\n <div class=\"rounded-xl bg-slate-50 p-3\">\n <p class=\"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500\">\n {{ getEntityLabel(change.entityType) }} \u00B7 {{ getActionLabel(change.action) }}\n </p>\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"text-slate-400\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </article>\n }\n </div>\n }\n</section>\n\n@if (isViewerOpen()) {\n <app-images-viewer [urls]=\"viewerUrls()\" (closed)=\"closeImageViewer()\" />\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1$1.DatePipe, name: "date" }, { kind: "pipe", type: i1$1.KeyValuePipe, name: "keyvalue" }] });
|
|
1889
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HistoryTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1890
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: HistoryTabComponent, isStandalone: true, selector: "app-history-tab", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<section class=\"space-y-4\">\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0456\u0441\u0442\u043E\u0440\u0456\u0457\u2026\n </div>\n } @else if (hasError()) {\n <div class=\"rounded-2xl border border-red-200 bg-red-50 p-6 text-sm text-red-700\">\n \u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0456\u0441\u0442\u043E\u0440\u0456\u044E \u0437\u043C\u0456\u043D.\n </div>\n } @else if (!operations().length) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0406\u0441\u0442\u043E\u0440\u0456\u044F \u0437\u043C\u0456\u043D \u043F\u043E\u043A\u0438 \u043F\u043E\u0440\u043E\u0436\u043D\u044F.\n </div>\n } @else {\n <div class=\"space-y-3\">\n @for (operation of operations(); track operation.id) {\n <article class=\"rounded-2xl border border-slate-200 bg-white p-5 shadow-sm\">\n <div class=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h3 class=\"text-sm font-semibold text-slate-900\">{{ operation.description }}</h3>\n @if (operation.actorName) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ operation.actorName }}</p>\n }\n </div>\n <time class=\"text-xs text-slate-400\" [dateTime]=\"operation.createdAt\">\n {{ operation.createdAt | date: 'dd.MM.yyyy HH:mm' }}\n </time>\n </div>\n\n @if (getPrimaryChanges(operation).length) {\n <div class=\"mt-4 space-y-2 border-t border-slate-100 pt-4\">\n @for (change of getPrimaryChanges(operation); track change.entityId + change.entityType) {\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n }\n </div>\n }\n\n @if (getRelatedChanges(operation).length) {\n <div class=\"mt-4 border-t border-slate-100 pt-4\">\n <button\n type=\"button\"\n class=\"flex w-full items-center justify-between gap-3 text-left text-sm text-slate-600\"\n [attr.aria-expanded]=\"isExpanded(operation.id)\"\n (click)=\"toggleOperation(operation.id)\"\n >\n <span>\n \u0414\u0435\u0442\u0430\u043B\u0456 \u0437\u043C\u0456\u043D:\n <span class=\"font-medium text-slate-900\">{{ getAffectedSummary(operation) }}</span>\n </span>\n <span class=\"text-lg leading-none text-slate-400\">{{ isExpanded(operation.id) ? '\u2212' : '+' }}</span>\n </button>\n\n @if (isExpanded(operation.id)) {\n <div class=\"mt-4 space-y-4\">\n @for (change of getRelatedChanges(operation); track change.entityId + change.entityType) {\n <div class=\"rounded-xl bg-slate-50 p-3\">\n <p class=\"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500\">\n {{ getEntityLabel(change.entityType) }} \u00B7 {{ getActionLabel(change.action) }}\n </p>\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"text-slate-400\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </article>\n }\n </div>\n }\n</section>\n\n@if (isViewerOpen()) {\n <app-images-viewer [urls]=\"viewerUrls()\" (closed)=\"closeImageViewer()\" />\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }] });
|
|
1875
1891
|
}
|
|
1876
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1892
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HistoryTabComponent, decorators: [{
|
|
1877
1893
|
type: Component,
|
|
1878
1894
|
args: [{ selector: 'app-history-tab', standalone: true, imports: [CommonModule, ImagesViewerComponent, RouterLink], template: "<section class=\"space-y-4\">\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0456\u0441\u0442\u043E\u0440\u0456\u0457\u2026\n </div>\n } @else if (hasError()) {\n <div class=\"rounded-2xl border border-red-200 bg-red-50 p-6 text-sm text-red-700\">\n \u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0456\u0441\u0442\u043E\u0440\u0456\u044E \u0437\u043C\u0456\u043D.\n </div>\n } @else if (!operations().length) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0406\u0441\u0442\u043E\u0440\u0456\u044F \u0437\u043C\u0456\u043D \u043F\u043E\u043A\u0438 \u043F\u043E\u0440\u043E\u0436\u043D\u044F.\n </div>\n } @else {\n <div class=\"space-y-3\">\n @for (operation of operations(); track operation.id) {\n <article class=\"rounded-2xl border border-slate-200 bg-white p-5 shadow-sm\">\n <div class=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h3 class=\"text-sm font-semibold text-slate-900\">{{ operation.description }}</h3>\n @if (operation.actorName) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ operation.actorName }}</p>\n }\n </div>\n <time class=\"text-xs text-slate-400\" [dateTime]=\"operation.createdAt\">\n {{ operation.createdAt | date: 'dd.MM.yyyy HH:mm' }}\n </time>\n </div>\n\n @if (getPrimaryChanges(operation).length) {\n <div class=\"mt-4 space-y-2 border-t border-slate-100 pt-4\">\n @for (change of getPrimaryChanges(operation); track change.entityId + change.entityType) {\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n }\n </div>\n }\n\n @if (getRelatedChanges(operation).length) {\n <div class=\"mt-4 border-t border-slate-100 pt-4\">\n <button\n type=\"button\"\n class=\"flex w-full items-center justify-between gap-3 text-left text-sm text-slate-600\"\n [attr.aria-expanded]=\"isExpanded(operation.id)\"\n (click)=\"toggleOperation(operation.id)\"\n >\n <span>\n \u0414\u0435\u0442\u0430\u043B\u0456 \u0437\u043C\u0456\u043D:\n <span class=\"font-medium text-slate-900\">{{ getAffectedSummary(operation) }}</span>\n </span>\n <span class=\"text-lg leading-none text-slate-400\">{{ isExpanded(operation.id) ? '\u2212' : '+' }}</span>\n </button>\n\n @if (isExpanded(operation.id)) {\n <div class=\"mt-4 space-y-4\">\n @for (change of getRelatedChanges(operation); track change.entityId + change.entityType) {\n <div class=\"rounded-xl bg-slate-50 p-3\">\n <p class=\"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500\">\n {{ getEntityLabel(change.entityType) }} \u00B7 {{ getActionLabel(change.action) }}\n </p>\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"text-slate-400\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </article>\n }\n </div>\n }\n</section>\n\n@if (isViewerOpen()) {\n <app-images-viewer [urls]=\"viewerUrls()\" (closed)=\"closeImageViewer()\" />\n}\n" }]
|
|
1879
1895
|
}], ctorParameters: () => [], propDecorators: { entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
|