@shival99/z-ui 2.1.29 → 2.1.30

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.
Files changed (68) hide show
  1. package/fesm2022/shival99-z-ui-components-z-autocomplete.mjs +1079 -0
  2. package/fesm2022/shival99-z-ui-components-z-autocomplete.mjs.map +1 -0
  3. package/fesm2022/shival99-z-ui-components-z-drawer.mjs +742 -0
  4. package/fesm2022/shival99-z-ui-components-z-drawer.mjs.map +1 -0
  5. package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs +58 -0
  6. package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs.map +1 -0
  7. package/fesm2022/shival99-z-ui-components-z-editor.mjs +1750 -0
  8. package/fesm2022/shival99-z-ui-components-z-editor.mjs.map +1 -0
  9. package/fesm2022/shival99-z-ui-components-z-gallery.mjs +2419 -0
  10. package/fesm2022/shival99-z-ui-components-z-gallery.mjs.map +1 -0
  11. package/fesm2022/shival99-z-ui-components-z-kanban.mjs +981 -0
  12. package/fesm2022/shival99-z-ui-components-z-kanban.mjs.map +1 -0
  13. package/fesm2022/shival99-z-ui-components-z-marquee.mjs +70 -0
  14. package/fesm2022/shival99-z-ui-components-z-marquee.mjs.map +1 -0
  15. package/fesm2022/shival99-z-ui-components-z-media-player.mjs +668 -0
  16. package/fesm2022/shival99-z-ui-components-z-media-player.mjs.map +1 -0
  17. package/fesm2022/shival99-z-ui-components-z-menu.mjs +843 -0
  18. package/fesm2022/shival99-z-ui-components-z-menu.mjs.map +1 -0
  19. package/fesm2022/shival99-z-ui-components-z-metric-card.mjs +128 -0
  20. package/fesm2022/shival99-z-ui-components-z-metric-card.mjs.map +1 -0
  21. package/fesm2022/shival99-z-ui-components-z-pagination.mjs +158 -0
  22. package/fesm2022/shival99-z-ui-components-z-pagination.mjs.map +1 -0
  23. package/fesm2022/shival99-z-ui-components-z-qrcode.mjs +383 -0
  24. package/fesm2022/shival99-z-ui-components-z-qrcode.mjs.map +1 -0
  25. package/fesm2022/shival99-z-ui-components-z-radio.mjs +167 -0
  26. package/fesm2022/shival99-z-ui-components-z-radio.mjs.map +1 -0
  27. package/fesm2022/shival99-z-ui-components-z-scrollarea.mjs +131 -0
  28. package/fesm2022/shival99-z-ui-components-z-scrollarea.mjs.map +1 -0
  29. package/fesm2022/shival99-z-ui-components-z-show-more.mjs +121 -0
  30. package/fesm2022/shival99-z-ui-components-z-show-more.mjs.map +1 -0
  31. package/fesm2022/shival99-z-ui-components-z-skeleton-auto.mjs +61 -0
  32. package/fesm2022/shival99-z-ui-components-z-skeleton-auto.mjs.map +1 -0
  33. package/fesm2022/shival99-z-ui-components-z-steps.mjs +396 -0
  34. package/fesm2022/shival99-z-ui-components-z-steps.mjs.map +1 -0
  35. package/fesm2022/shival99-z-ui-components-z-table.mjs +10510 -0
  36. package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -0
  37. package/fesm2022/shival99-z-ui-components-z-tabs.mjs +507 -0
  38. package/fesm2022/shival99-z-ui-components-z-tabs.mjs.map +1 -0
  39. package/fesm2022/shival99-z-ui-components-z-tags.mjs +349 -0
  40. package/fesm2022/shival99-z-ui-components-z-tags.mjs.map +1 -0
  41. package/fesm2022/shival99-z-ui-components-z-timeline.mjs +237 -0
  42. package/fesm2022/shival99-z-ui-components-z-timeline.mjs.map +1 -0
  43. package/fesm2022/shival99-z-ui-components-z-upload.mjs +523 -0
  44. package/fesm2022/shival99-z-ui-components-z-upload.mjs.map +1 -0
  45. package/package.json +1 -1
  46. package/types/shival99-z-ui-components-z-autocomplete.d.ts +290 -0
  47. package/types/shival99-z-ui-components-z-calendar.d.ts +4 -4
  48. package/types/shival99-z-ui-components-z-drawer.d.ts +266 -0
  49. package/types/shival99-z-ui-components-z-dropdown-menu.d.ts +54 -0
  50. package/types/shival99-z-ui-components-z-editor.d.ts +337 -0
  51. package/types/shival99-z-ui-components-z-gallery.d.ts +402 -0
  52. package/types/shival99-z-ui-components-z-kanban.d.ts +237 -0
  53. package/types/shival99-z-ui-components-z-marquee.d.ts +35 -0
  54. package/types/shival99-z-ui-components-z-media-player.d.ts +124 -0
  55. package/types/shival99-z-ui-components-z-menu.d.ts +222 -0
  56. package/types/shival99-z-ui-components-z-metric-card.d.ts +67 -0
  57. package/types/shival99-z-ui-components-z-pagination.d.ts +55 -0
  58. package/types/shival99-z-ui-components-z-qrcode.d.ts +76 -0
  59. package/types/shival99-z-ui-components-z-radio.d.ts +69 -0
  60. package/types/shival99-z-ui-components-z-scrollarea.d.ts +46 -0
  61. package/types/shival99-z-ui-components-z-show-more.d.ts +36 -0
  62. package/types/shival99-z-ui-components-z-skeleton-auto.d.ts +35 -0
  63. package/types/shival99-z-ui-components-z-steps.d.ts +106 -0
  64. package/types/shival99-z-ui-components-z-table.d.ts +1924 -0
  65. package/types/shival99-z-ui-components-z-tabs.d.ts +92 -0
  66. package/types/shival99-z-ui-components-z-tags.d.ts +128 -0
  67. package/types/shival99-z-ui-components-z-timeline.d.ts +71 -0
  68. package/types/shival99-z-ui-components-z-upload.d.ts +153 -0
@@ -0,0 +1,2419 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, output, signal, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, inject, viewChild, effect, EventEmitter, Injector, PLATFORM_ID, Injectable, DestroyRef, model, ElementRef, Directive } from '@angular/core';
3
+ import * as i1$1 from '@angular/forms';
4
+ import { FormsModule } from '@angular/forms';
5
+ import { TranslatePipe } from '@ngx-translate/core';
6
+ import { ZButtonComponent } from '@shival99/z-ui/components/z-button';
7
+ import { ZButtonGroupComponent, ZButtonGroupItemDirective } from '@shival99/z-ui/components/z-button-group';
8
+ import { ZCheckboxComponent } from '@shival99/z-ui/components/z-checkbox';
9
+ import { ZEmptyComponent } from '@shival99/z-ui/components/z-empty';
10
+ import { ZIconComponent } from '@shival99/z-ui/components/z-icon';
11
+ import { ZInputComponent } from '@shival99/z-ui/components/z-input';
12
+ import { ZSkeletonComponent } from '@shival99/z-ui/components/z-skeleton';
13
+ import { zMergeClasses, zTransform } from '@shival99/z-ui/utils';
14
+ import { ZTooltipDirective } from '@shival99/z-ui/components/z-tooltip';
15
+ import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
16
+ import { ComponentPortal } from '@angular/cdk/portal';
17
+ import { DOCUMENT, isPlatformBrowser } from '@angular/common';
18
+ import { ZOverlayZIndexService } from '@shival99/z-ui/services';
19
+ import { DomSanitizer } from '@angular/platform-browser';
20
+ import * as i1 from 'ng2-pdfjs-viewer';
21
+ import { PdfJsViewerModule } from 'ng2-pdfjs-viewer';
22
+ import { cva } from 'class-variance-authority';
23
+
24
+ const FILE_CATEGORY_STYLES = {
25
+ image: {
26
+ bg: 'bg-purple-100 dark:bg-purple-900/30',
27
+ text: 'text-purple-600 dark:text-purple-400',
28
+ label: 'IMG',
29
+ icon: 'lucideImage',
30
+ },
31
+ pdf: {
32
+ bg: 'bg-red-100 dark:bg-red-900/30',
33
+ text: 'text-red-600 dark:text-red-400',
34
+ label: 'PDF',
35
+ icon: 'lucideFileText',
36
+ },
37
+ word: {
38
+ bg: 'bg-blue-100 dark:bg-blue-900/30',
39
+ text: 'text-blue-600 dark:text-blue-400',
40
+ label: 'DOC',
41
+ icon: 'lucideFileText',
42
+ },
43
+ excel: {
44
+ bg: 'bg-green-100 dark:bg-green-900/30',
45
+ text: 'text-green-600 dark:text-green-400',
46
+ label: 'XLS',
47
+ icon: 'lucideFileSpreadsheet',
48
+ },
49
+ powerpoint: {
50
+ bg: 'bg-orange-100 dark:bg-orange-900/30',
51
+ text: 'text-orange-600 dark:text-orange-400',
52
+ label: 'PPT',
53
+ icon: 'lucideFileText',
54
+ },
55
+ video: {
56
+ bg: 'bg-pink-100 dark:bg-pink-900/30',
57
+ text: 'text-pink-600 dark:text-pink-400',
58
+ label: 'VID',
59
+ icon: 'lucideVideo',
60
+ },
61
+ audio: {
62
+ bg: 'bg-yellow-100 dark:bg-yellow-900/30',
63
+ text: 'text-yellow-700 dark:text-yellow-400',
64
+ label: 'AUD',
65
+ icon: 'lucideMusic',
66
+ },
67
+ archive: {
68
+ bg: 'bg-amber-100 dark:bg-amber-900/30',
69
+ text: 'text-amber-600 dark:text-amber-400',
70
+ label: 'ZIP',
71
+ icon: 'lucideFileArchive',
72
+ },
73
+ code: {
74
+ bg: 'bg-slate-100 dark:bg-slate-800',
75
+ text: 'text-slate-600 dark:text-slate-400',
76
+ label: 'CODE',
77
+ icon: 'lucideCode',
78
+ },
79
+ text: {
80
+ bg: 'bg-gray-100 dark:bg-gray-800',
81
+ text: 'text-gray-600 dark:text-gray-400',
82
+ label: 'TXT',
83
+ icon: 'lucideFileText',
84
+ },
85
+ unknown: {
86
+ bg: 'bg-gray-100 dark:bg-gray-800',
87
+ text: 'text-gray-500 dark:text-gray-400',
88
+ label: 'FILE',
89
+ icon: 'lucideFile',
90
+ },
91
+ };
92
+
93
+ const IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'ico'];
94
+ const VIDEO_EXTENSIONS = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv'];
95
+ const AUDIO_EXTENSIONS = ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a'];
96
+ const ARCHIVE_EXTENSIONS = ['zip', 'rar', 'tar', 'gz', '7z', 'bz2'];
97
+ const CODE_EXTENSIONS = [
98
+ 'js',
99
+ 'ts',
100
+ 'jsx',
101
+ 'tsx',
102
+ 'html',
103
+ 'css',
104
+ 'scss',
105
+ 'json',
106
+ 'xml',
107
+ 'py',
108
+ 'java',
109
+ 'c',
110
+ 'cpp',
111
+ 'go',
112
+ 'rs',
113
+ 'php',
114
+ 'rb',
115
+ 'swift',
116
+ 'kt',
117
+ ];
118
+ const TEXT_EXTENSIONS = ['txt', 'md', 'log'];
119
+ const WORD_EXTENSIONS = ['doc', 'docx', 'odt', 'rtf'];
120
+ const EXCEL_EXTENSIONS = ['xls', 'xlsx', 'csv', 'ods'];
121
+ const POWERPOINT_EXTENSIONS = ['ppt', 'pptx', 'odp'];
122
+ const FILE_SIZE_UNITS = ['B', 'KB', 'MB', 'GB'];
123
+ const FILE_SIZE_BASE = 1024;
124
+ const getFileCategory = (file) => {
125
+ const type = file.type?.toLowerCase() || '';
126
+ const name = file.name?.toLowerCase() || '';
127
+ const ext = name.split('.').pop() || '';
128
+ if (type.startsWith('image/') || IMAGE_EXTENSIONS.includes(ext)) {
129
+ return 'image';
130
+ }
131
+ if (type === 'application/pdf' || ext === 'pdf') {
132
+ return 'pdf';
133
+ }
134
+ if (type.includes('excel') || type.includes('spreadsheet') || EXCEL_EXTENSIONS.includes(ext)) {
135
+ return 'excel';
136
+ }
137
+ if (type.includes('powerpoint') || type.includes('presentation') || POWERPOINT_EXTENSIONS.includes(ext)) {
138
+ return 'powerpoint';
139
+ }
140
+ if (type.includes('word') || type.includes('wordprocessingml') || WORD_EXTENSIONS.includes(ext)) {
141
+ return 'word';
142
+ }
143
+ if (type.startsWith('video/') || VIDEO_EXTENSIONS.includes(ext)) {
144
+ return 'video';
145
+ }
146
+ if (type.startsWith('audio/') || AUDIO_EXTENSIONS.includes(ext)) {
147
+ return 'audio';
148
+ }
149
+ if (type.includes('zip') ||
150
+ type.includes('rar') ||
151
+ type.includes('tar') ||
152
+ type.includes('compressed') ||
153
+ ARCHIVE_EXTENSIONS.includes(ext)) {
154
+ return 'archive';
155
+ }
156
+ if (CODE_EXTENSIONS.includes(ext)) {
157
+ return 'code';
158
+ }
159
+ if (type.startsWith('text/') || TEXT_EXTENSIONS.includes(ext)) {
160
+ return 'text';
161
+ }
162
+ return 'unknown';
163
+ };
164
+ const formatFileSize = (bytes) => {
165
+ if (bytes === 0) {
166
+ return '0 B';
167
+ }
168
+ const i = Math.floor(Math.log(bytes) / Math.log(FILE_SIZE_BASE));
169
+ const size = bytes / Math.pow(FILE_SIZE_BASE, i);
170
+ return `${size.toFixed(i > 0 ? 1 : 0)} ${FILE_SIZE_UNITS[i]}`;
171
+ };
172
+ const isPreviewable = (file) => {
173
+ const category = getFileCategory(file);
174
+ return (category === 'image' ||
175
+ category === 'pdf' ||
176
+ category === 'video' ||
177
+ category === 'word' ||
178
+ category === 'excel' ||
179
+ category === 'text' ||
180
+ category === 'code');
181
+ };
182
+ const isImage = (file) => getFileCategory(file) === 'image';
183
+
184
+ class ZGalleryItemComponent {
185
+ file = input.required(...(ngDevMode ? [{ debugName: "file" }] : []));
186
+ zMode = input('grid', ...(ngDevMode ? [{ debugName: "zMode" }] : []));
187
+ zSize = input('default', ...(ngDevMode ? [{ debugName: "zSize" }] : []));
188
+ zShowDownload = input(true, ...(ngDevMode ? [{ debugName: "zShowDownload" }] : []));
189
+ zShowPreview = input(true, ...(ngDevMode ? [{ debugName: "zShowPreview" }] : []));
190
+ zShowRemove = input(false, ...(ngDevMode ? [{ debugName: "zShowRemove" }] : []));
191
+ zSelectable = input(false, ...(ngDevMode ? [{ debugName: "zSelectable" }] : []));
192
+ zSelected = input(false, ...(ngDevMode ? [{ debugName: "zSelected" }] : []));
193
+ zOnDownload = output();
194
+ zOnPreview = output();
195
+ zOnRemove = output();
196
+ zOnSelect = output();
197
+ isLoading = signal(true, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
198
+ formattedSize = computed(() => formatFileSize(this.file().size), ...(ngDevMode ? [{ debugName: "formattedSize" }] : []));
199
+ category = computed(() => getFileCategory(this.file()), ...(ngDevMode ? [{ debugName: "category" }] : []));
200
+ isImage = computed(() => this.category() === 'image', ...(ngDevMode ? [{ debugName: "isImage" }] : []));
201
+ isVideo = computed(() => this.category() === 'video', ...(ngDevMode ? [{ debugName: "isVideo" }] : []));
202
+ hasVideoPreview = computed(() => this.isVideo() && !!this.file().url, ...(ngDevMode ? [{ debugName: "hasVideoPreview" }] : []));
203
+ fileExtension = computed(() => {
204
+ const fileName = this.file().name;
205
+ const parts = fileName.split('.');
206
+ if (parts.length < 2) {
207
+ return 'FILE';
208
+ }
209
+ return parts[parts.length - 1].toUpperCase();
210
+ }, ...(ngDevMode ? [{ debugName: "fileExtension" }] : []));
211
+ mediaHeightClass = computed(() => {
212
+ const size = this.zSize();
213
+ switch (size) {
214
+ case 'sm':
215
+ return 'h-36';
216
+ case 'lg':
217
+ return 'h-56';
218
+ default:
219
+ return 'h-44';
220
+ }
221
+ }, ...(ngDevMode ? [{ debugName: "mediaHeightClass" }] : []));
222
+ formattedDate = computed(() => {
223
+ const file = this.file();
224
+ const date = file.updatedAt || file.createdAt;
225
+ if (!date) {
226
+ return null;
227
+ }
228
+ return new Intl.DateTimeFormat(undefined, {
229
+ month: 'short',
230
+ day: '2-digit',
231
+ year: 'numeric',
232
+ }).format(date);
233
+ }, ...(ngDevMode ? [{ debugName: "formattedDate" }] : []));
234
+ categoryStyle = computed(() => {
235
+ const style = FILE_CATEGORY_STYLES[this.category()];
236
+ return {
237
+ ...style,
238
+ icon: style.icon,
239
+ };
240
+ }, ...(ngDevMode ? [{ debugName: "categoryStyle" }] : []));
241
+ fileTypeClasses = computed(() => zMergeClasses('inline-flex min-w-14 items-center justify-center rounded-sm border border-black/5 px-2.5 py-1 text-[0.6875rem] font-semibold tracking-wide dark:border-white/10', this.categoryStyle().bg, this.categoryStyle().text), ...(ngDevMode ? [{ debugName: "fileTypeClasses" }] : []));
242
+ canPreview = computed(() => isPreviewable(this.file()), ...(ngDevMode ? [{ debugName: "canPreview" }] : []));
243
+ onImageLoad() {
244
+ this.isLoading.set(false);
245
+ }
246
+ onImageError() {
247
+ this.isLoading.set(false);
248
+ }
249
+ onDownload(event) {
250
+ event.stopPropagation();
251
+ this.zOnDownload.emit(this.file());
252
+ }
253
+ onPreviewClick(event) {
254
+ event.stopPropagation();
255
+ this.zOnPreview.emit(this.file());
256
+ }
257
+ onPreview() {
258
+ if (this.canPreview()) {
259
+ this.zOnPreview.emit(this.file());
260
+ }
261
+ }
262
+ onItemClick() {
263
+ if (this.zSelectable()) {
264
+ this.zOnSelect.emit(this.file());
265
+ return;
266
+ }
267
+ this.onPreview();
268
+ }
269
+ onRemove(event) {
270
+ event.stopPropagation();
271
+ this.zOnRemove.emit(this.file());
272
+ }
273
+ onSelectClick(event) {
274
+ event.stopPropagation();
275
+ this.zOnSelect.emit(this.file());
276
+ }
277
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
278
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", type: ZGalleryItemComponent, isStandalone: true, selector: "z-gallery-item", inputs: { file: { classPropertyName: "file", publicName: "file", isSignal: true, isRequired: true, transformFunction: null }, zMode: { classPropertyName: "zMode", publicName: "zMode", isSignal: true, isRequired: false, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zShowDownload: { classPropertyName: "zShowDownload", publicName: "zShowDownload", isSignal: true, isRequired: false, transformFunction: null }, zShowPreview: { classPropertyName: "zShowPreview", publicName: "zShowPreview", isSignal: true, isRequired: false, transformFunction: null }, zShowRemove: { classPropertyName: "zShowRemove", publicName: "zShowRemove", isSignal: true, isRequired: false, transformFunction: null }, zSelectable: { classPropertyName: "zSelectable", publicName: "zSelectable", isSignal: true, isRequired: false, transformFunction: null }, zSelected: { classPropertyName: "zSelected", publicName: "zSelected", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zOnDownload: "zOnDownload", zOnPreview: "zOnPreview", zOnRemove: "zOnRemove", zOnSelect: "zOnSelect" }, host: { classAttribute: "z-gallery-item block" }, ngImport: i0, template: `
279
+ @if (zMode() === 'grid') {
280
+ <div
281
+ class="group border-border bg-card hover:border-primary/30 relative cursor-pointer overflow-hidden rounded-md border shadow-sm transition-all duration-300 hover:shadow-lg"
282
+ [class.border-primary]="zSelected()"
283
+ [class.ring-1]="zSelected()"
284
+ [class.ring-primary/35]="zSelected()"
285
+ (click)="onItemClick()"
286
+ >
287
+ @if (zSelectable()) {
288
+ <div
289
+ class="bg-primary shadow-card absolute top-3 right-3 z-20 flex size-6 items-center justify-center rounded-full transition-all duration-200"
290
+ [class.scale-100]="zSelected()"
291
+ [class.opacity-100]="zSelected()"
292
+ [class.scale-90]="!zSelected()"
293
+ [class.opacity-0]="!zSelected()"
294
+ >
295
+ <i z-icon zType="lucideCheck" zSize="14" class="text-primary-foreground"></i>
296
+ </div>
297
+ }
298
+
299
+ <div class="relative overflow-hidden" [class]="mediaHeightClass()">
300
+ @if (isImage()) {
301
+ @if (isLoading()) {
302
+ <div class="absolute inset-0">
303
+ <z-skeleton class="size-full" />
304
+ </div>
305
+ }
306
+ <img
307
+ [src]="file().thumbnailUrl || file().url"
308
+ [alt]="file().name"
309
+ class="size-full object-cover transition-all duration-500"
310
+ [class.opacity-0]="isLoading()"
311
+ [class.scale-100]="!isLoading()"
312
+ [class.group-hover:scale-110]="!isLoading()"
313
+ loading="lazy"
314
+ (load)="onImageLoad()"
315
+ (error)="onImageError()"
316
+ />
317
+ } @else if (hasVideoPreview()) {
318
+ <video
319
+ [src]="file().url"
320
+ [poster]="file().thumbnailUrl ?? ''"
321
+ class="size-full object-cover transition-all duration-500 group-hover:scale-110"
322
+ muted
323
+ playsinline
324
+ preload="metadata"
325
+ ></video>
326
+ <div
327
+ class="absolute inset-0 flex items-center justify-center bg-black/10 transition-colors duration-300 group-hover:bg-black/25"
328
+ >
329
+ <div
330
+ class="flex size-12 items-center justify-center rounded-full bg-black/50 shadow-lg backdrop-blur-sm transition-transform duration-300 group-hover:scale-110"
331
+ >
332
+ <i z-icon zType="lucidePlay" zSize="20" class="fill-white text-white"></i>
333
+ </div>
334
+ </div>
335
+ } @else {
336
+ <div
337
+ class="flex size-full flex-col items-center justify-center gap-2 bg-gradient-to-br"
338
+ [class]="categoryStyle().bg"
339
+ >
340
+ <i z-icon [zType]="categoryStyle().icon" zSize="34" [class]="categoryStyle().text"></i>
341
+ <span class="text-xs font-semibold tracking-wide" [class]="categoryStyle().text">
342
+ {{ categoryStyle().label }}
343
+ </span>
344
+ </div>
345
+ }
346
+
347
+ <div class="absolute inset-x-0 top-0 z-10 flex items-start justify-between p-3">
348
+ <span
349
+ class="rounded-full border border-white/35 bg-black/45 px-2.5 py-1 text-[0.6875rem] font-semibold tracking-wide text-white backdrop-blur-md"
350
+ >
351
+ {{ fileExtension() }}
352
+ </span>
353
+ <span
354
+ class="rounded-full border border-white/25 bg-black/35 px-2 py-1 text-[0.625rem] font-medium text-white/95 backdrop-blur-md"
355
+ >
356
+ {{ formattedSize() }}
357
+ </span>
358
+ </div>
359
+
360
+ <div
361
+ class="absolute inset-x-0 bottom-0 h-24 bg-gradient-to-t from-black/70 via-black/30 to-transparent opacity-85 transition-opacity duration-300 group-hover:opacity-100"
362
+ ></div>
363
+
364
+ <div
365
+ class="absolute right-3 bottom-3 z-20 flex items-center gap-1.5 rounded-full border border-white/20 bg-black/40 p-1 opacity-0 backdrop-blur-md transition-all duration-200 group-hover:opacity-100"
366
+ >
367
+ @if (zShowPreview() && canPreview()) {
368
+ <button
369
+ z-button
370
+ zType="secondary"
371
+ zSize="xs"
372
+ zShape="circle"
373
+ class="shadow-lg"
374
+ (click)="onPreviewClick($event)"
375
+ z-tooltip
376
+ [zContent]="'i18n_z_ui_gallery_preview' | translate"
377
+ >
378
+ <i z-icon zType="lucideEye" zSize="14"></i>
379
+ </button>
380
+ }
381
+ @if (zShowDownload() && (file().downloadUrl || file().url)) {
382
+ <button
383
+ z-button
384
+ zType="secondary"
385
+ zSize="xs"
386
+ zShape="circle"
387
+ class="shadow-lg"
388
+ (click)="onDownload($event)"
389
+ z-tooltip
390
+ [zContent]="'i18n_z_ui_gallery_download' | translate"
391
+ >
392
+ <i z-icon zType="lucideDownload" zSize="14"></i>
393
+ </button>
394
+ }
395
+ @if (zShowRemove()) {
396
+ <button
397
+ z-button
398
+ zType="secondary"
399
+ zSize="xs"
400
+ zShape="circle"
401
+ class="shadow-lg"
402
+ (click)="onRemove($event)"
403
+ z-tooltip
404
+ [zContent]="'i18n_z_ui_gallery_remove' | translate"
405
+ >
406
+ <i z-icon zType="lucideTrash2" zSize="14"></i>
407
+ </button>
408
+ }
409
+ </div>
410
+ </div>
411
+
412
+ <div class="p-3">
413
+ <p class="text-foreground truncate text-sm leading-normal font-semibold" z-tooltip [zContent]="file().name">
414
+ {{ file().name }}
415
+ </p>
416
+ @if (formattedDate()) {
417
+ <p class="text-muted-foreground mt-1 text-xs">{{ formattedDate() }}</p>
418
+ }
419
+ </div>
420
+ </div>
421
+ } @else {
422
+ <div
423
+ class="group border-border bg-card hover:border-primary/35 flex cursor-pointer items-center gap-3 rounded-sm border px-3 py-2.5 shadow-sm transition-all duration-200 hover:shadow-md"
424
+ [class.border-primary]="zSelected()"
425
+ [class.ring-1]="zSelected()"
426
+ [class.ring-primary/30]="zSelected()"
427
+ (click)="onItemClick()"
428
+ >
429
+ @if (zSelectable()) {
430
+ <div
431
+ class="bg-primary -ml-1 flex size-5 shrink-0 items-center justify-center rounded-full transition-all duration-200"
432
+ [class.scale-100]="zSelected()"
433
+ [class.opacity-100]="zSelected()"
434
+ [class.scale-90]="!zSelected()"
435
+ [class.opacity-0]="!zSelected()"
436
+ >
437
+ <i z-icon zType="lucideCheck" zSize="12" class="text-primary-foreground"></i>
438
+ </div>
439
+ }
440
+
441
+ <div
442
+ class="relative flex size-11 shrink-0 items-center justify-center overflow-hidden rounded-sm border border-black/5 bg-white/40 shadow-sm backdrop-blur-sm dark:border-white/10 dark:bg-white/5"
443
+ >
444
+ @if (isImage() && (file().thumbnailUrl || file().url)) {
445
+ <img
446
+ [src]="file().thumbnailUrl || file().url"
447
+ [alt]="file().name"
448
+ class="size-full rounded-sm object-cover"
449
+ loading="lazy"
450
+ />
451
+ } @else if (hasVideoPreview()) {
452
+ <video
453
+ [src]="file().url"
454
+ [poster]="file().thumbnailUrl ?? ''"
455
+ class="size-full rounded-sm object-cover"
456
+ muted
457
+ playsinline
458
+ preload="metadata"
459
+ ></video>
460
+ <div class="absolute inset-0 flex items-center justify-center rounded-sm bg-black/25">
461
+ <i z-icon zType="lucidePlay" zSize="12" class="fill-white text-white"></i>
462
+ </div>
463
+ } @else {
464
+ <span class="absolute inset-0 opacity-30 dark:opacity-20" [class]="categoryStyle().bg"></span>
465
+ <i
466
+ z-icon
467
+ [zType]="categoryStyle().icon"
468
+ zSize="18"
469
+ class="relative z-10"
470
+ [class]="categoryStyle().text"
471
+ ></i>
472
+ }
473
+ </div>
474
+
475
+ <div class="min-w-0 flex-1">
476
+ <p class="text-foreground truncate text-sm font-medium" z-tooltip [zContent]="file().name">
477
+ {{ file().name }}
478
+ </p>
479
+ <p class="text-muted-foreground truncate text-xs">{{ formattedSize() }} · {{ categoryStyle().label }}</p>
480
+ </div>
481
+
482
+ <div class="ml-auto flex shrink-0 items-center gap-1.5">
483
+ <span [class]="fileTypeClasses()">
484
+ {{ fileExtension() }}
485
+ </span>
486
+ @if (zShowPreview() && canPreview()) {
487
+ <button
488
+ z-button
489
+ zType="ghost"
490
+ zSize="xs"
491
+ zShape="circle"
492
+ class="text-muted-foreground hover:text-foreground"
493
+ (click)="onPreviewClick($event)"
494
+ z-tooltip
495
+ [zContent]="'i18n_z_ui_gallery_preview' | translate"
496
+ >
497
+ <i z-icon zType="lucideEye" zSize="16"></i>
498
+ </button>
499
+ }
500
+ @if (zShowDownload() && (file().downloadUrl || file().url)) {
501
+ <button
502
+ z-button
503
+ zType="ghost"
504
+ zSize="xs"
505
+ zShape="circle"
506
+ class="text-muted-foreground hover:text-foreground"
507
+ (click)="onDownload($event)"
508
+ z-tooltip
509
+ [zContent]="'i18n_z_ui_gallery_download' | translate"
510
+ >
511
+ <i z-icon zType="lucideDownload" zSize="16"></i>
512
+ </button>
513
+ }
514
+ @if (zShowRemove()) {
515
+ <button
516
+ z-button
517
+ zType="ghost"
518
+ zSize="xs"
519
+ zShape="circle"
520
+ class="text-muted-foreground hover:text-destructive"
521
+ (click)="onRemove($event)"
522
+ z-tooltip
523
+ [zContent]="'i18n_z_ui_gallery_remove' | translate"
524
+ >
525
+ <i z-icon zType="lucideTrash2" zSize="16"></i>
526
+ </button>
527
+ }
528
+ </div>
529
+ </div>
530
+ }
531
+ `, isInline: true, dependencies: [{ kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
532
+ }
533
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryItemComponent, decorators: [{
534
+ type: Component,
535
+ args: [{
536
+ selector: 'z-gallery-item',
537
+ imports: [ZButtonComponent, ZIconComponent, ZTooltipDirective, ZSkeletonComponent, TranslatePipe],
538
+ standalone: true,
539
+ template: `
540
+ @if (zMode() === 'grid') {
541
+ <div
542
+ class="group border-border bg-card hover:border-primary/30 relative cursor-pointer overflow-hidden rounded-md border shadow-sm transition-all duration-300 hover:shadow-lg"
543
+ [class.border-primary]="zSelected()"
544
+ [class.ring-1]="zSelected()"
545
+ [class.ring-primary/35]="zSelected()"
546
+ (click)="onItemClick()"
547
+ >
548
+ @if (zSelectable()) {
549
+ <div
550
+ class="bg-primary shadow-card absolute top-3 right-3 z-20 flex size-6 items-center justify-center rounded-full transition-all duration-200"
551
+ [class.scale-100]="zSelected()"
552
+ [class.opacity-100]="zSelected()"
553
+ [class.scale-90]="!zSelected()"
554
+ [class.opacity-0]="!zSelected()"
555
+ >
556
+ <i z-icon zType="lucideCheck" zSize="14" class="text-primary-foreground"></i>
557
+ </div>
558
+ }
559
+
560
+ <div class="relative overflow-hidden" [class]="mediaHeightClass()">
561
+ @if (isImage()) {
562
+ @if (isLoading()) {
563
+ <div class="absolute inset-0">
564
+ <z-skeleton class="size-full" />
565
+ </div>
566
+ }
567
+ <img
568
+ [src]="file().thumbnailUrl || file().url"
569
+ [alt]="file().name"
570
+ class="size-full object-cover transition-all duration-500"
571
+ [class.opacity-0]="isLoading()"
572
+ [class.scale-100]="!isLoading()"
573
+ [class.group-hover:scale-110]="!isLoading()"
574
+ loading="lazy"
575
+ (load)="onImageLoad()"
576
+ (error)="onImageError()"
577
+ />
578
+ } @else if (hasVideoPreview()) {
579
+ <video
580
+ [src]="file().url"
581
+ [poster]="file().thumbnailUrl ?? ''"
582
+ class="size-full object-cover transition-all duration-500 group-hover:scale-110"
583
+ muted
584
+ playsinline
585
+ preload="metadata"
586
+ ></video>
587
+ <div
588
+ class="absolute inset-0 flex items-center justify-center bg-black/10 transition-colors duration-300 group-hover:bg-black/25"
589
+ >
590
+ <div
591
+ class="flex size-12 items-center justify-center rounded-full bg-black/50 shadow-lg backdrop-blur-sm transition-transform duration-300 group-hover:scale-110"
592
+ >
593
+ <i z-icon zType="lucidePlay" zSize="20" class="fill-white text-white"></i>
594
+ </div>
595
+ </div>
596
+ } @else {
597
+ <div
598
+ class="flex size-full flex-col items-center justify-center gap-2 bg-gradient-to-br"
599
+ [class]="categoryStyle().bg"
600
+ >
601
+ <i z-icon [zType]="categoryStyle().icon" zSize="34" [class]="categoryStyle().text"></i>
602
+ <span class="text-xs font-semibold tracking-wide" [class]="categoryStyle().text">
603
+ {{ categoryStyle().label }}
604
+ </span>
605
+ </div>
606
+ }
607
+
608
+ <div class="absolute inset-x-0 top-0 z-10 flex items-start justify-between p-3">
609
+ <span
610
+ class="rounded-full border border-white/35 bg-black/45 px-2.5 py-1 text-[0.6875rem] font-semibold tracking-wide text-white backdrop-blur-md"
611
+ >
612
+ {{ fileExtension() }}
613
+ </span>
614
+ <span
615
+ class="rounded-full border border-white/25 bg-black/35 px-2 py-1 text-[0.625rem] font-medium text-white/95 backdrop-blur-md"
616
+ >
617
+ {{ formattedSize() }}
618
+ </span>
619
+ </div>
620
+
621
+ <div
622
+ class="absolute inset-x-0 bottom-0 h-24 bg-gradient-to-t from-black/70 via-black/30 to-transparent opacity-85 transition-opacity duration-300 group-hover:opacity-100"
623
+ ></div>
624
+
625
+ <div
626
+ class="absolute right-3 bottom-3 z-20 flex items-center gap-1.5 rounded-full border border-white/20 bg-black/40 p-1 opacity-0 backdrop-blur-md transition-all duration-200 group-hover:opacity-100"
627
+ >
628
+ @if (zShowPreview() && canPreview()) {
629
+ <button
630
+ z-button
631
+ zType="secondary"
632
+ zSize="xs"
633
+ zShape="circle"
634
+ class="shadow-lg"
635
+ (click)="onPreviewClick($event)"
636
+ z-tooltip
637
+ [zContent]="'i18n_z_ui_gallery_preview' | translate"
638
+ >
639
+ <i z-icon zType="lucideEye" zSize="14"></i>
640
+ </button>
641
+ }
642
+ @if (zShowDownload() && (file().downloadUrl || file().url)) {
643
+ <button
644
+ z-button
645
+ zType="secondary"
646
+ zSize="xs"
647
+ zShape="circle"
648
+ class="shadow-lg"
649
+ (click)="onDownload($event)"
650
+ z-tooltip
651
+ [zContent]="'i18n_z_ui_gallery_download' | translate"
652
+ >
653
+ <i z-icon zType="lucideDownload" zSize="14"></i>
654
+ </button>
655
+ }
656
+ @if (zShowRemove()) {
657
+ <button
658
+ z-button
659
+ zType="secondary"
660
+ zSize="xs"
661
+ zShape="circle"
662
+ class="shadow-lg"
663
+ (click)="onRemove($event)"
664
+ z-tooltip
665
+ [zContent]="'i18n_z_ui_gallery_remove' | translate"
666
+ >
667
+ <i z-icon zType="lucideTrash2" zSize="14"></i>
668
+ </button>
669
+ }
670
+ </div>
671
+ </div>
672
+
673
+ <div class="p-3">
674
+ <p class="text-foreground truncate text-sm leading-normal font-semibold" z-tooltip [zContent]="file().name">
675
+ {{ file().name }}
676
+ </p>
677
+ @if (formattedDate()) {
678
+ <p class="text-muted-foreground mt-1 text-xs">{{ formattedDate() }}</p>
679
+ }
680
+ </div>
681
+ </div>
682
+ } @else {
683
+ <div
684
+ class="group border-border bg-card hover:border-primary/35 flex cursor-pointer items-center gap-3 rounded-sm border px-3 py-2.5 shadow-sm transition-all duration-200 hover:shadow-md"
685
+ [class.border-primary]="zSelected()"
686
+ [class.ring-1]="zSelected()"
687
+ [class.ring-primary/30]="zSelected()"
688
+ (click)="onItemClick()"
689
+ >
690
+ @if (zSelectable()) {
691
+ <div
692
+ class="bg-primary -ml-1 flex size-5 shrink-0 items-center justify-center rounded-full transition-all duration-200"
693
+ [class.scale-100]="zSelected()"
694
+ [class.opacity-100]="zSelected()"
695
+ [class.scale-90]="!zSelected()"
696
+ [class.opacity-0]="!zSelected()"
697
+ >
698
+ <i z-icon zType="lucideCheck" zSize="12" class="text-primary-foreground"></i>
699
+ </div>
700
+ }
701
+
702
+ <div
703
+ class="relative flex size-11 shrink-0 items-center justify-center overflow-hidden rounded-sm border border-black/5 bg-white/40 shadow-sm backdrop-blur-sm dark:border-white/10 dark:bg-white/5"
704
+ >
705
+ @if (isImage() && (file().thumbnailUrl || file().url)) {
706
+ <img
707
+ [src]="file().thumbnailUrl || file().url"
708
+ [alt]="file().name"
709
+ class="size-full rounded-sm object-cover"
710
+ loading="lazy"
711
+ />
712
+ } @else if (hasVideoPreview()) {
713
+ <video
714
+ [src]="file().url"
715
+ [poster]="file().thumbnailUrl ?? ''"
716
+ class="size-full rounded-sm object-cover"
717
+ muted
718
+ playsinline
719
+ preload="metadata"
720
+ ></video>
721
+ <div class="absolute inset-0 flex items-center justify-center rounded-sm bg-black/25">
722
+ <i z-icon zType="lucidePlay" zSize="12" class="fill-white text-white"></i>
723
+ </div>
724
+ } @else {
725
+ <span class="absolute inset-0 opacity-30 dark:opacity-20" [class]="categoryStyle().bg"></span>
726
+ <i
727
+ z-icon
728
+ [zType]="categoryStyle().icon"
729
+ zSize="18"
730
+ class="relative z-10"
731
+ [class]="categoryStyle().text"
732
+ ></i>
733
+ }
734
+ </div>
735
+
736
+ <div class="min-w-0 flex-1">
737
+ <p class="text-foreground truncate text-sm font-medium" z-tooltip [zContent]="file().name">
738
+ {{ file().name }}
739
+ </p>
740
+ <p class="text-muted-foreground truncate text-xs">{{ formattedSize() }} · {{ categoryStyle().label }}</p>
741
+ </div>
742
+
743
+ <div class="ml-auto flex shrink-0 items-center gap-1.5">
744
+ <span [class]="fileTypeClasses()">
745
+ {{ fileExtension() }}
746
+ </span>
747
+ @if (zShowPreview() && canPreview()) {
748
+ <button
749
+ z-button
750
+ zType="ghost"
751
+ zSize="xs"
752
+ zShape="circle"
753
+ class="text-muted-foreground hover:text-foreground"
754
+ (click)="onPreviewClick($event)"
755
+ z-tooltip
756
+ [zContent]="'i18n_z_ui_gallery_preview' | translate"
757
+ >
758
+ <i z-icon zType="lucideEye" zSize="16"></i>
759
+ </button>
760
+ }
761
+ @if (zShowDownload() && (file().downloadUrl || file().url)) {
762
+ <button
763
+ z-button
764
+ zType="ghost"
765
+ zSize="xs"
766
+ zShape="circle"
767
+ class="text-muted-foreground hover:text-foreground"
768
+ (click)="onDownload($event)"
769
+ z-tooltip
770
+ [zContent]="'i18n_z_ui_gallery_download' | translate"
771
+ >
772
+ <i z-icon zType="lucideDownload" zSize="16"></i>
773
+ </button>
774
+ }
775
+ @if (zShowRemove()) {
776
+ <button
777
+ z-button
778
+ zType="ghost"
779
+ zSize="xs"
780
+ zShape="circle"
781
+ class="text-muted-foreground hover:text-destructive"
782
+ (click)="onRemove($event)"
783
+ z-tooltip
784
+ [zContent]="'i18n_z_ui_gallery_remove' | translate"
785
+ >
786
+ <i z-icon zType="lucideTrash2" zSize="16"></i>
787
+ </button>
788
+ }
789
+ </div>
790
+ </div>
791
+ }
792
+ `,
793
+ changeDetection: ChangeDetectionStrategy.OnPush,
794
+ encapsulation: ViewEncapsulation.None,
795
+ host: {
796
+ class: 'z-gallery-item block',
797
+ },
798
+ }]
799
+ }], propDecorators: { file: [{ type: i0.Input, args: [{ isSignal: true, alias: "file", required: true }] }], zMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMode", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zShowDownload: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowDownload", required: false }] }], zShowPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowPreview", required: false }] }], zShowRemove: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowRemove", required: false }] }], zSelectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSelectable", required: false }] }], zSelected: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSelected", required: false }] }], zOnDownload: [{ type: i0.Output, args: ["zOnDownload"] }], zOnPreview: [{ type: i0.Output, args: ["zOnPreview"] }], zOnRemove: [{ type: i0.Output, args: ["zOnRemove"] }], zOnSelect: [{ type: i0.Output, args: ["zOnSelect"] }] } });
800
+
801
+ const Z_GALLERY_PDF_VIEWER_CHROME_CSS = `
802
+ #toolbarContainer,
803
+ #toolbarContainer * {
804
+ box-sizing: border-box;
805
+ }
806
+
807
+ #toolbarContainer,
808
+ .findbar,
809
+ .secondaryToolbar {
810
+ --toolbar-bg-color: #050505;
811
+ --toolbar-box-shadow: none;
812
+ --toolbar-border-bottom: 1px solid #222222;
813
+ --main-color: #f5f5f5;
814
+ --toolbar-icon-bg-color: #e7e7e7;
815
+ --toolbar-icon-hover-bg-color: #ffffff;
816
+ --toolbar-icon-opacity: 0.92;
817
+ --button-hover-color: #1f1f1f;
818
+ --toggled-btn-bg-color: #2a2a2a;
819
+ --toggled-btn-color: #ffffff;
820
+ --separator-color: #303030;
821
+ --field-bg-color: #111111;
822
+ --field-color: #f5f5f5;
823
+ --field-border-color: #3a3a3a;
824
+ --dropdown-btn-bg-color: #111111;
825
+ --dropdown-btn-border: 1px solid #3a3a3a;
826
+ }
827
+
828
+ #toolbarContainer {
829
+ height: var(--toolbar-height) !important;
830
+ padding: var(--toolbar-vertical-padding) var(--toolbar-horizontal-padding) !important;
831
+ background-color: var(--toolbar-bg-color) !important;
832
+ box-shadow: var(--toolbar-box-shadow) !important;
833
+ border-bottom: var(--toolbar-border-bottom) !important;
834
+ font: message-box !important;
835
+ }
836
+
837
+ #toolbarContainer #toolbarViewer,
838
+ #toolbarViewerLeft,
839
+ #toolbarViewerMiddle,
840
+ #toolbarViewerRight {
841
+ height: 100%;
842
+ align-items: center;
843
+ }
844
+
845
+ #toolbarContainer #toolbarViewer {
846
+ justify-content: space-between;
847
+ }
848
+
849
+ #toolbarViewerLeft,
850
+ #toolbarViewerMiddle,
851
+ #toolbarViewerRight,
852
+ .toolbarHorizontalGroup {
853
+ gap: 1px;
854
+ }
855
+
856
+ #toolbarViewerLeft .loadingInput {
857
+ position: relative;
858
+ display: inline-flex;
859
+ align-items: center;
860
+ }
861
+
862
+ .toolbarButton,
863
+ .toolbarButtonWithContainer {
864
+ height: 100% !important;
865
+ aspect-ratio: 1 !important;
866
+ flex: none !important;
867
+ }
868
+
869
+ .toolbarButton {
870
+ display: flex !important;
871
+ align-items: center !important;
872
+ justify-content: center !important;
873
+ padding: 0 !important;
874
+ border: none !important;
875
+ border-radius: 2px !important;
876
+ background: none !important;
877
+ color: var(--main-color) !important;
878
+ font: message-box !important;
879
+ outline: none !important;
880
+ }
881
+
882
+ .toolbarButton:is(:hover, :focus-visible) {
883
+ background-color: var(--button-hover-color) !important;
884
+ color: var(--main-color) !important;
885
+ }
886
+
887
+ .toolbarButton::before {
888
+ width: var(--icon-size) !important;
889
+ height: var(--icon-size) !important;
890
+ background-color: var(--toolbar-icon-bg-color) !important;
891
+ opacity: var(--toolbar-icon-opacity) !important;
892
+ -webkit-mask-size: cover !important;
893
+ mask-size: cover !important;
894
+ -webkit-mask-position: center !important;
895
+ mask-position: center !important;
896
+ }
897
+
898
+ .toolbarButton:is(:hover, :focus-visible)::before {
899
+ background-color: var(--toolbar-icon-hover-bg-color) !important;
900
+ }
901
+
902
+ .toolbarButton.toggled {
903
+ background-color: var(--toggled-btn-bg-color) !important;
904
+ color: var(--toggled-btn-color) !important;
905
+ }
906
+
907
+ .toolbarButton.toggled::before {
908
+ background-color: var(--toggled-btn-color) !important;
909
+ }
910
+
911
+ .splitToolbarButtonSeparator {
912
+ width: 0 !important;
913
+ height: 62% !important;
914
+ border-left: 1px solid var(--separator-color) !important;
915
+ border-right: none !important;
916
+ }
917
+
918
+ .toolbarField {
919
+ padding: 4px 7px !important;
920
+ margin: 3px 0 !important;
921
+ border-radius: 2px !important;
922
+ background-color: var(--field-bg-color) !important;
923
+ background-clip: padding-box !important;
924
+ border: 1px solid var(--field-border-color) !important;
925
+ box-shadow: none !important;
926
+ color: var(--field-color) !important;
927
+ font: message-box !important;
928
+ font-size: 12px !important;
929
+ line-height: 16px !important;
930
+ outline: none !important;
931
+ }
932
+
933
+ .toolbarField:focus {
934
+ border-color: #0a84ff !important;
935
+ }
936
+
937
+ #toolbarViewerLeft #pageNumber.toolbarField {
938
+ appearance: textfield !important;
939
+ width: 48px !important;
940
+ min-width: 48px !important;
941
+ max-width: 48px !important;
942
+ height: auto !important;
943
+ min-height: 0 !important;
944
+ margin: 3px 0 !important;
945
+ padding: 4px 7px !important;
946
+ border-radius: 2px !important;
947
+ font-size: 12px !important;
948
+ line-height: 16px !important;
949
+ text-align: end !important;
950
+ background-size: 0 0 !important;
951
+ transition-property: none !important;
952
+ }
953
+
954
+ #pageNumber::-webkit-inner-spin-button {
955
+ -webkit-appearance: none !important;
956
+ appearance: none !important;
957
+ }
958
+
959
+ #toolbarViewerLeft #numPages.toolbarLabel {
960
+ white-space: nowrap;
961
+ }
962
+
963
+ .toolbarLabel {
964
+ width: max-content !important;
965
+ min-width: 16px !important;
966
+ height: 100% !important;
967
+ padding-inline: 4px !important;
968
+ margin: 2px !important;
969
+ border-radius: 2px !important;
970
+ color: var(--main-color) !important;
971
+ font-size: 12px !important;
972
+ line-height: 14px !important;
973
+ text-align: left !important;
974
+ user-select: none !important;
975
+ cursor: default !important;
976
+ display: inline flex !important;
977
+ flex-direction: column !important;
978
+ align-items: center !important;
979
+ justify-content: center !important;
980
+ }
981
+
982
+ .dropdownToolbarButton {
983
+ width: fit-content !important;
984
+ min-width: 140px !important;
985
+ padding: 0 !important;
986
+ border: var(--dropdown-btn-border) !important;
987
+ border-radius: 2px !important;
988
+ background-color: var(--dropdown-btn-bg-color) !important;
989
+ color: var(--main-color) !important;
990
+ font-size: 12px !important;
991
+ line-height: 14px !important;
992
+ }
993
+
994
+ .dropdownToolbarButton:hover {
995
+ background-color: var(--button-hover-color) !important;
996
+ }
997
+
998
+ .dropdownToolbarButton > select {
999
+ height: 28px !important;
1000
+ margin: 0 !important;
1001
+ padding-block: 1px 2px !important;
1002
+ padding-inline: 6px 38px !important;
1003
+ border: none !important;
1004
+ background-color: var(--dropdown-btn-bg-color) !important;
1005
+ color: var(--main-color) !important;
1006
+ font: message-box !important;
1007
+ font-size: 12px !important;
1008
+ }
1009
+
1010
+ .dropdownToolbarButton > select > option {
1011
+ background-color: #111111 !important;
1012
+ color: #f5f5f5 !important;
1013
+ }
1014
+
1015
+ #viewerContainer,
1016
+ #viewer,
1017
+ .pdfViewer,
1018
+ .pdfViewer .page,
1019
+ .pdfViewer .page canvas {
1020
+ border-color: oklch(0.49 0 0) !important;
1021
+ outline-color: oklch(0.49 0 0) !important;
1022
+ }
1023
+
1024
+ .pdfViewer .page {
1025
+ background-color: oklch(0.49 0 0) !important;
1026
+ border: 0 !important;
1027
+ box-shadow: none !important;
1028
+ }
1029
+
1030
+ @media (max-width: 768px) {
1031
+ #toolbarContainer {
1032
+ --toolbar-horizontal-padding: 4px;
1033
+ }
1034
+
1035
+ #editorModeButtons,
1036
+ #editorSignatureButton,
1037
+ #editorHighlightButton,
1038
+ #editorFreeTextButton,
1039
+ #editorInkButton,
1040
+ #editorStampButton {
1041
+ display: none !important;
1042
+ }
1043
+
1044
+ #toolbarViewerRight {
1045
+ gap: 0;
1046
+ }
1047
+
1048
+ .dropdownToolbarButton {
1049
+ min-width: 112px !important;
1050
+ }
1051
+
1052
+ #toolbarViewerLeft #pageNumber.toolbarField {
1053
+ width: 40px !important;
1054
+ min-width: 40px !important;
1055
+ max-width: 40px !important;
1056
+ }
1057
+ }
1058
+
1059
+ @media (max-width: 480px) {
1060
+ #printButton,
1061
+ #secondaryToolbarToggleButton {
1062
+ display: none !important;
1063
+ }
1064
+
1065
+ .dropdownToolbarButton {
1066
+ min-width: 96px !important;
1067
+ }
1068
+ }
1069
+ `;
1070
+
1071
+ class ZGalleryPreviewComponent {
1072
+ _document = inject(DOCUMENT);
1073
+ _sanitizer = inject(DomSanitizer);
1074
+ file = input.required(...(ngDevMode ? [{ debugName: "file" }] : []));
1075
+ files = input([], ...(ngDevMode ? [{ debugName: "files" }] : []));
1076
+ zShowRemove = input(false, ...(ngDevMode ? [{ debugName: "zShowRemove" }] : []));
1077
+ zPdfViewerConfig = input({}, ...(ngDevMode ? [{ debugName: "zPdfViewerConfig" }] : []));
1078
+ zTrustedResourceOrigins = input([], ...(ngDevMode ? [{ debugName: "zTrustedResourceOrigins" }] : []));
1079
+ zOnClose = output();
1080
+ zOnDownload = output();
1081
+ zOnNavigate = output();
1082
+ zOnRemove = output();
1083
+ zoomed = signal(false, ...(ngDevMode ? [{ debugName: "zoomed" }] : []));
1084
+ isLoading = signal(true, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
1085
+ rotation = signal(0, ...(ngDevMode ? [{ debugName: "rotation" }] : []));
1086
+ isConverting = signal(false, ...(ngDevMode ? [{ debugName: "isConverting" }] : []));
1087
+ conversionError = signal(null, ...(ngDevMode ? [{ debugName: "conversionError" }] : []));
1088
+ previewError = signal(false, ...(ngDevMode ? [{ debugName: "previewError" }] : []));
1089
+ docHtmlContent = signal(null, ...(ngDevMode ? [{ debugName: "docHtmlContent" }] : []));
1090
+ textContent = signal('', ...(ngDevMode ? [{ debugName: "textContent" }] : []));
1091
+ pdfViewer = viewChild('pdfViewer', ...(ngDevMode ? [{ debugName: "pdfViewer" }] : []));
1092
+ _mediaLoaded = signal(false, ...(ngDevMode ? [{ debugName: "_mediaLoaded" }] : []));
1093
+ _loadingStartTime = 0;
1094
+ _minLoadingTime = 300;
1095
+ constructor() {
1096
+ effect(() => {
1097
+ const currentFile = this.file();
1098
+ if (!currentFile) {
1099
+ return;
1100
+ }
1101
+ this.isLoading.set(true);
1102
+ this._mediaLoaded.set(false);
1103
+ this._loadingStartTime = Date.now();
1104
+ this.zoomed.set(false);
1105
+ this.rotation.set(0);
1106
+ this.isConverting.set(false);
1107
+ this.conversionError.set(null);
1108
+ this.previewError.set(false);
1109
+ this.docHtmlContent.set(null);
1110
+ this.textContent.set('');
1111
+ const category = getFileCategory(currentFile);
1112
+ if (category === 'word' || category === 'excel' || category === 'text' || category === 'code') {
1113
+ void this._loadFileContent(currentFile, category);
1114
+ }
1115
+ });
1116
+ }
1117
+ async _loadFileContent(file, category) {
1118
+ const url = file.url || file.downloadUrl;
1119
+ if (!url) {
1120
+ this.conversionError.set('No URL available for preview');
1121
+ this._completeLoading();
1122
+ return;
1123
+ }
1124
+ this.isConverting.set(true);
1125
+ try {
1126
+ if (category === 'word') {
1127
+ await this._loadDocx(url);
1128
+ }
1129
+ else if (category === 'excel') {
1130
+ await this._loadExcel(url);
1131
+ }
1132
+ else {
1133
+ await this._loadText(url);
1134
+ }
1135
+ }
1136
+ catch (error) {
1137
+ const message = error instanceof Error ? error.message : 'Failed to load file content';
1138
+ this.conversionError.set(message);
1139
+ }
1140
+ finally {
1141
+ this.isConverting.set(false);
1142
+ this._completeLoading();
1143
+ }
1144
+ }
1145
+ async _loadDocx(url) {
1146
+ const response = await fetch(url);
1147
+ this._assertSuccessfulResponse(response);
1148
+ const arrayBuffer = await response.arrayBuffer();
1149
+ const mammothModule = await import('mammoth');
1150
+ const mammoth = mammothModule.default ?? mammothModule;
1151
+ const result = await mammoth.convertToHtml({ arrayBuffer });
1152
+ this.docHtmlContent.set(this._sanitizer.bypassSecurityTrustHtml(result.value));
1153
+ }
1154
+ async _loadExcel(url) {
1155
+ const response = await fetch(url);
1156
+ this._assertSuccessfulResponse(response);
1157
+ const arrayBuffer = await response.arrayBuffer();
1158
+ const xlsxModule = await import('xlsx');
1159
+ const XLSX = xlsxModule.default ?? xlsxModule;
1160
+ const workbook = XLSX.read(arrayBuffer);
1161
+ const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
1162
+ const html = XLSX.utils.sheet_to_html(firstSheet);
1163
+ this.docHtmlContent.set(this._sanitizer.bypassSecurityTrustHtml(html));
1164
+ }
1165
+ async _loadText(url) {
1166
+ const response = await fetch(url);
1167
+ this._assertSuccessfulResponse(response);
1168
+ const text = await response.text();
1169
+ this.textContent.set(text);
1170
+ }
1171
+ _assertSuccessfulResponse(response) {
1172
+ if (!response.ok) {
1173
+ throw new Error(`Failed to fetch file: ${response.status}`);
1174
+ }
1175
+ }
1176
+ _completeLoading() {
1177
+ const elapsed = Date.now() - this._loadingStartTime;
1178
+ const remaining = this._minLoadingTime - elapsed;
1179
+ if (remaining > 0) {
1180
+ setTimeout(() => this.isLoading.set(false), remaining);
1181
+ return;
1182
+ }
1183
+ this.isLoading.set(false);
1184
+ }
1185
+ currentIndex = computed(() => {
1186
+ const allFiles = this.files();
1187
+ const current = this.file();
1188
+ return allFiles.findIndex(f => f.id === current.id);
1189
+ }, ...(ngDevMode ? [{ debugName: "currentIndex" }] : []));
1190
+ hasPrev = computed(() => this.currentIndex() > 0, ...(ngDevMode ? [{ debugName: "hasPrev" }] : []));
1191
+ hasNext = computed(() => this.currentIndex() < this.files().length - 1, ...(ngDevMode ? [{ debugName: "hasNext" }] : []));
1192
+ isImageFile = computed(() => isImage(this.file()), ...(ngDevMode ? [{ debugName: "isImageFile" }] : []));
1193
+ isPdf = computed(() => getFileCategory(this.file()) === 'pdf', ...(ngDevMode ? [{ debugName: "isPdf" }] : []));
1194
+ pdfUrl = computed(() => {
1195
+ const url = this.file().url || this.file().downloadUrl;
1196
+ if (!url) {
1197
+ return null;
1198
+ }
1199
+ if (!this._isAllowedResourceUrl(url)) {
1200
+ return null;
1201
+ }
1202
+ return url;
1203
+ }, ...(ngDevMode ? [{ debugName: "pdfUrl" }] : []));
1204
+ pdfViewerId = computed(() => {
1205
+ const normalizedId = this.file().id.replace(/[^a-zA-Z0-9_-]/g, '-');
1206
+ return `z-gallery-preview-${normalizedId}`;
1207
+ }, ...(ngDevMode ? [{ debugName: "pdfViewerId" }] : []));
1208
+ pdfViewerConfig = computed(() => {
1209
+ const config = this.zPdfViewerConfig();
1210
+ const { controlVisibility } = config;
1211
+ const { groupVisibility } = config;
1212
+ const { autoActions } = config;
1213
+ const { viewerConfig } = config;
1214
+ const { themeConfig } = config;
1215
+ const { layoutConfig } = config;
1216
+ return {
1217
+ ...config,
1218
+ viewerFolder: config.viewerFolder ?? '/assets/pdfjs',
1219
+ locale: viewerConfig?.locale ?? config.locale ?? '',
1220
+ showSpinner: viewerConfig?.showSpinner ?? config.showSpinner ?? false,
1221
+ useOnlyCssZoom: viewerConfig?.useOnlyCssZoom ?? config.useOnlyCssZoom ?? false,
1222
+ diagnosticLogs: viewerConfig?.diagnosticLogs ?? config.diagnosticLogs ?? false,
1223
+ showOpenFile: controlVisibility?.openFile ?? config.showOpenFile ?? false,
1224
+ showAnnotations: controlVisibility?.annotations ?? config.showAnnotations ?? true,
1225
+ showDownload: controlVisibility?.download ?? config.showDownload ?? true,
1226
+ showViewBookmark: controlVisibility?.viewBookmark ?? config.showViewBookmark ?? true,
1227
+ showPrint: controlVisibility?.print ?? config.showPrint ?? true,
1228
+ showFullScreen: controlVisibility?.fullScreen ?? config.showFullScreen ?? true,
1229
+ showFind: controlVisibility?.find ?? config.showFind ?? true,
1230
+ downloadOnLoad: autoActions?.downloadOnLoad ?? config.downloadOnLoad ?? false,
1231
+ printOnLoad: autoActions?.printOnLoad ?? config.printOnLoad ?? false,
1232
+ rotateCW: autoActions?.rotateCW ?? config.rotateCW ?? false,
1233
+ rotateCCW: autoActions?.rotateCCW ?? config.rotateCCW ?? false,
1234
+ showLastPageOnLoad: autoActions?.showLastPageOnLoad ?? config.showLastPageOnLoad ?? false,
1235
+ showToolbarLeft: groupVisibility?.toolbarLeft ?? config.showToolbarLeft ?? true,
1236
+ showToolbarMiddle: groupVisibility?.toolbarMiddle ?? config.showToolbarMiddle ?? true,
1237
+ showToolbarRight: groupVisibility?.toolbarRight ?? config.showToolbarRight ?? true,
1238
+ showSecondaryToolbarToggle: groupVisibility?.secondaryToolbarToggle ?? config.showSecondaryToolbarToggle ?? true,
1239
+ showSidebar: groupVisibility?.sidebar ?? config.showSidebar ?? true,
1240
+ showSidebarLeft: groupVisibility?.sidebarLeft ?? config.showSidebarLeft ?? true,
1241
+ showSidebarRight: groupVisibility?.sidebarRight ?? config.showSidebarRight ?? true,
1242
+ toolbarDensity: layoutConfig?.toolbarDensity ?? config.toolbarDensity ?? 'default',
1243
+ sidebarWidth: layoutConfig?.sidebarWidth ?? config.sidebarWidth,
1244
+ toolbarPosition: layoutConfig?.toolbarPosition ?? config.toolbarPosition ?? 'top',
1245
+ sidebarPosition: layoutConfig?.sidebarPosition ?? config.sidebarPosition ?? 'left',
1246
+ responsiveBreakpoint: layoutConfig?.responsiveBreakpoint ?? config.responsiveBreakpoint,
1247
+ zoom: config.zoom ?? 'page-fit',
1248
+ rotation: config.rotation ?? 0,
1249
+ cursor: config.cursor ?? 'select',
1250
+ scroll: config.scroll ?? 'vertical',
1251
+ spread: config.spread ?? 'none',
1252
+ pageMode: config.pageMode ?? 'none',
1253
+ page: config.page ?? 1,
1254
+ iframeBorder: config.iframeBorder ?? 0,
1255
+ theme: themeConfig?.theme ?? config.theme ?? 'auto',
1256
+ primaryColor: themeConfig?.primaryColor ?? config.primaryColor,
1257
+ backgroundColor: themeConfig?.backgroundColor ?? config.backgroundColor,
1258
+ pageBorderColor: themeConfig?.pageBorderColor ?? config.pageBorderColor,
1259
+ pageSpacing: themeConfig?.pageSpacing ?? config.pageSpacing,
1260
+ toolbarColor: themeConfig?.toolbarColor ?? config.toolbarColor,
1261
+ textColor: themeConfig?.textColor ?? config.textColor,
1262
+ borderRadius: themeConfig?.borderRadius ?? config.borderRadius,
1263
+ customCSS: this._mergePdfViewerCss(themeConfig?.customCSS ?? config.customCSS),
1264
+ cspNonce: themeConfig?.cspNonce ?? config.cspNonce,
1265
+ iframeTitle: themeConfig?.iframeTitle ?? config.iframeTitle,
1266
+ urlValidation: config.urlValidation ?? true,
1267
+ controlVisibility: controlVisibility ?? {},
1268
+ groupVisibility: groupVisibility ?? {},
1269
+ autoActions: autoActions ?? {},
1270
+ viewerConfig: viewerConfig ?? {},
1271
+ themeConfig: themeConfig ?? {},
1272
+ layoutConfig: layoutConfig ?? {},
1273
+ };
1274
+ }, ...(ngDevMode ? [{ debugName: "pdfViewerConfig" }] : []));
1275
+ _mergePdfViewerCss(customCSS) {
1276
+ if (!customCSS) {
1277
+ return Z_GALLERY_PDF_VIEWER_CHROME_CSS;
1278
+ }
1279
+ return `${Z_GALLERY_PDF_VIEWER_CHROME_CSS}\n${customCSS}`;
1280
+ }
1281
+ isVideo = computed(() => getFileCategory(this.file()) === 'video', ...(ngDevMode ? [{ debugName: "isVideo" }] : []));
1282
+ isWordFile = computed(() => getFileCategory(this.file()) === 'word', ...(ngDevMode ? [{ debugName: "isWordFile" }] : []));
1283
+ isExcelFile = computed(() => getFileCategory(this.file()) === 'excel', ...(ngDevMode ? [{ debugName: "isExcelFile" }] : []));
1284
+ isTextFile = computed(() => {
1285
+ const category = getFileCategory(this.file());
1286
+ return category === 'text' || category === 'code';
1287
+ }, ...(ngDevMode ? [{ debugName: "isTextFile" }] : []));
1288
+ canPreview = computed(() => isPreviewable(this.file()), ...(ngDevMode ? [{ debugName: "canPreview" }] : []));
1289
+ formattedSize = computed(() => formatFileSize(this.file().size), ...(ngDevMode ? [{ debugName: "formattedSize" }] : []));
1290
+ imageTransform = computed(() => {
1291
+ const rot = this.rotation();
1292
+ const zoom = this.zoomed() ? 'scale(1.5)' : 'scale(1)';
1293
+ return `rotate(${rot}deg) ${zoom}`;
1294
+ }, ...(ngDevMode ? [{ debugName: "imageTransform" }] : []));
1295
+ _isAllowedResourceUrl(url) {
1296
+ const currentOrigin = globalThis.location?.origin;
1297
+ const baseUrl = currentOrigin ?? 'http://localhost';
1298
+ try {
1299
+ const parsedUrl = new URL(url, baseUrl);
1300
+ if (parsedUrl.protocol === 'blob:') {
1301
+ return parsedUrl.origin === baseUrl;
1302
+ }
1303
+ return parsedUrl.origin === baseUrl || this._trustedOrigins().has(parsedUrl.origin);
1304
+ }
1305
+ catch {
1306
+ return false;
1307
+ }
1308
+ }
1309
+ _trustedOrigins = computed(() => new Set(this.zTrustedResourceOrigins()
1310
+ .map(origin => this._normalizeOrigin(origin))
1311
+ .filter((origin) => Boolean(origin))), ...(ngDevMode ? [{ debugName: "_trustedOrigins" }] : []));
1312
+ _normalizeOrigin(origin) {
1313
+ try {
1314
+ return new URL(origin).origin;
1315
+ }
1316
+ catch {
1317
+ return null;
1318
+ }
1319
+ }
1320
+ fileIcon = computed(() => {
1321
+ const category = getFileCategory(this.file());
1322
+ const iconMap = {
1323
+ pdf: 'lucideFileText',
1324
+ word: 'lucideFileText',
1325
+ excel: 'lucideFileSpreadsheet',
1326
+ video: 'lucideVideo',
1327
+ audio: 'lucideMusic',
1328
+ archive: 'lucideFileArchive',
1329
+ code: 'lucideCode',
1330
+ text: 'lucideFileText',
1331
+ unknown: 'lucideFile',
1332
+ };
1333
+ return iconMap[category] || 'lucideFile';
1334
+ }, ...(ngDevMode ? [{ debugName: "fileIcon" }] : []));
1335
+ onKeyDown(event) {
1336
+ switch (event.key) {
1337
+ case 'Escape':
1338
+ this.close();
1339
+ break;
1340
+ case 'ArrowLeft':
1341
+ if (this.hasPrev()) {
1342
+ this.navigate(-1);
1343
+ }
1344
+ break;
1345
+ case 'ArrowRight':
1346
+ if (this.hasNext()) {
1347
+ this.navigate(1);
1348
+ }
1349
+ break;
1350
+ case 'r':
1351
+ case 'R':
1352
+ if (this.isImageFile()) {
1353
+ this.rotateRight();
1354
+ }
1355
+ break;
1356
+ }
1357
+ }
1358
+ close() {
1359
+ this.zOnClose.emit();
1360
+ }
1361
+ navigate(direction) {
1362
+ const allFiles = this.files();
1363
+ const newIndex = this.currentIndex() + direction;
1364
+ if (newIndex >= 0 && newIndex < allFiles.length) {
1365
+ this.zoomed.set(false);
1366
+ this.rotation.set(0);
1367
+ this.isLoading.set(true);
1368
+ this._mediaLoaded.set(false);
1369
+ this._loadingStartTime = Date.now();
1370
+ this.previewError.set(false);
1371
+ this.zOnNavigate.emit(allFiles[newIndex]);
1372
+ }
1373
+ }
1374
+ toggleZoom() {
1375
+ if (this.isImageFile()) {
1376
+ this.zoomed.update(z => !z);
1377
+ }
1378
+ }
1379
+ rotateLeft() {
1380
+ this.rotation.update(r => (r - 90 + 360) % 360);
1381
+ }
1382
+ rotateRight() {
1383
+ this.rotation.update(r => (r + 90) % 360);
1384
+ }
1385
+ onImageLoad() {
1386
+ this._completeLoading();
1387
+ }
1388
+ onVideoLoad() {
1389
+ this._completeLoading();
1390
+ }
1391
+ onPdfLoad() {
1392
+ this._queueMobilePdfFit();
1393
+ this._completeLoading();
1394
+ }
1395
+ onMediaError() {
1396
+ this.previewError.set(true);
1397
+ this._completeLoading();
1398
+ }
1399
+ download() {
1400
+ this.zOnDownload.emit(this.file());
1401
+ }
1402
+ remove() {
1403
+ this.zOnRemove.emit(this.file());
1404
+ }
1405
+ onBackdropClick(event) {
1406
+ if (event.target.classList.contains('fixed')) {
1407
+ this.close();
1408
+ }
1409
+ }
1410
+ _queueMobilePdfFit() {
1411
+ if (this.zPdfViewerConfig().zoom) {
1412
+ return;
1413
+ }
1414
+ const { defaultView } = this._document;
1415
+ if (!defaultView?.matchMedia('(max-width: 768px)').matches) {
1416
+ return;
1417
+ }
1418
+ const syncZoom = () => {
1419
+ void this.pdfViewer()?.setZoom('page-fit');
1420
+ };
1421
+ defaultView.requestAnimationFrame(() => {
1422
+ syncZoom();
1423
+ defaultView.setTimeout(syncZoom, 120);
1424
+ });
1425
+ }
1426
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1427
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", type: ZGalleryPreviewComponent, isStandalone: true, selector: "z-gallery-preview", inputs: { file: { classPropertyName: "file", publicName: "file", isSignal: true, isRequired: true, transformFunction: null }, files: { classPropertyName: "files", publicName: "files", isSignal: true, isRequired: false, transformFunction: null }, zShowRemove: { classPropertyName: "zShowRemove", publicName: "zShowRemove", isSignal: true, isRequired: false, transformFunction: null }, zPdfViewerConfig: { classPropertyName: "zPdfViewerConfig", publicName: "zPdfViewerConfig", isSignal: true, isRequired: false, transformFunction: null }, zTrustedResourceOrigins: { classPropertyName: "zTrustedResourceOrigins", publicName: "zTrustedResourceOrigins", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zOnClose: "zOnClose", zOnDownload: "zOnDownload", zOnNavigate: "zOnNavigate", zOnRemove: "zOnRemove" }, host: { listeners: { "document:keydown": "onKeyDown($event)" }, classAttribute: "z-gallery-preview z-[9999]" }, viewQueries: [{ propertyName: "pdfViewer", first: true, predicate: ["pdfViewer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"animate-in fade-in fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm duration-200\"\n (click)=\"onBackdropClick($event)\">\n <button\n z-button\n zType=\"ghost\"\n zShape=\"circle\"\n class=\"absolute top-3 right-3 z-20 text-white hover:bg-white/20 lg:top-4 lg:right-4\"\n (click)=\"close()\">\n <i z-icon zType=\"lucideX\" zSize=\"24\"></i>\n </button>\n\n @if (hasPrev()) {\n <button\n z-button\n zType=\"ghost\"\n zShape=\"circle\"\n class=\"absolute left-4 z-10 text-white hover:bg-white/20\"\n (click)=\"navigate(-1)\">\n <i z-icon zType=\"lucideChevronLeft\" zSize=\"32\"></i>\n </button>\n }\n\n @if (hasNext()) {\n <button\n z-button\n zType=\"ghost\"\n zShape=\"circle\"\n class=\"absolute right-4 z-10 text-white hover:bg-white/20\"\n (click)=\"navigate(1)\">\n <i z-icon zType=\"lucideChevronRight\" zSize=\"32\"></i>\n </button>\n }\n\n <div class=\"flex h-full w-full flex-col items-center\" (click)=\"$event.stopPropagation()\">\n <div\n class=\"dark:!border-border absolute top-3 right-14 left-3 z-10 flex min-w-0 items-center justify-between gap-2 rounded-[0.375rem] border !border-transparent bg-black/70 px-2.5 py-1.5 text-xs text-white shadow-lg backdrop-blur-sm lg:top-4 lg:right-auto lg:left-1/2 lg:max-w-[calc(100vw-10rem)] lg:-translate-x-1/2 lg:justify-start lg:bg-black/60 lg:px-4 lg:py-2 lg:text-sm dark:border\">\n <div class=\"flex min-w-0 items-baseline gap-1.5\">\n <span class=\"min-w-0 truncate font-medium lg:max-w-[12.5rem]\">{{ file().name }}</span>\n <span class=\"hidden shrink-0 text-white/70 lg:inline\">({{ formattedSize() }})</span>\n </div>\n\n @if (files().length > 1) {\n <span class=\"hidden shrink-0 text-white/70 md:inline\">{{ currentIndex() + 1 }} / {{ files().length }}</span>\n }\n\n <div class=\"ml-1 flex shrink-0 items-center gap-0.5\">\n @if (isImageFile()) {\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_rotate_left' | translate\"\n (click)=\"rotateLeft()\">\n <i z-icon zType=\"lucideUndo\" zSize=\"14\"></i>\n </button>\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_rotate_right' | translate\"\n (click)=\"rotateRight()\">\n <i z-icon zType=\"lucideRedo\" zSize=\"14\"></i>\n </button>\n }\n\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_download' | translate\"\n (click)=\"download()\">\n <i z-icon zType=\"lucideDownload\" zSize=\"14\"></i>\n </button>\n\n @if (zShowRemove()) {\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_delete' | translate\"\n (click)=\"remove()\">\n <i z-icon zType=\"lucideTrash2\" zSize=\"14\"></i>\n </button>\n }\n </div>\n </div>\n\n <div class=\"relative flex flex-1 items-center justify-center pt-16\">\n @if (isImageFile()) {\n <div class=\"relative flex h-[60vh] w-[70vw] items-center justify-center\">\n @if (isLoading()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (previewError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-8 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-16 items-center justify-center rounded-xl\">\n <i z-icon zType=\"lucideTriangleAlert\" zSize=\"28\" class=\"text-destructive\"></i>\n </div>\n <span class=\"text-foreground text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_preview_load_error' | translate }}\n </span>\n </div>\n } @else {\n <img\n [src]=\"file().url || file().thumbnailUrl\"\n [alt]=\"file().name\"\n class=\"max-h-full max-w-full rounded-lg object-contain shadow-2xl transition-opacity duration-300\"\n [class.opacity-0]=\"isLoading()\"\n [class.opacity-100]=\"!isLoading()\"\n [class.cursor-zoom-in]=\"!zoomed()\"\n [class.cursor-zoom-out]=\"zoomed()\"\n [style.transform]=\"imageTransform()\"\n (load)=\"onImageLoad()\"\n (error)=\"onMediaError()\"\n (click)=\"toggleZoom()\" />\n }\n </div>\n } @else if (isPdf() && pdfUrl()) {\n <div\n class=\"z-gallery-pdf-frame relative h-[75vh] w-[85vw] max-w-[96vw] overflow-hidden rounded-sm border shadow-xs\">\n @if (isLoading()) {\n <z-skeleton class=\"absolute inset-0 rounded-sm\" />\n <div\n class=\"text-muted-foreground absolute inset-0 z-10 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (previewError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center p-8\">\n <div class=\"bg-muted mb-4 flex size-16 items-center justify-center rounded-xl\">\n <i z-icon zType=\"lucideTriangleAlert\" zSize=\"28\" class=\"text-destructive\"></i>\n </div>\n <span class=\"text-foreground text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_preview_load_error' | translate }}\n </span>\n </div>\n } @else {\n <div\n class=\"relative size-full bg-white transition-opacity duration-300\"\n [class.opacity-0]=\"isLoading()\"\n [class.opacity-100]=\"!isLoading()\">\n @let pdfConfig = pdfViewerConfig();\n <ng2-pdfjs-viewer\n #pdfViewer\n class=\"block size-full\"\n [viewerFolder]=\"pdfConfig.viewerFolder!\"\n [viewerId]=\"pdfViewerId()\"\n [pdfSrc]=\"pdfUrl()!\"\n [downloadFileName]=\"file().name\"\n [locale]=\"pdfConfig.locale!\"\n [showSpinner]=\"pdfConfig.showSpinner!\"\n [useOnlyCssZoom]=\"pdfConfig.useOnlyCssZoom!\"\n [diagnosticLogs]=\"pdfConfig.diagnosticLogs!\"\n [showOpenFile]=\"pdfConfig.showOpenFile!\"\n [showAnnotations]=\"pdfConfig.showAnnotations!\"\n [showDownload]=\"pdfConfig.showDownload!\"\n [showViewBookmark]=\"pdfConfig.showViewBookmark!\"\n [showPrint]=\"pdfConfig.showPrint!\"\n [showFullScreen]=\"pdfConfig.showFullScreen!\"\n [showFind]=\"pdfConfig.showFind!\"\n [downloadOnLoad]=\"pdfConfig.downloadOnLoad!\"\n [printOnLoad]=\"pdfConfig.printOnLoad!\"\n [rotateCW]=\"pdfConfig.rotateCW!\"\n [rotateCCW]=\"pdfConfig.rotateCCW!\"\n [showLastPageOnLoad]=\"pdfConfig.showLastPageOnLoad!\"\n [showToolbarLeft]=\"pdfConfig.showToolbarLeft!\"\n [showToolbarMiddle]=\"pdfConfig.showToolbarMiddle!\"\n [showToolbarRight]=\"pdfConfig.showToolbarRight!\"\n [showSecondaryToolbarToggle]=\"pdfConfig.showSecondaryToolbarToggle!\"\n [showSidebar]=\"pdfConfig.showSidebar!\"\n [showSidebarLeft]=\"pdfConfig.showSidebarLeft!\"\n [showSidebarRight]=\"pdfConfig.showSidebarRight!\"\n [toolbarDensity]=\"pdfConfig.toolbarDensity!\"\n [sidebarWidth]=\"pdfConfig.sidebarWidth\"\n [toolbarPosition]=\"pdfConfig.toolbarPosition!\"\n [sidebarPosition]=\"pdfConfig.sidebarPosition!\"\n [responsiveBreakpoint]=\"pdfConfig.responsiveBreakpoint\"\n [zoom]=\"pdfConfig.zoom!\"\n [rotation]=\"pdfConfig.rotation!\"\n [cursor]=\"pdfConfig.cursor!\"\n [scroll]=\"pdfConfig.scroll!\"\n [spread]=\"pdfConfig.spread!\"\n [pageMode]=\"pdfConfig.pageMode!\"\n [page]=\"pdfConfig.page!\"\n [iframeBorder]=\"pdfConfig.iframeBorder!\"\n [theme]=\"pdfConfig.theme!\"\n [primaryColor]=\"pdfConfig.primaryColor\"\n [backgroundColor]=\"pdfConfig.backgroundColor\"\n [pageBorderColor]=\"pdfConfig.pageBorderColor\"\n [pageSpacing]=\"pdfConfig.pageSpacing\"\n [toolbarColor]=\"pdfConfig.toolbarColor\"\n [textColor]=\"pdfConfig.textColor\"\n [borderRadius]=\"pdfConfig.borderRadius\"\n [customCSS]=\"pdfConfig.customCSS\"\n [cspNonce]=\"pdfConfig.cspNonce\"\n [iframeTitle]=\"pdfConfig.iframeTitle || ('i18n_z_ui_gallery_pdf_preview' | translate)\"\n [urlValidation]=\"pdfConfig.urlValidation!\"\n [controlVisibility]=\"pdfConfig.controlVisibility!\"\n [groupVisibility]=\"pdfConfig.groupVisibility!\"\n [autoActions]=\"pdfConfig.autoActions!\"\n [viewerConfig]=\"pdfConfig.viewerConfig!\"\n [themeConfig]=\"pdfConfig.themeConfig!\"\n [layoutConfig]=\"pdfConfig.layoutConfig!\"\n (onDocumentLoad)=\"onPdfLoad()\"\n (onDocumentError)=\"onMediaError()\" />\n </div>\n }\n </div>\n } @else if (isVideo()) {\n <div class=\"relative flex h-[60vh] w-[70vw] items-center justify-center\">\n @if (isLoading()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (previewError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-8 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-16 items-center justify-center rounded-xl\">\n <i z-icon zType=\"lucideTriangleAlert\" zSize=\"28\" class=\"text-destructive\"></i>\n </div>\n <span class=\"text-foreground text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_preview_load_error' | translate }}\n </span>\n </div>\n } @else {\n <video\n [src]=\"file().url\"\n controls\n autoplay\n class=\"max-h-full max-w-full rounded-lg shadow-2xl transition-opacity duration-300\"\n [class.opacity-0]=\"isLoading()\"\n [class.opacity-100]=\"!isLoading()\"\n (loadeddata)=\"onVideoLoad()\"\n (error)=\"onMediaError()\">\n {{ 'i18n_z_ui_gallery_video_not_supported' | translate }}\n </video>\n }\n </div>\n } @else if (isWordFile()) {\n <div class=\"relative h-[75vh] w-[85vw]\">\n @if (isLoading() || isConverting()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (conversionError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground rounded-md bg-red-100 px-3 py-1.5 text-xs dark:bg-red-900/30\">\n <span class=\"text-red-700 dark:text-red-300\">{{ conversionError() }}</span>\n </span>\n </div>\n } @else if (docHtmlContent()) {\n <div\n class=\"absolute inset-0 overflow-auto rounded-lg bg-white p-8 text-gray-950 shadow-2xl\"\n [innerHTML]=\"docHtmlContent()\"></div>\n }\n </div>\n } @else if (isExcelFile()) {\n <div class=\"relative h-[75vh] w-[85vw]\">\n @if (isLoading() || isConverting()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (conversionError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground rounded-md bg-red-100 px-3 py-1.5 text-xs dark:bg-red-900/30\">\n <span class=\"text-red-700 dark:text-red-300\">{{ conversionError() }}</span>\n </span>\n </div>\n } @else if (docHtmlContent()) {\n <div\n class=\"absolute inset-0 overflow-auto rounded-lg bg-white p-4 text-gray-950 shadow-2xl\"\n [innerHTML]=\"docHtmlContent()\"></div>\n }\n </div>\n } @else if (isTextFile()) {\n <div class=\"relative h-[75vh] w-[85vw]\">\n @if (isLoading() || isConverting()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (conversionError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground rounded-md bg-red-100 px-3 py-1.5 text-xs dark:bg-red-900/30\">\n <span class=\"text-red-700 dark:text-red-300\">{{ conversionError() }}</span>\n </span>\n </div>\n } @else if (textContent()) {\n <div class=\"absolute inset-0 overflow-auto rounded-lg bg-gray-950 p-6 shadow-2xl\">\n <pre class=\"font-mono text-sm leading-relaxed whitespace-pre-wrap text-gray-100\">{{ textContent() }}</pre>\n </div>\n }\n </div>\n } @else {\n <div class=\"bg-card flex flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground mb-4 text-sm\">{{ formattedSize() }}</span>\n <span class=\"text-muted-foreground rounded-md bg-amber-100 px-3 py-1.5 text-xs dark:bg-amber-900/30\">\n <i\n z-icon\n zType=\"lucideInfo\"\n zSize=\"14\"\n class=\"mr-1 inline-block align-middle text-amber-600 dark:text-amber-400\"></i>\n <span class=\"align-middle text-amber-700 dark:text-amber-300\">\n {{ 'i18n_z_ui_gallery_preview_not_supported' | translate }}\n </span>\n </span>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [".z-gallery-pdf-frame,.z-gallery-pdf-frame *{border-color:#606060!important;outline-color:#606060!important}.z-gallery-pdf-frame{border-width:1px!important;border-style:solid!important;background:#606060}.z-gallery-pdf-frame ng2-pdfjs-viewer,.z-gallery-pdf-frame ng2-pdfjs-viewer iframe{display:block;width:100%;height:100%;border:0!important;outline:0!important;box-shadow:none!important;background:#606060}\n"], dependencies: [{ kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "ngmodule", type: PdfJsViewerModule }, { kind: "component", type: i1.PdfJsViewerComponent, selector: "ng2-pdfjs-viewer", inputs: ["viewerId", "viewerFolder", "externalWindow", "target", "showSpinner", "downloadFileName", "locale", "useOnlyCssZoom", "externalLinkTarget", "rememberLastView", "annotationEditor", "highlightEditorColors", "enableSignatureEditor", "signatureStorage", "pageColors", "pdfJsOptions", "enableCommentEditor", "enablePageEditing", "showToolbar", "chromeless", "customToolbarTpl", "customSidebarTpl", "aiAssistantConfig", "pageOverlayTpl", "httpHeaders", "withCredentials", "formData", "contentProtection", "iframeSandbox", "diagnosticLogs", "showOpenFile", "showAnnotations", "showDownload", "showViewBookmark", "showPrint", "showFullScreen", "showFind", "downloadOnLoad", "printOnLoad", "rotateCW", "rotateCCW", "showLastPageOnLoad", "namedDest", "errorOverride", "errorAppend", "errorMessage", "urlValidation", "customSecurityTpl", "theme", "primaryColor", "backgroundColor", "pageBorderColor", "pageSpacing", "toolbarColor", "textColor", "borderRadius", "customCSS", "cspNonce", "iframeTitle", "customSpinnerTpl", "spinnerClass", "customErrorTpl", "errorClass", "showToolbarLeft", "showToolbarMiddle", "showToolbarRight", "showSecondaryToolbarToggle", "showSidebar", "showSidebarLeft", "showSidebarRight", "toolbarDensity", "sidebarWidth", "toolbarPosition", "sidebarPosition", "responsiveBreakpoint", "controlVisibility", "autoActions", "errorHandling", "viewerConfig", "themeConfig", "groupVisibility", "layoutConfig", "startDownload", "startPrint", "openFile", "download", "print", "fullScreen", "find", "viewBookmark", "lastPage", "externalWindowOptions", "iframeBorder", "zoom", "rotation", "cursor", "scroll", "spread", "pageMode", "page", "pdfSrc"], outputs: ["onBeforePrint", "onAfterPrint", "onDocumentLoad", "onPageChange", "onScaleChange", "onRotationChange", "onDocumentError", "onDocumentInit", "onPagesInit", "onPresentationModeChanged", "onOpenFile", "onFind", "onUpdateFindMatchesCount", "onMetadataLoaded", "onOutlineLoaded", "onPageRendered", "onAnnotationLayerRendered", "onBookmarkClick", "onIdle", "onPasswordPrompt", "onAnnotationEditorStateChange", "onPagesEdited", "onReadAloudStateChange", "onSidebarViewChanged", "onLayersChanged", "onNamedAction", "onDocumentProperties", "annotationEditorChange", "onProgress", "formDataChange", "zoomChange", "cursorChange", "scrollChange", "spreadChange", "pageModeChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1428
+ }
1429
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewComponent, decorators: [{
1430
+ type: Component,
1431
+ args: [{ selector: 'z-gallery-preview', imports: [ZButtonComponent, ZIconComponent, ZSkeletonComponent, ZTooltipDirective, TranslatePipe, PdfJsViewerModule], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1432
+ class: 'z-gallery-preview z-[9999]',
1433
+ '(document:keydown)': 'onKeyDown($event)',
1434
+ }, template: "<div\n class=\"animate-in fade-in fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm duration-200\"\n (click)=\"onBackdropClick($event)\">\n <button\n z-button\n zType=\"ghost\"\n zShape=\"circle\"\n class=\"absolute top-3 right-3 z-20 text-white hover:bg-white/20 lg:top-4 lg:right-4\"\n (click)=\"close()\">\n <i z-icon zType=\"lucideX\" zSize=\"24\"></i>\n </button>\n\n @if (hasPrev()) {\n <button\n z-button\n zType=\"ghost\"\n zShape=\"circle\"\n class=\"absolute left-4 z-10 text-white hover:bg-white/20\"\n (click)=\"navigate(-1)\">\n <i z-icon zType=\"lucideChevronLeft\" zSize=\"32\"></i>\n </button>\n }\n\n @if (hasNext()) {\n <button\n z-button\n zType=\"ghost\"\n zShape=\"circle\"\n class=\"absolute right-4 z-10 text-white hover:bg-white/20\"\n (click)=\"navigate(1)\">\n <i z-icon zType=\"lucideChevronRight\" zSize=\"32\"></i>\n </button>\n }\n\n <div class=\"flex h-full w-full flex-col items-center\" (click)=\"$event.stopPropagation()\">\n <div\n class=\"dark:!border-border absolute top-3 right-14 left-3 z-10 flex min-w-0 items-center justify-between gap-2 rounded-[0.375rem] border !border-transparent bg-black/70 px-2.5 py-1.5 text-xs text-white shadow-lg backdrop-blur-sm lg:top-4 lg:right-auto lg:left-1/2 lg:max-w-[calc(100vw-10rem)] lg:-translate-x-1/2 lg:justify-start lg:bg-black/60 lg:px-4 lg:py-2 lg:text-sm dark:border\">\n <div class=\"flex min-w-0 items-baseline gap-1.5\">\n <span class=\"min-w-0 truncate font-medium lg:max-w-[12.5rem]\">{{ file().name }}</span>\n <span class=\"hidden shrink-0 text-white/70 lg:inline\">({{ formattedSize() }})</span>\n </div>\n\n @if (files().length > 1) {\n <span class=\"hidden shrink-0 text-white/70 md:inline\">{{ currentIndex() + 1 }} / {{ files().length }}</span>\n }\n\n <div class=\"ml-1 flex shrink-0 items-center gap-0.5\">\n @if (isImageFile()) {\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_rotate_left' | translate\"\n (click)=\"rotateLeft()\">\n <i z-icon zType=\"lucideUndo\" zSize=\"14\"></i>\n </button>\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_rotate_right' | translate\"\n (click)=\"rotateRight()\">\n <i z-icon zType=\"lucideRedo\" zSize=\"14\"></i>\n </button>\n }\n\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_download' | translate\"\n (click)=\"download()\">\n <i z-icon zType=\"lucideDownload\" zSize=\"14\"></i>\n </button>\n\n @if (zShowRemove()) {\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_delete' | translate\"\n (click)=\"remove()\">\n <i z-icon zType=\"lucideTrash2\" zSize=\"14\"></i>\n </button>\n }\n </div>\n </div>\n\n <div class=\"relative flex flex-1 items-center justify-center pt-16\">\n @if (isImageFile()) {\n <div class=\"relative flex h-[60vh] w-[70vw] items-center justify-center\">\n @if (isLoading()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (previewError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-8 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-16 items-center justify-center rounded-xl\">\n <i z-icon zType=\"lucideTriangleAlert\" zSize=\"28\" class=\"text-destructive\"></i>\n </div>\n <span class=\"text-foreground text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_preview_load_error' | translate }}\n </span>\n </div>\n } @else {\n <img\n [src]=\"file().url || file().thumbnailUrl\"\n [alt]=\"file().name\"\n class=\"max-h-full max-w-full rounded-lg object-contain shadow-2xl transition-opacity duration-300\"\n [class.opacity-0]=\"isLoading()\"\n [class.opacity-100]=\"!isLoading()\"\n [class.cursor-zoom-in]=\"!zoomed()\"\n [class.cursor-zoom-out]=\"zoomed()\"\n [style.transform]=\"imageTransform()\"\n (load)=\"onImageLoad()\"\n (error)=\"onMediaError()\"\n (click)=\"toggleZoom()\" />\n }\n </div>\n } @else if (isPdf() && pdfUrl()) {\n <div\n class=\"z-gallery-pdf-frame relative h-[75vh] w-[85vw] max-w-[96vw] overflow-hidden rounded-sm border shadow-xs\">\n @if (isLoading()) {\n <z-skeleton class=\"absolute inset-0 rounded-sm\" />\n <div\n class=\"text-muted-foreground absolute inset-0 z-10 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (previewError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center p-8\">\n <div class=\"bg-muted mb-4 flex size-16 items-center justify-center rounded-xl\">\n <i z-icon zType=\"lucideTriangleAlert\" zSize=\"28\" class=\"text-destructive\"></i>\n </div>\n <span class=\"text-foreground text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_preview_load_error' | translate }}\n </span>\n </div>\n } @else {\n <div\n class=\"relative size-full bg-white transition-opacity duration-300\"\n [class.opacity-0]=\"isLoading()\"\n [class.opacity-100]=\"!isLoading()\">\n @let pdfConfig = pdfViewerConfig();\n <ng2-pdfjs-viewer\n #pdfViewer\n class=\"block size-full\"\n [viewerFolder]=\"pdfConfig.viewerFolder!\"\n [viewerId]=\"pdfViewerId()\"\n [pdfSrc]=\"pdfUrl()!\"\n [downloadFileName]=\"file().name\"\n [locale]=\"pdfConfig.locale!\"\n [showSpinner]=\"pdfConfig.showSpinner!\"\n [useOnlyCssZoom]=\"pdfConfig.useOnlyCssZoom!\"\n [diagnosticLogs]=\"pdfConfig.diagnosticLogs!\"\n [showOpenFile]=\"pdfConfig.showOpenFile!\"\n [showAnnotations]=\"pdfConfig.showAnnotations!\"\n [showDownload]=\"pdfConfig.showDownload!\"\n [showViewBookmark]=\"pdfConfig.showViewBookmark!\"\n [showPrint]=\"pdfConfig.showPrint!\"\n [showFullScreen]=\"pdfConfig.showFullScreen!\"\n [showFind]=\"pdfConfig.showFind!\"\n [downloadOnLoad]=\"pdfConfig.downloadOnLoad!\"\n [printOnLoad]=\"pdfConfig.printOnLoad!\"\n [rotateCW]=\"pdfConfig.rotateCW!\"\n [rotateCCW]=\"pdfConfig.rotateCCW!\"\n [showLastPageOnLoad]=\"pdfConfig.showLastPageOnLoad!\"\n [showToolbarLeft]=\"pdfConfig.showToolbarLeft!\"\n [showToolbarMiddle]=\"pdfConfig.showToolbarMiddle!\"\n [showToolbarRight]=\"pdfConfig.showToolbarRight!\"\n [showSecondaryToolbarToggle]=\"pdfConfig.showSecondaryToolbarToggle!\"\n [showSidebar]=\"pdfConfig.showSidebar!\"\n [showSidebarLeft]=\"pdfConfig.showSidebarLeft!\"\n [showSidebarRight]=\"pdfConfig.showSidebarRight!\"\n [toolbarDensity]=\"pdfConfig.toolbarDensity!\"\n [sidebarWidth]=\"pdfConfig.sidebarWidth\"\n [toolbarPosition]=\"pdfConfig.toolbarPosition!\"\n [sidebarPosition]=\"pdfConfig.sidebarPosition!\"\n [responsiveBreakpoint]=\"pdfConfig.responsiveBreakpoint\"\n [zoom]=\"pdfConfig.zoom!\"\n [rotation]=\"pdfConfig.rotation!\"\n [cursor]=\"pdfConfig.cursor!\"\n [scroll]=\"pdfConfig.scroll!\"\n [spread]=\"pdfConfig.spread!\"\n [pageMode]=\"pdfConfig.pageMode!\"\n [page]=\"pdfConfig.page!\"\n [iframeBorder]=\"pdfConfig.iframeBorder!\"\n [theme]=\"pdfConfig.theme!\"\n [primaryColor]=\"pdfConfig.primaryColor\"\n [backgroundColor]=\"pdfConfig.backgroundColor\"\n [pageBorderColor]=\"pdfConfig.pageBorderColor\"\n [pageSpacing]=\"pdfConfig.pageSpacing\"\n [toolbarColor]=\"pdfConfig.toolbarColor\"\n [textColor]=\"pdfConfig.textColor\"\n [borderRadius]=\"pdfConfig.borderRadius\"\n [customCSS]=\"pdfConfig.customCSS\"\n [cspNonce]=\"pdfConfig.cspNonce\"\n [iframeTitle]=\"pdfConfig.iframeTitle || ('i18n_z_ui_gallery_pdf_preview' | translate)\"\n [urlValidation]=\"pdfConfig.urlValidation!\"\n [controlVisibility]=\"pdfConfig.controlVisibility!\"\n [groupVisibility]=\"pdfConfig.groupVisibility!\"\n [autoActions]=\"pdfConfig.autoActions!\"\n [viewerConfig]=\"pdfConfig.viewerConfig!\"\n [themeConfig]=\"pdfConfig.themeConfig!\"\n [layoutConfig]=\"pdfConfig.layoutConfig!\"\n (onDocumentLoad)=\"onPdfLoad()\"\n (onDocumentError)=\"onMediaError()\" />\n </div>\n }\n </div>\n } @else if (isVideo()) {\n <div class=\"relative flex h-[60vh] w-[70vw] items-center justify-center\">\n @if (isLoading()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (previewError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-8 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-16 items-center justify-center rounded-xl\">\n <i z-icon zType=\"lucideTriangleAlert\" zSize=\"28\" class=\"text-destructive\"></i>\n </div>\n <span class=\"text-foreground text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_preview_load_error' | translate }}\n </span>\n </div>\n } @else {\n <video\n [src]=\"file().url\"\n controls\n autoplay\n class=\"max-h-full max-w-full rounded-lg shadow-2xl transition-opacity duration-300\"\n [class.opacity-0]=\"isLoading()\"\n [class.opacity-100]=\"!isLoading()\"\n (loadeddata)=\"onVideoLoad()\"\n (error)=\"onMediaError()\">\n {{ 'i18n_z_ui_gallery_video_not_supported' | translate }}\n </video>\n }\n </div>\n } @else if (isWordFile()) {\n <div class=\"relative h-[75vh] w-[85vw]\">\n @if (isLoading() || isConverting()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (conversionError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground rounded-md bg-red-100 px-3 py-1.5 text-xs dark:bg-red-900/30\">\n <span class=\"text-red-700 dark:text-red-300\">{{ conversionError() }}</span>\n </span>\n </div>\n } @else if (docHtmlContent()) {\n <div\n class=\"absolute inset-0 overflow-auto rounded-lg bg-white p-8 text-gray-950 shadow-2xl\"\n [innerHTML]=\"docHtmlContent()\"></div>\n }\n </div>\n } @else if (isExcelFile()) {\n <div class=\"relative h-[75vh] w-[85vw]\">\n @if (isLoading() || isConverting()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (conversionError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground rounded-md bg-red-100 px-3 py-1.5 text-xs dark:bg-red-900/30\">\n <span class=\"text-red-700 dark:text-red-300\">{{ conversionError() }}</span>\n </span>\n </div>\n } @else if (docHtmlContent()) {\n <div\n class=\"absolute inset-0 overflow-auto rounded-lg bg-white p-4 text-gray-950 shadow-2xl\"\n [innerHTML]=\"docHtmlContent()\"></div>\n }\n </div>\n } @else if (isTextFile()) {\n <div class=\"relative h-[75vh] w-[85vw]\">\n @if (isLoading() || isConverting()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (conversionError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground rounded-md bg-red-100 px-3 py-1.5 text-xs dark:bg-red-900/30\">\n <span class=\"text-red-700 dark:text-red-300\">{{ conversionError() }}</span>\n </span>\n </div>\n } @else if (textContent()) {\n <div class=\"absolute inset-0 overflow-auto rounded-lg bg-gray-950 p-6 shadow-2xl\">\n <pre class=\"font-mono text-sm leading-relaxed whitespace-pre-wrap text-gray-100\">{{ textContent() }}</pre>\n </div>\n }\n </div>\n } @else {\n <div class=\"bg-card flex flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground mb-4 text-sm\">{{ formattedSize() }}</span>\n <span class=\"text-muted-foreground rounded-md bg-amber-100 px-3 py-1.5 text-xs dark:bg-amber-900/30\">\n <i\n z-icon\n zType=\"lucideInfo\"\n zSize=\"14\"\n class=\"mr-1 inline-block align-middle text-amber-600 dark:text-amber-400\"></i>\n <span class=\"align-middle text-amber-700 dark:text-amber-300\">\n {{ 'i18n_z_ui_gallery_preview_not_supported' | translate }}\n </span>\n </span>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [".z-gallery-pdf-frame,.z-gallery-pdf-frame *{border-color:#606060!important;outline-color:#606060!important}.z-gallery-pdf-frame{border-width:1px!important;border-style:solid!important;background:#606060}.z-gallery-pdf-frame ng2-pdfjs-viewer,.z-gallery-pdf-frame ng2-pdfjs-viewer iframe{display:block;width:100%;height:100%;border:0!important;outline:0!important;box-shadow:none!important;background:#606060}\n"] }]
1435
+ }], ctorParameters: () => [], propDecorators: { file: [{ type: i0.Input, args: [{ isSignal: true, alias: "file", required: true }] }], files: [{ type: i0.Input, args: [{ isSignal: true, alias: "files", required: false }] }], zShowRemove: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowRemove", required: false }] }], zPdfViewerConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPdfViewerConfig", required: false }] }], zTrustedResourceOrigins: [{ type: i0.Input, args: [{ isSignal: true, alias: "zTrustedResourceOrigins", required: false }] }], zOnClose: [{ type: i0.Output, args: ["zOnClose"] }], zOnDownload: [{ type: i0.Output, args: ["zOnDownload"] }], zOnNavigate: [{ type: i0.Output, args: ["zOnNavigate"] }], zOnRemove: [{ type: i0.Output, args: ["zOnRemove"] }], pdfViewer: [{ type: i0.ViewChild, args: ['pdfViewer', { isSignal: true }] }] } });
1436
+
1437
+ class ZGalleryPreviewRef {
1438
+ _overlayRef;
1439
+ _closed = false;
1440
+ componentInstance = null;
1441
+ zAfterClose = new EventEmitter();
1442
+ constructor(_overlayRef) {
1443
+ this._overlayRef = _overlayRef;
1444
+ }
1445
+ close() {
1446
+ if (this._closed) {
1447
+ return;
1448
+ }
1449
+ this._closed = true;
1450
+ this.zAfterClose.emit();
1451
+ this.zAfterClose.complete();
1452
+ this._overlayRef?.dispose();
1453
+ }
1454
+ }
1455
+
1456
+ class ZGalleryPreviewService {
1457
+ _document = inject(DOCUMENT);
1458
+ _injector = inject(Injector);
1459
+ _overlay = inject(Overlay);
1460
+ _platformId = inject(PLATFORM_ID);
1461
+ _zIndexService = inject(ZOverlayZIndexService);
1462
+ open(fileOrOptions, options = {}) {
1463
+ const previewOptions = this._normalizeOptions(fileOrOptions, options);
1464
+ const overlayRef = this._createOverlay();
1465
+ const previewRef = new ZGalleryPreviewRef(overlayRef ?? null);
1466
+ if (!overlayRef) {
1467
+ return previewRef;
1468
+ }
1469
+ const componentRef = overlayRef.attach(new ComponentPortal(ZGalleryPreviewComponent, null, this._injector));
1470
+ previewRef.componentInstance = componentRef.instance;
1471
+ componentRef.setInput('file', previewOptions.file);
1472
+ componentRef.setInput('files', previewOptions.files);
1473
+ componentRef.setInput('zShowRemove', previewOptions.zShowRemove ?? false);
1474
+ componentRef.setInput('zPdfViewerConfig', previewOptions.zPdfViewerConfig ?? {});
1475
+ componentRef.setInput('zTrustedResourceOrigins', previewOptions.zTrustedResourceOrigins ?? []);
1476
+ componentRef.instance.zOnClose.subscribe(() => {
1477
+ previewOptions.zOnClose?.();
1478
+ previewRef.close();
1479
+ });
1480
+ componentRef.instance.zOnDownload.subscribe(file => this._handleDownload(file, previewOptions));
1481
+ componentRef.instance.zOnNavigate.subscribe(file => {
1482
+ componentRef.setInput('file', file);
1483
+ previewOptions.zOnNavigate?.(file);
1484
+ });
1485
+ componentRef.instance.zOnRemove.subscribe(file => previewOptions.zOnRemove?.(file));
1486
+ return previewRef;
1487
+ }
1488
+ _createOverlay() {
1489
+ if (!isPlatformBrowser(this._platformId)) {
1490
+ return undefined;
1491
+ }
1492
+ const overlayRef = this._overlay.create(new OverlayConfig({
1493
+ hasBackdrop: false,
1494
+ panelClass: 'z-gallery-preview-overlay-pane',
1495
+ positionStrategy: this._overlay.position().global(),
1496
+ scrollStrategy: this._overlay.scrollStrategies.block(),
1497
+ }));
1498
+ this._zIndexService.applyToOverlay(overlayRef);
1499
+ this._zIndexService.deferMoveToTop(overlayRef);
1500
+ return overlayRef;
1501
+ }
1502
+ _normalizeOptions(fileOrOptions, options) {
1503
+ const previewOptions = 'file' in fileOrOptions ? fileOrOptions : { ...options, file: fileOrOptions };
1504
+ const files = previewOptions.files?.length ? previewOptions.files : [previewOptions.file];
1505
+ const hasCurrentFile = files.some(file => file.id === previewOptions.file.id);
1506
+ return {
1507
+ ...previewOptions,
1508
+ files: hasCurrentFile ? files : [previewOptions.file, ...files],
1509
+ };
1510
+ }
1511
+ _handleDownload(file, options) {
1512
+ options.zOnDownload?.(file);
1513
+ if (options.zDownload === false) {
1514
+ return;
1515
+ }
1516
+ const downloadLink = file.downloadUrl || file.url;
1517
+ if (!downloadLink || !isPlatformBrowser(this._platformId)) {
1518
+ return;
1519
+ }
1520
+ const link = this._document.createElement('a');
1521
+ link.href = downloadLink;
1522
+ link.download = file.name;
1523
+ link.target = '_blank';
1524
+ this._document.body.appendChild(link);
1525
+ link.click();
1526
+ this._document.body.removeChild(link);
1527
+ }
1528
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1529
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewService, providedIn: 'root' });
1530
+ }
1531
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewService, decorators: [{
1532
+ type: Injectable,
1533
+ args: [{
1534
+ providedIn: 'root',
1535
+ }]
1536
+ }] });
1537
+
1538
+ const zGalleryVariants = cva('z-gallery', {
1539
+ variants: {
1540
+ zSize: {
1541
+ sm: 'z-gallery--sm',
1542
+ default: 'z-gallery--default',
1543
+ lg: 'z-gallery--lg',
1544
+ },
1545
+ },
1546
+ defaultVariants: {
1547
+ zSize: 'default',
1548
+ },
1549
+ });
1550
+ // Grid item variants
1551
+ const zGalleryItemVariants = cva('group relative overflow-hidden rounded-lg border border-border bg-card transition-all duration-200 cursor-pointer', {
1552
+ variants: {
1553
+ zMode: {
1554
+ grid: 'flex flex-col hover:scale-[1.02] hover:shadow-md hover:border-primary/50',
1555
+ list: 'flex flex-row items-center gap-3 p-3 hover:bg-accent hover:border-primary/50',
1556
+ },
1557
+ zSize: {
1558
+ sm: '',
1559
+ default: '',
1560
+ lg: '',
1561
+ },
1562
+ },
1563
+ compoundVariants: [
1564
+ // Grid sizes
1565
+ { zMode: 'grid', zSize: 'sm', class: '' },
1566
+ { zMode: 'grid', zSize: 'default', class: '' },
1567
+ { zMode: 'grid', zSize: 'lg', class: '' },
1568
+ // List sizes
1569
+ { zMode: 'list', zSize: 'sm', class: 'p-2' },
1570
+ { zMode: 'list', zSize: 'default', class: 'p-3' },
1571
+ { zMode: 'list', zSize: 'lg', class: 'p-4' },
1572
+ ],
1573
+ defaultVariants: {
1574
+ zMode: 'grid',
1575
+ zSize: 'default',
1576
+ },
1577
+ });
1578
+ // File icon badge variants
1579
+ const zGalleryFileIconVariants = cva('flex items-center justify-center rounded-md font-bold uppercase select-none', {
1580
+ variants: {
1581
+ zSize: {
1582
+ sm: 'w-full h-16 text-xs',
1583
+ default: 'w-full h-24 text-sm',
1584
+ lg: 'w-full h-32 text-base',
1585
+ },
1586
+ zMode: {
1587
+ grid: '',
1588
+ list: '',
1589
+ },
1590
+ },
1591
+ compoundVariants: [
1592
+ { zMode: 'list', zSize: 'sm', class: 'size-8 text-[0.625rem]' },
1593
+ { zMode: 'list', zSize: 'default', class: 'size-10 text-xs' },
1594
+ { zMode: 'list', zSize: 'lg', class: 'size-12 text-sm' },
1595
+ ],
1596
+ defaultVariants: {
1597
+ zSize: 'default',
1598
+ zMode: 'grid',
1599
+ },
1600
+ });
1601
+
1602
+ class ZGalleryComponent {
1603
+ _destroyRef = inject(DestroyRef);
1604
+ _previewService = inject(ZGalleryPreviewService);
1605
+ _previewRef = null;
1606
+ zFiles = input([], ...(ngDevMode ? [{ debugName: "zFiles" }] : []));
1607
+ zMode = model('grid', ...(ngDevMode ? [{ debugName: "zMode" }] : []));
1608
+ zSize = input('default', ...(ngDevMode ? [{ debugName: "zSize" }] : []));
1609
+ zColumns = input(4, ...(ngDevMode ? [{ debugName: "zColumns" }] : []));
1610
+ zItemWidth = input(null, ...(ngDevMode ? [{ debugName: "zItemWidth" }] : []));
1611
+ zLoading = input(false, ...(ngDevMode ? [{ debugName: "zLoading" }] : []));
1612
+ zSkeletonRows = input(2, ...(ngDevMode ? [{ debugName: "zSkeletonRows" }] : []));
1613
+ zSkeletonItems = input(null, ...(ngDevMode ? [{ debugName: "zSkeletonItems" }] : []));
1614
+ zShowDownload = input(true, ...(ngDevMode ? [{ debugName: "zShowDownload" }] : []));
1615
+ zShowPreview = input(true, ...(ngDevMode ? [{ debugName: "zShowPreview" }] : []));
1616
+ zShowRemove = input(false, ...(ngDevMode ? [{ debugName: "zShowRemove" }] : []));
1617
+ zPdfViewerConfig = input({}, ...(ngDevMode ? [{ debugName: "zPdfViewerConfig" }] : []));
1618
+ zTrustedResourceOrigins = input([], ...(ngDevMode ? [{ debugName: "zTrustedResourceOrigins" }] : []));
1619
+ zShowModeToggle = input(true, ...(ngDevMode ? [{ debugName: "zShowModeToggle" }] : []));
1620
+ zShowSearch = input(false, ...(ngDevMode ? [{ debugName: "zShowSearch" }] : []));
1621
+ zServerSearch = input(false, ...(ngDevMode ? [{ debugName: "zServerSearch" }] : []));
1622
+ zSearchDebounce = input(300, ...(ngDevMode ? [{ debugName: "zSearchDebounce" }] : []));
1623
+ zSearchPlaceholder = input('Search files...', ...(ngDevMode ? [{ debugName: "zSearchPlaceholder" }] : []));
1624
+ zToggleSize = input('default', ...(ngDevMode ? [{ debugName: "zToggleSize" }] : []));
1625
+ zTitle = input('', ...(ngDevMode ? [{ debugName: "zTitle" }] : []));
1626
+ zEmptyText = input('No files', ...(ngDevMode ? [{ debugName: "zEmptyText" }] : []));
1627
+ zEmptyIcon = input('lucideImage', ...(ngDevMode ? [{ debugName: "zEmptyIcon" }] : []));
1628
+ zClass = input('', ...(ngDevMode ? [{ debugName: "zClass" }] : []));
1629
+ zSelectable = input(false, ...(ngDevMode ? [{ debugName: "zSelectable" }] : []));
1630
+ zSelectedFiles = model([], ...(ngDevMode ? [{ debugName: "zSelectedFiles" }] : []));
1631
+ zOnDownload = output();
1632
+ zOnPreview = output();
1633
+ zOnRemove = output();
1634
+ zModeChange = output();
1635
+ zSearchChange = output();
1636
+ zControl = output();
1637
+ zSelectionChange = output();
1638
+ zOnAction = output();
1639
+ modeIndex = signal(0, ...(ngDevMode ? [{ debugName: "modeIndex" }] : []));
1640
+ searchInputQuery = signal('', ...(ngDevMode ? [{ debugName: "searchInputQuery" }] : []));
1641
+ searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
1642
+ skeletonItems = computed(() => {
1643
+ const itemCount = this.zSkeletonItems();
1644
+ if (itemCount !== null) {
1645
+ return Array.from({ length: Math.max(1, itemCount) }, (_, index) => index);
1646
+ }
1647
+ const columns = this.currentMode() === 'list' ? 1 : Math.max(1, this.zColumns());
1648
+ const rows = Math.max(1, this.zSkeletonRows());
1649
+ return Array.from({ length: columns * rows }, (_, index) => index);
1650
+ }, ...(ngDevMode ? [{ debugName: "skeletonItems" }] : []));
1651
+ currentMode = computed(() => {
1652
+ const index = this.modeIndex();
1653
+ return index === 1 ? 'list' : 'grid';
1654
+ }, ...(ngDevMode ? [{ debugName: "currentMode" }] : []));
1655
+ gridColumnsClass = computed(() => {
1656
+ if (this.zItemWidth()) {
1657
+ return 'justify-start';
1658
+ }
1659
+ const cols = this.zColumns();
1660
+ switch (cols) {
1661
+ case 1:
1662
+ return 'grid-cols-1';
1663
+ case 2:
1664
+ return 'grid-cols-1 sm:grid-cols-2';
1665
+ case 3:
1666
+ return 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3';
1667
+ case 4:
1668
+ return 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4';
1669
+ case 5:
1670
+ return 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5';
1671
+ case 6:
1672
+ return 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6';
1673
+ default:
1674
+ return `grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-${cols}`;
1675
+ }
1676
+ }, ...(ngDevMode ? [{ debugName: "gridColumnsClass" }] : []));
1677
+ gridTemplateColumns = computed(() => {
1678
+ const itemWidth = this.zItemWidth();
1679
+ return itemWidth ? `repeat(auto-fill, minmax(${itemWidth}, ${itemWidth}))` : null;
1680
+ }, ...(ngDevMode ? [{ debugName: "gridTemplateColumns" }] : []));
1681
+ containerClasses = computed(() => zMergeClasses(zGalleryVariants({ zSize: this.zSize() }), this.zClass()), ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
1682
+ showHeader = computed(() => this.zTitle() || this.zShowSearch() || (this.zShowModeToggle() && (this.zFiles().length > 0 || this.zLoading())), ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
1683
+ headerControlHeight = computed(() => {
1684
+ switch (this.zToggleSize()) {
1685
+ case 'xs':
1686
+ return '1.75rem';
1687
+ case 'sm':
1688
+ return '2rem';
1689
+ case 'lg':
1690
+ return '2.5rem';
1691
+ default:
1692
+ return '2.25rem';
1693
+ }
1694
+ }, ...(ngDevMode ? [{ debugName: "headerControlHeight" }] : []));
1695
+ skeletonMediaHeight = computed(() => {
1696
+ switch (this.zSize()) {
1697
+ case 'sm':
1698
+ return '9rem';
1699
+ case 'lg':
1700
+ return '14rem';
1701
+ default:
1702
+ return '11rem';
1703
+ }
1704
+ }, ...(ngDevMode ? [{ debugName: "skeletonMediaHeight" }] : []));
1705
+ toggleIconSize = computed(() => {
1706
+ const size = this.zToggleSize();
1707
+ switch (size) {
1708
+ case 'xs':
1709
+ return '14';
1710
+ case 'sm':
1711
+ return '16';
1712
+ case 'lg':
1713
+ return '20';
1714
+ default:
1715
+ return '18';
1716
+ }
1717
+ }, ...(ngDevMode ? [{ debugName: "toggleIconSize" }] : []));
1718
+ searchInputSize = computed(() => {
1719
+ const size = this.zToggleSize();
1720
+ if (size === 'xs') {
1721
+ return 'sm';
1722
+ }
1723
+ return size;
1724
+ }, ...(ngDevMode ? [{ debugName: "searchInputSize" }] : []));
1725
+ filteredFiles = computed(() => {
1726
+ const files = this.zFiles();
1727
+ const query = this.searchQuery().toLowerCase().trim();
1728
+ if (!query || this.zServerSearch()) {
1729
+ return files;
1730
+ }
1731
+ return files.filter(file => file.name.toLowerCase().includes(query));
1732
+ }, ...(ngDevMode ? [{ debugName: "filteredFiles" }] : []));
1733
+ selectedIds = computed(() => new Set(this.zSelectedFiles().map(f => f.id)), ...(ngDevMode ? [{ debugName: "selectedIds" }] : []));
1734
+ isAllSelected = computed(() => {
1735
+ const files = this.filteredFiles();
1736
+ const selectedIds = this.selectedIds();
1737
+ return files.length > 0 && files.every(f => selectedIds.has(f.id));
1738
+ }, ...(ngDevMode ? [{ debugName: "isAllSelected" }] : []));
1739
+ isIndeterminate = computed(() => {
1740
+ const files = this.filteredFiles();
1741
+ const selectedIds = this.selectedIds();
1742
+ const selectedCount = files.filter(f => selectedIds.has(f.id)).length;
1743
+ return selectedCount > 0 && selectedCount < files.length;
1744
+ }, ...(ngDevMode ? [{ debugName: "isIndeterminate" }] : []));
1745
+ selectedCount = computed(() => this.zSelectedFiles().length, ...(ngDevMode ? [{ debugName: "selectedCount" }] : []));
1746
+ ngAfterViewInit() {
1747
+ this._destroyRef.onDestroy(() => this.closePreview());
1748
+ this.zControl.emit({
1749
+ setMode: mode => {
1750
+ this.modeIndex.set(mode === 'list' ? 1 : 0);
1751
+ this.zMode.set(mode);
1752
+ this.zModeChange.emit(mode);
1753
+ },
1754
+ getMode: () => this.currentMode(),
1755
+ getFiles: () => this.zFiles(),
1756
+ openPreview: file => this._openPreview(file),
1757
+ closePreview: () => this.closePreview(),
1758
+ selectAll: () => this.selectAll(),
1759
+ deselectAll: () => this.deselectAll(),
1760
+ toggleSelection: file => this.toggleSelection(file),
1761
+ getSelectedFiles: () => this.zSelectedFiles(),
1762
+ isSelected: file => this.isFileSelected(file),
1763
+ });
1764
+ }
1765
+ onSearchChange(query) {
1766
+ const normalizedQuery = String(query ?? '');
1767
+ this.searchQuery.set(normalizedQuery);
1768
+ this.zSearchChange.emit(normalizedQuery);
1769
+ }
1770
+ onDownload(file) {
1771
+ this.zOnDownload.emit(file);
1772
+ const downloadLink = file.downloadUrl || file.url;
1773
+ if (downloadLink) {
1774
+ const link = document.createElement('a');
1775
+ link.href = downloadLink;
1776
+ link.download = file.name;
1777
+ link.target = '_blank';
1778
+ document.body.appendChild(link);
1779
+ link.click();
1780
+ document.body.removeChild(link);
1781
+ }
1782
+ }
1783
+ onPreview(file) {
1784
+ this._openPreview(file, true);
1785
+ }
1786
+ onRemove(file) {
1787
+ this.zOnRemove.emit(file);
1788
+ }
1789
+ closePreview() {
1790
+ this._previewRef?.close();
1791
+ this._previewRef = null;
1792
+ }
1793
+ onRemoveFromPreview(file) {
1794
+ this.zOnRemove.emit(file);
1795
+ const allFiles = this.filteredFiles();
1796
+ const currentIndex = allFiles.findIndex(f => f.id === file.id);
1797
+ if (allFiles.length <= 1) {
1798
+ this.closePreview();
1799
+ return;
1800
+ }
1801
+ const nextFile = currentIndex < allFiles.length - 1 ? allFiles[currentIndex + 1] : allFiles[currentIndex - 1];
1802
+ this._openPreview(nextFile);
1803
+ }
1804
+ _openPreview(file, emitPreview = false) {
1805
+ this.closePreview();
1806
+ if (emitPreview) {
1807
+ this.zOnPreview.emit(file);
1808
+ }
1809
+ const previewRef = this._previewService.open({
1810
+ file,
1811
+ files: this.filteredFiles(),
1812
+ zShowRemove: this.zShowRemove(),
1813
+ zPdfViewerConfig: this.zPdfViewerConfig(),
1814
+ zTrustedResourceOrigins: this.zTrustedResourceOrigins(),
1815
+ zDownload: false,
1816
+ zOnClose: () => {
1817
+ this._previewRef = null;
1818
+ },
1819
+ zOnDownload: previewFile => this.onDownload(previewFile),
1820
+ zOnRemove: previewFile => this.onRemoveFromPreview(previewFile),
1821
+ });
1822
+ this._previewRef = previewRef;
1823
+ }
1824
+ isFileSelected(file) {
1825
+ return this.selectedIds().has(file.id);
1826
+ }
1827
+ toggleSelection(file) {
1828
+ const currentSelected = this.zSelectedFiles();
1829
+ const isSelected = this.isFileSelected(file);
1830
+ const newSelected = isSelected ? currentSelected.filter(f => f.id !== file.id) : [...currentSelected, file];
1831
+ this.zOnAction.emit({ type: isSelected ? 'deselect' : 'select', file });
1832
+ this.zSelectedFiles.set(newSelected);
1833
+ this.zSelectionChange.emit({
1834
+ selectedFiles: newSelected,
1835
+ addedFiles: isSelected ? undefined : [file],
1836
+ removedFiles: isSelected ? [file] : undefined,
1837
+ });
1838
+ }
1839
+ selectAll() {
1840
+ const files = this.filteredFiles();
1841
+ this.zSelectedFiles.set([...files]);
1842
+ this.zOnAction.emit({ type: 'select-all', files });
1843
+ this.zSelectionChange.emit({
1844
+ selectedFiles: files,
1845
+ addedFiles: files,
1846
+ });
1847
+ }
1848
+ deselectAll() {
1849
+ const previousSelected = this.zSelectedFiles();
1850
+ this.zSelectedFiles.set([]);
1851
+ this.zOnAction.emit({ type: 'deselect-all', files: previousSelected });
1852
+ this.zSelectionChange.emit({
1853
+ selectedFiles: [],
1854
+ removedFiles: previousSelected,
1855
+ });
1856
+ }
1857
+ toggleSelectAll() {
1858
+ if (this.isAllSelected()) {
1859
+ this.deselectAll();
1860
+ return;
1861
+ }
1862
+ this.selectAll();
1863
+ }
1864
+ onBulkDelete() {
1865
+ const selectedFiles = this.zSelectedFiles();
1866
+ this.zOnAction.emit({ type: 'delete', files: selectedFiles });
1867
+ }
1868
+ onBulkDownload() {
1869
+ const selectedFiles = this.zSelectedFiles();
1870
+ this.zOnAction.emit({ type: 'download', files: selectedFiles });
1871
+ selectedFiles.forEach(file => this.onDownload(file));
1872
+ }
1873
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1874
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", type: ZGalleryComponent, isStandalone: true, selector: "z-gallery", inputs: { zFiles: { classPropertyName: "zFiles", publicName: "zFiles", isSignal: true, isRequired: false, transformFunction: null }, zMode: { classPropertyName: "zMode", publicName: "zMode", isSignal: true, isRequired: false, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zColumns: { classPropertyName: "zColumns", publicName: "zColumns", isSignal: true, isRequired: false, transformFunction: null }, zItemWidth: { classPropertyName: "zItemWidth", publicName: "zItemWidth", isSignal: true, isRequired: false, transformFunction: null }, zLoading: { classPropertyName: "zLoading", publicName: "zLoading", isSignal: true, isRequired: false, transformFunction: null }, zSkeletonRows: { classPropertyName: "zSkeletonRows", publicName: "zSkeletonRows", isSignal: true, isRequired: false, transformFunction: null }, zSkeletonItems: { classPropertyName: "zSkeletonItems", publicName: "zSkeletonItems", isSignal: true, isRequired: false, transformFunction: null }, zShowDownload: { classPropertyName: "zShowDownload", publicName: "zShowDownload", isSignal: true, isRequired: false, transformFunction: null }, zShowPreview: { classPropertyName: "zShowPreview", publicName: "zShowPreview", isSignal: true, isRequired: false, transformFunction: null }, zShowRemove: { classPropertyName: "zShowRemove", publicName: "zShowRemove", isSignal: true, isRequired: false, transformFunction: null }, zPdfViewerConfig: { classPropertyName: "zPdfViewerConfig", publicName: "zPdfViewerConfig", isSignal: true, isRequired: false, transformFunction: null }, zTrustedResourceOrigins: { classPropertyName: "zTrustedResourceOrigins", publicName: "zTrustedResourceOrigins", isSignal: true, isRequired: false, transformFunction: null }, zShowModeToggle: { classPropertyName: "zShowModeToggle", publicName: "zShowModeToggle", isSignal: true, isRequired: false, transformFunction: null }, zShowSearch: { classPropertyName: "zShowSearch", publicName: "zShowSearch", isSignal: true, isRequired: false, transformFunction: null }, zServerSearch: { classPropertyName: "zServerSearch", publicName: "zServerSearch", isSignal: true, isRequired: false, transformFunction: null }, zSearchDebounce: { classPropertyName: "zSearchDebounce", publicName: "zSearchDebounce", isSignal: true, isRequired: false, transformFunction: null }, zSearchPlaceholder: { classPropertyName: "zSearchPlaceholder", publicName: "zSearchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, zToggleSize: { classPropertyName: "zToggleSize", publicName: "zToggleSize", isSignal: true, isRequired: false, transformFunction: null }, zTitle: { classPropertyName: "zTitle", publicName: "zTitle", isSignal: true, isRequired: false, transformFunction: null }, zEmptyText: { classPropertyName: "zEmptyText", publicName: "zEmptyText", isSignal: true, isRequired: false, transformFunction: null }, zEmptyIcon: { classPropertyName: "zEmptyIcon", publicName: "zEmptyIcon", isSignal: true, isRequired: false, transformFunction: null }, zClass: { classPropertyName: "zClass", publicName: "zClass", isSignal: true, isRequired: false, transformFunction: null }, zSelectable: { classPropertyName: "zSelectable", publicName: "zSelectable", isSignal: true, isRequired: false, transformFunction: null }, zSelectedFiles: { classPropertyName: "zSelectedFiles", publicName: "zSelectedFiles", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zMode: "zModeChange", zSelectedFiles: "zSelectedFilesChange", zOnDownload: "zOnDownload", zOnPreview: "zOnPreview", zOnRemove: "zOnRemove", zModeChange: "zModeChange", zSearchChange: "zSearchChange", zControl: "zControl", zSelectionChange: "zSelectionChange", zOnAction: "zOnAction" }, host: { classAttribute: "z-gallery block" }, exportAs: ["zGallery"], ngImport: i0, template: `
1875
+ <div [class]="containerClasses()">
1876
+ @if (showHeader()) {
1877
+ <div class="mb-4 flex flex-wrap items-center justify-between gap-3">
1878
+ <div class="flex items-center gap-3">
1879
+ @if (zTitle()) {
1880
+ @if (zLoading()) {
1881
+ <z-skeleton zWidth="7rem" zHeight="1.25rem" />
1882
+ } @else {
1883
+ <h3 class="text-sm font-medium">{{ zTitle() }}</h3>
1884
+ }
1885
+ }
1886
+
1887
+ @if (zShowSearch()) {
1888
+ @if (zLoading()) {
1889
+ <z-skeleton zWidth="16rem" [zHeight]="headerControlHeight()" zRadius="0.375rem" />
1890
+ } @else {
1891
+ <z-input
1892
+ zSearch
1893
+ [zSize]="searchInputSize()"
1894
+ [zPlaceholder]="zSearchPlaceholder() || ('i18n_z_ui_gallery_search_placeholder' | translate)"
1895
+ [zDebounce]="zSearchDebounce()"
1896
+ [ngModel]="searchInputQuery()"
1897
+ (ngModelChange)="searchInputQuery.set($event)"
1898
+ (zOnSearch)="onSearchChange($event)"
1899
+ class="w-64"
1900
+ />
1901
+ }
1902
+ }
1903
+ </div>
1904
+
1905
+ @if (zShowModeToggle() && (zFiles().length > 0 || zLoading())) {
1906
+ @if (zLoading()) {
1907
+ <z-skeleton zWidth="5rem" [zHeight]="headerControlHeight()" zRadius="0.375rem" />
1908
+ } @else {
1909
+ <z-button-group [(zActive)]="modeIndex">
1910
+ <button z-button zType="outline" [zSize]="zToggleSize()" z-button-group-item>
1911
+ <i z-icon zType="lucideLayoutGrid" [zSize]="toggleIconSize()"></i>
1912
+ </button>
1913
+ <button z-button zType="outline" [zSize]="zToggleSize()" z-button-group-item>
1914
+ <i z-icon zType="lucideList" [zSize]="toggleIconSize()"></i>
1915
+ </button>
1916
+ </z-button-group>
1917
+ }
1918
+ }
1919
+ </div>
1920
+ }
1921
+
1922
+ @if (zLoading()) {
1923
+ @if (currentMode() === 'grid') {
1924
+ <div class="grid gap-4" [class]="gridColumnsClass()" [style.gridTemplateColumns]="gridTemplateColumns()">
1925
+ @for (item of skeletonItems(); track item) {
1926
+ <div class="border-border bg-card overflow-hidden rounded-md border shadow-sm">
1927
+ <z-skeleton [zHeight]="skeletonMediaHeight()" zRadius="0" />
1928
+ <div class="p-3">
1929
+ <z-skeleton zWidth="75%" zHeight="1.25rem" />
1930
+ </div>
1931
+ </div>
1932
+ }
1933
+ </div>
1934
+ } @else {
1935
+ <div class="flex flex-col gap-2">
1936
+ @for (item of skeletonItems(); track item) {
1937
+ <div class="border-border bg-card flex items-center gap-3 rounded-sm border px-3 py-2.5 shadow-sm">
1938
+ <z-skeleton class="shrink-0" zWidth="2.75rem" zHeight="2.75rem" zRadius="0.125rem" />
1939
+ <div class="min-w-0 flex-1 space-y-2">
1940
+ <z-skeleton zWidth="40%" zHeight="0.875rem" />
1941
+ <z-skeleton zWidth="25%" zHeight="0.75rem" />
1942
+ </div>
1943
+ <z-skeleton class="shrink-0" zWidth="3.5rem" zHeight="1.5rem" zRadius="0.125rem" />
1944
+ </div>
1945
+ }
1946
+ </div>
1947
+ }
1948
+ } @else if (zSelectable() && filteredFiles().length > 0) {
1949
+ <div
1950
+ class="bg-muted/30 shadow-card dark:!border-border mb-4 flex h-11 items-center justify-between gap-3 rounded-[0.375rem] border border-transparent px-3"
1951
+ >
1952
+ <div class="flex items-center gap-3">
1953
+ <z-checkbox
1954
+ [zChecked]="isAllSelected()"
1955
+ [zIndeterminate]="isIndeterminate()"
1956
+ (zChange)="toggleSelectAll()"
1957
+ zSize="sm"
1958
+ />
1959
+ <span class="text-muted-foreground text-sm">
1960
+ @if (selectedCount() > 0) {
1961
+ {{ selectedCount() }} {{ 'i18n_z_ui_gallery_selected' | translate }}
1962
+ } @else {
1963
+ {{ 'i18n_z_ui_gallery_select_all' | translate }}
1964
+ }
1965
+ </span>
1966
+ </div>
1967
+
1968
+ @if (selectedCount() > 0) {
1969
+ <div class="flex items-center gap-1">
1970
+ @if (zShowDownload()) {
1971
+ <button
1972
+ z-button
1973
+ zType="ghost"
1974
+ zSize="xs"
1975
+ (click)="onBulkDownload()"
1976
+ class="text-muted-foreground hover:text-foreground"
1977
+ >
1978
+ <i z-icon zType="lucideDownload" zSize="14"></i>
1979
+ <span class="ml-1">{{ 'i18n_z_ui_gallery_download' | translate }}</span>
1980
+ </button>
1981
+ }
1982
+ @if (zShowRemove()) {
1983
+ <button
1984
+ z-button
1985
+ zType="ghost"
1986
+ zSize="xs"
1987
+ (click)="onBulkDelete()"
1988
+ class="text-destructive hover:text-destructive"
1989
+ >
1990
+ <i z-icon zType="lucideTrash2" zSize="14"></i>
1991
+ <span class="ml-1">{{ 'i18n_z_ui_gallery_delete' | translate }}</span>
1992
+ </button>
1993
+ }
1994
+ <button z-button zType="ghost" zSize="xs" (click)="deselectAll()">
1995
+ <i z-icon zType="lucideX" zSize="14"></i>
1996
+ </button>
1997
+ </div>
1998
+ }
1999
+ </div>
2000
+ }
2001
+
2002
+ @if (!zLoading() && filteredFiles().length > 0) {
2003
+ @if (currentMode() === 'grid') {
2004
+ <div class="grid gap-4" [class]="gridColumnsClass()" [style.gridTemplateColumns]="gridTemplateColumns()">
2005
+ @for (file of filteredFiles(); track file.id) {
2006
+ <z-gallery-item
2007
+ [file]="file"
2008
+ zMode="grid"
2009
+ [zSize]="zSize()"
2010
+ [zShowDownload]="zShowDownload()"
2011
+ [zShowPreview]="zShowPreview()"
2012
+ [zShowRemove]="zShowRemove()"
2013
+ [zSelectable]="zSelectable()"
2014
+ [zSelected]="isFileSelected(file)"
2015
+ (zOnDownload)="onDownload($event)"
2016
+ (zOnPreview)="onPreview($event)"
2017
+ (zOnRemove)="onRemove($event)"
2018
+ (zOnSelect)="toggleSelection($event)"
2019
+ />
2020
+ }
2021
+ </div>
2022
+ } @else {
2023
+ <div class="flex flex-col gap-2">
2024
+ @for (file of filteredFiles(); track file.id) {
2025
+ <z-gallery-item
2026
+ [file]="file"
2027
+ zMode="list"
2028
+ [zSize]="zSize()"
2029
+ [zShowDownload]="zShowDownload()"
2030
+ [zShowPreview]="zShowPreview()"
2031
+ [zShowRemove]="zShowRemove()"
2032
+ [zSelectable]="zSelectable()"
2033
+ [zSelected]="isFileSelected(file)"
2034
+ (zOnDownload)="onDownload($event)"
2035
+ (zOnPreview)="onPreview($event)"
2036
+ (zOnRemove)="onRemove($event)"
2037
+ (zOnSelect)="toggleSelection($event)"
2038
+ />
2039
+ }
2040
+ </div>
2041
+ }
2042
+ } @else if (!zLoading() && zFiles().length > 0 && searchQuery()) {
2043
+ <z-empty zIcon="lucideSearchX" [zMessage]="'i18n_z_ui_gallery_no_search_results' | translate" zSize="sm" />
2044
+ } @else if (!zLoading()) {
2045
+ <z-empty
2046
+ [zIcon]="zEmptyIcon()"
2047
+ [zMessage]="zEmptyText() || ('i18n_z_ui_gallery_no_files' | translate)"
2048
+ zSize="sm"
2049
+ />
2050
+ }
2051
+ </div>
2052
+ `, isInline: true, dependencies: [{ 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: ZGalleryItemComponent, selector: "z-gallery-item", inputs: ["file", "zMode", "zSize", "zShowDownload", "zShowPreview", "zShowRemove", "zSelectable", "zSelected"], outputs: ["zOnDownload", "zOnPreview", "zOnRemove", "zOnSelect"] }, { kind: "component", type: ZButtonGroupComponent, selector: "z-button-group", inputs: ["zClass", "zOrientation", "zActive"], outputs: ["zActiveChange", "zActiveIndexChange", "zActiveValueChange"], exportAs: ["zButtonGroup"] }, { kind: "directive", type: ZButtonGroupItemDirective, selector: "[z-button-group-item]", inputs: ["zValue"], exportAs: ["zButtonGroupItem"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "component", type: ZCheckboxComponent, selector: "z-checkbox", inputs: ["class", "zType", "zSize", "zLabel", "zText", "zDisabled", "zIndeterminate", "zValue", "zOptions", "zOrientation", "zCheckAll", "zCheckAllText", "zChecked", "zGroupValue"], outputs: ["zChange", "zGroupChange", "zOnBlur", "zOnFocus", "zControl", "zEvent", "zCheckedChange", "zGroupValueChange"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "component", type: ZInputComponent, selector: "z-input", inputs: ["class", "zType", "zSize", "zAlign", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zLoadingOutline", "zPrefix", "zSuffix", "zMin", "zMax", "zStep", "zShowArrows", "zMask", "zDecimalPlaces", "zAllowNegative", "zThousandSeparator", "zDecimalMarker", "zValidators", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zShowPasswordToggle", "zSearch", "zDebounce", "zAutofocus", "zAutoComplete", "zAllowClear", "zAutoSizeContent", "zRows", "zResize", "zMaxLength", "zAutoSuggest", "zColorConfig"], outputs: ["zOnSearch", "zOnChange", "zOnBlur", "zOnFocus", "zOnKeydown", "zOnEnter", "zOnColorCollapse", "zControl", "zEvent"], exportAs: ["zInput"] }, { kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2053
+ }
2054
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryComponent, decorators: [{
2055
+ type: Component,
2056
+ args: [{
2057
+ selector: 'z-gallery',
2058
+ imports: [
2059
+ FormsModule,
2060
+ TranslatePipe,
2061
+ ZGalleryItemComponent,
2062
+ ZButtonGroupComponent,
2063
+ ZButtonGroupItemDirective,
2064
+ ZButtonComponent,
2065
+ ZCheckboxComponent,
2066
+ ZIconComponent,
2067
+ ZEmptyComponent,
2068
+ ZInputComponent,
2069
+ ZSkeletonComponent,
2070
+ ],
2071
+ standalone: true,
2072
+ template: `
2073
+ <div [class]="containerClasses()">
2074
+ @if (showHeader()) {
2075
+ <div class="mb-4 flex flex-wrap items-center justify-between gap-3">
2076
+ <div class="flex items-center gap-3">
2077
+ @if (zTitle()) {
2078
+ @if (zLoading()) {
2079
+ <z-skeleton zWidth="7rem" zHeight="1.25rem" />
2080
+ } @else {
2081
+ <h3 class="text-sm font-medium">{{ zTitle() }}</h3>
2082
+ }
2083
+ }
2084
+
2085
+ @if (zShowSearch()) {
2086
+ @if (zLoading()) {
2087
+ <z-skeleton zWidth="16rem" [zHeight]="headerControlHeight()" zRadius="0.375rem" />
2088
+ } @else {
2089
+ <z-input
2090
+ zSearch
2091
+ [zSize]="searchInputSize()"
2092
+ [zPlaceholder]="zSearchPlaceholder() || ('i18n_z_ui_gallery_search_placeholder' | translate)"
2093
+ [zDebounce]="zSearchDebounce()"
2094
+ [ngModel]="searchInputQuery()"
2095
+ (ngModelChange)="searchInputQuery.set($event)"
2096
+ (zOnSearch)="onSearchChange($event)"
2097
+ class="w-64"
2098
+ />
2099
+ }
2100
+ }
2101
+ </div>
2102
+
2103
+ @if (zShowModeToggle() && (zFiles().length > 0 || zLoading())) {
2104
+ @if (zLoading()) {
2105
+ <z-skeleton zWidth="5rem" [zHeight]="headerControlHeight()" zRadius="0.375rem" />
2106
+ } @else {
2107
+ <z-button-group [(zActive)]="modeIndex">
2108
+ <button z-button zType="outline" [zSize]="zToggleSize()" z-button-group-item>
2109
+ <i z-icon zType="lucideLayoutGrid" [zSize]="toggleIconSize()"></i>
2110
+ </button>
2111
+ <button z-button zType="outline" [zSize]="zToggleSize()" z-button-group-item>
2112
+ <i z-icon zType="lucideList" [zSize]="toggleIconSize()"></i>
2113
+ </button>
2114
+ </z-button-group>
2115
+ }
2116
+ }
2117
+ </div>
2118
+ }
2119
+
2120
+ @if (zLoading()) {
2121
+ @if (currentMode() === 'grid') {
2122
+ <div class="grid gap-4" [class]="gridColumnsClass()" [style.gridTemplateColumns]="gridTemplateColumns()">
2123
+ @for (item of skeletonItems(); track item) {
2124
+ <div class="border-border bg-card overflow-hidden rounded-md border shadow-sm">
2125
+ <z-skeleton [zHeight]="skeletonMediaHeight()" zRadius="0" />
2126
+ <div class="p-3">
2127
+ <z-skeleton zWidth="75%" zHeight="1.25rem" />
2128
+ </div>
2129
+ </div>
2130
+ }
2131
+ </div>
2132
+ } @else {
2133
+ <div class="flex flex-col gap-2">
2134
+ @for (item of skeletonItems(); track item) {
2135
+ <div class="border-border bg-card flex items-center gap-3 rounded-sm border px-3 py-2.5 shadow-sm">
2136
+ <z-skeleton class="shrink-0" zWidth="2.75rem" zHeight="2.75rem" zRadius="0.125rem" />
2137
+ <div class="min-w-0 flex-1 space-y-2">
2138
+ <z-skeleton zWidth="40%" zHeight="0.875rem" />
2139
+ <z-skeleton zWidth="25%" zHeight="0.75rem" />
2140
+ </div>
2141
+ <z-skeleton class="shrink-0" zWidth="3.5rem" zHeight="1.5rem" zRadius="0.125rem" />
2142
+ </div>
2143
+ }
2144
+ </div>
2145
+ }
2146
+ } @else if (zSelectable() && filteredFiles().length > 0) {
2147
+ <div
2148
+ class="bg-muted/30 shadow-card dark:!border-border mb-4 flex h-11 items-center justify-between gap-3 rounded-[0.375rem] border border-transparent px-3"
2149
+ >
2150
+ <div class="flex items-center gap-3">
2151
+ <z-checkbox
2152
+ [zChecked]="isAllSelected()"
2153
+ [zIndeterminate]="isIndeterminate()"
2154
+ (zChange)="toggleSelectAll()"
2155
+ zSize="sm"
2156
+ />
2157
+ <span class="text-muted-foreground text-sm">
2158
+ @if (selectedCount() > 0) {
2159
+ {{ selectedCount() }} {{ 'i18n_z_ui_gallery_selected' | translate }}
2160
+ } @else {
2161
+ {{ 'i18n_z_ui_gallery_select_all' | translate }}
2162
+ }
2163
+ </span>
2164
+ </div>
2165
+
2166
+ @if (selectedCount() > 0) {
2167
+ <div class="flex items-center gap-1">
2168
+ @if (zShowDownload()) {
2169
+ <button
2170
+ z-button
2171
+ zType="ghost"
2172
+ zSize="xs"
2173
+ (click)="onBulkDownload()"
2174
+ class="text-muted-foreground hover:text-foreground"
2175
+ >
2176
+ <i z-icon zType="lucideDownload" zSize="14"></i>
2177
+ <span class="ml-1">{{ 'i18n_z_ui_gallery_download' | translate }}</span>
2178
+ </button>
2179
+ }
2180
+ @if (zShowRemove()) {
2181
+ <button
2182
+ z-button
2183
+ zType="ghost"
2184
+ zSize="xs"
2185
+ (click)="onBulkDelete()"
2186
+ class="text-destructive hover:text-destructive"
2187
+ >
2188
+ <i z-icon zType="lucideTrash2" zSize="14"></i>
2189
+ <span class="ml-1">{{ 'i18n_z_ui_gallery_delete' | translate }}</span>
2190
+ </button>
2191
+ }
2192
+ <button z-button zType="ghost" zSize="xs" (click)="deselectAll()">
2193
+ <i z-icon zType="lucideX" zSize="14"></i>
2194
+ </button>
2195
+ </div>
2196
+ }
2197
+ </div>
2198
+ }
2199
+
2200
+ @if (!zLoading() && filteredFiles().length > 0) {
2201
+ @if (currentMode() === 'grid') {
2202
+ <div class="grid gap-4" [class]="gridColumnsClass()" [style.gridTemplateColumns]="gridTemplateColumns()">
2203
+ @for (file of filteredFiles(); track file.id) {
2204
+ <z-gallery-item
2205
+ [file]="file"
2206
+ zMode="grid"
2207
+ [zSize]="zSize()"
2208
+ [zShowDownload]="zShowDownload()"
2209
+ [zShowPreview]="zShowPreview()"
2210
+ [zShowRemove]="zShowRemove()"
2211
+ [zSelectable]="zSelectable()"
2212
+ [zSelected]="isFileSelected(file)"
2213
+ (zOnDownload)="onDownload($event)"
2214
+ (zOnPreview)="onPreview($event)"
2215
+ (zOnRemove)="onRemove($event)"
2216
+ (zOnSelect)="toggleSelection($event)"
2217
+ />
2218
+ }
2219
+ </div>
2220
+ } @else {
2221
+ <div class="flex flex-col gap-2">
2222
+ @for (file of filteredFiles(); track file.id) {
2223
+ <z-gallery-item
2224
+ [file]="file"
2225
+ zMode="list"
2226
+ [zSize]="zSize()"
2227
+ [zShowDownload]="zShowDownload()"
2228
+ [zShowPreview]="zShowPreview()"
2229
+ [zShowRemove]="zShowRemove()"
2230
+ [zSelectable]="zSelectable()"
2231
+ [zSelected]="isFileSelected(file)"
2232
+ (zOnDownload)="onDownload($event)"
2233
+ (zOnPreview)="onPreview($event)"
2234
+ (zOnRemove)="onRemove($event)"
2235
+ (zOnSelect)="toggleSelection($event)"
2236
+ />
2237
+ }
2238
+ </div>
2239
+ }
2240
+ } @else if (!zLoading() && zFiles().length > 0 && searchQuery()) {
2241
+ <z-empty zIcon="lucideSearchX" [zMessage]="'i18n_z_ui_gallery_no_search_results' | translate" zSize="sm" />
2242
+ } @else if (!zLoading()) {
2243
+ <z-empty
2244
+ [zIcon]="zEmptyIcon()"
2245
+ [zMessage]="zEmptyText() || ('i18n_z_ui_gallery_no_files' | translate)"
2246
+ zSize="sm"
2247
+ />
2248
+ }
2249
+ </div>
2250
+ `,
2251
+ changeDetection: ChangeDetectionStrategy.OnPush,
2252
+ encapsulation: ViewEncapsulation.None,
2253
+ host: {
2254
+ class: 'z-gallery block',
2255
+ },
2256
+ exportAs: 'zGallery',
2257
+ }]
2258
+ }], propDecorators: { zFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "zFiles", required: false }] }], zMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMode", required: false }] }, { type: i0.Output, args: ["zModeChange"] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "zColumns", required: false }] }], zItemWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "zItemWidth", required: false }] }], zLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLoading", required: false }] }], zSkeletonRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSkeletonRows", required: false }] }], zSkeletonItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSkeletonItems", required: false }] }], zShowDownload: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowDownload", required: false }] }], zShowPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowPreview", required: false }] }], zShowRemove: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowRemove", required: false }] }], zPdfViewerConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPdfViewerConfig", required: false }] }], zTrustedResourceOrigins: [{ type: i0.Input, args: [{ isSignal: true, alias: "zTrustedResourceOrigins", required: false }] }], zShowModeToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowModeToggle", required: false }] }], zShowSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowSearch", required: false }] }], zServerSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "zServerSearch", required: false }] }], zSearchDebounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSearchDebounce", required: false }] }], zSearchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSearchPlaceholder", required: false }] }], zToggleSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zToggleSize", required: false }] }], zTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "zTitle", required: false }] }], zEmptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "zEmptyText", required: false }] }], zEmptyIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "zEmptyIcon", required: false }] }], zClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "zClass", required: false }] }], zSelectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSelectable", required: false }] }], zSelectedFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSelectedFiles", required: false }] }, { type: i0.Output, args: ["zSelectedFilesChange"] }], zOnDownload: [{ type: i0.Output, args: ["zOnDownload"] }], zOnPreview: [{ type: i0.Output, args: ["zOnPreview"] }], zOnRemove: [{ type: i0.Output, args: ["zOnRemove"] }], zModeChange: [{ type: i0.Output, args: ["zModeChange"] }], zSearchChange: [{ type: i0.Output, args: ["zSearchChange"] }], zControl: [{ type: i0.Output, args: ["zControl"] }], zSelectionChange: [{ type: i0.Output, args: ["zSelectionChange"] }], zOnAction: [{ type: i0.Output, args: ["zOnAction"] }] } });
2259
+
2260
+ class ZGalleryFileIconComponent {
2261
+ file = input.required(...(ngDevMode ? [{ debugName: "file" }] : []));
2262
+ zSize = input('default', ...(ngDevMode ? [{ debugName: "zSize" }] : []));
2263
+ zMode = input('grid', ...(ngDevMode ? [{ debugName: "zMode" }] : []));
2264
+ imageError = signal(false, ...(ngDevMode ? [{ debugName: "imageError" }] : []));
2265
+ isLoading = signal(true, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
2266
+ category = computed(() => getFileCategory(this.file()), ...(ngDevMode ? [{ debugName: "category" }] : []));
2267
+ style = computed(() => FILE_CATEGORY_STYLES[this.category()], ...(ngDevMode ? [{ debugName: "style" }] : []));
2268
+ showThumbnail = computed(() => {
2269
+ const file = this.file();
2270
+ const cat = this.category();
2271
+ return cat === 'image' && (file.thumbnailUrl || file.url) && !this.imageError();
2272
+ }, ...(ngDevMode ? [{ debugName: "showThumbnail" }] : []));
2273
+ containerClasses = computed(() => {
2274
+ const style = this.style();
2275
+ const showThumb = this.showThumbnail();
2276
+ return zMergeClasses(zGalleryFileIconVariants({
2277
+ zSize: this.zSize(),
2278
+ zMode: this.zMode(),
2279
+ }), showThumb ? 'bg-muted relative' : [style.bg, style.text]);
2280
+ }, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
2281
+ onImageLoad() {
2282
+ this.isLoading.set(false);
2283
+ }
2284
+ onImageError(event) {
2285
+ this.imageError.set(true);
2286
+ this.isLoading.set(false);
2287
+ const img = event.target;
2288
+ img.style.display = 'none';
2289
+ }
2290
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryFileIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2291
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", type: ZGalleryFileIconComponent, isStandalone: true, selector: "z-gallery-file-icon", inputs: { file: { classPropertyName: "file", publicName: "file", isSignal: true, isRequired: true, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zMode: { classPropertyName: "zMode", publicName: "zMode", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "z-gallery-file-icon block" }, ngImport: i0, template: `
2292
+ <div [class]="containerClasses()" class="group/icon overflow-hidden">
2293
+ @if (showThumbnail()) {
2294
+ @if (isLoading()) {
2295
+ <z-skeleton class="absolute inset-0 size-full" />
2296
+ }
2297
+ <img
2298
+ [src]="file().thumbnailUrl || file().url"
2299
+ [alt]="file().name"
2300
+ class="size-full object-cover transition-transform duration-300 group-hover/icon:scale-105"
2301
+ loading="lazy"
2302
+ [class.opacity-0]="isLoading()"
2303
+ [class.opacity-100]="!isLoading()"
2304
+ (load)="onImageLoad()"
2305
+ (error)="onImageError($event)"
2306
+ />
2307
+ } @else {
2308
+ <div class="flex flex-col items-center justify-center gap-1">
2309
+ <span class="font-bold tracking-wide">{{ style().label }}</span>
2310
+ </div>
2311
+ }
2312
+ </div>
2313
+ `, isInline: true, dependencies: [{ kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2314
+ }
2315
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryFileIconComponent, decorators: [{
2316
+ type: Component,
2317
+ args: [{
2318
+ selector: 'z-gallery-file-icon',
2319
+ imports: [ZSkeletonComponent],
2320
+ standalone: true,
2321
+ template: `
2322
+ <div [class]="containerClasses()" class="group/icon overflow-hidden">
2323
+ @if (showThumbnail()) {
2324
+ @if (isLoading()) {
2325
+ <z-skeleton class="absolute inset-0 size-full" />
2326
+ }
2327
+ <img
2328
+ [src]="file().thumbnailUrl || file().url"
2329
+ [alt]="file().name"
2330
+ class="size-full object-cover transition-transform duration-300 group-hover/icon:scale-105"
2331
+ loading="lazy"
2332
+ [class.opacity-0]="isLoading()"
2333
+ [class.opacity-100]="!isLoading()"
2334
+ (load)="onImageLoad()"
2335
+ (error)="onImageError($event)"
2336
+ />
2337
+ } @else {
2338
+ <div class="flex flex-col items-center justify-center gap-1">
2339
+ <span class="font-bold tracking-wide">{{ style().label }}</span>
2340
+ </div>
2341
+ }
2342
+ </div>
2343
+ `,
2344
+ changeDetection: ChangeDetectionStrategy.OnPush,
2345
+ encapsulation: ViewEncapsulation.None,
2346
+ host: {
2347
+ class: 'z-gallery-file-icon block',
2348
+ },
2349
+ }]
2350
+ }], propDecorators: { file: [{ type: i0.Input, args: [{ isSignal: true, alias: "file", required: true }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMode", required: false }] }] } });
2351
+
2352
+ class ZGalleryPreviewItemDirective {
2353
+ zGalleryPreviewItem = input.required(...(ngDevMode ? [{ debugName: "zGalleryPreviewItem" }] : []));
2354
+ zGalleryPreviewFiles = input(null, ...(ngDevMode ? [{ debugName: "zGalleryPreviewFiles" }] : []));
2355
+ zGalleryPreviewOptions = input({}, ...(ngDevMode ? [{ debugName: "zGalleryPreviewOptions" }] : []));
2356
+ zDisabled = input(false, { ...(ngDevMode ? { debugName: "zDisabled" } : {}), transform: zTransform });
2357
+ zOnPreview = output();
2358
+ _elementRef = inject((ElementRef));
2359
+ _previewService = inject(ZGalleryPreviewService);
2360
+ hostRole = computed(() => (this._isNativeInteractive() ? null : 'button'), ...(ngDevMode ? [{ debugName: "hostRole" }] : []));
2361
+ hostTabIndex = computed(() => {
2362
+ if (this._isNativeInteractive()) {
2363
+ return null;
2364
+ }
2365
+ return this.zDisabled() ? -1 : 0;
2366
+ }, ...(ngDevMode ? [{ debugName: "hostTabIndex" }] : []));
2367
+ hostAriaDisabled = computed(() => (this.zDisabled() ? true : null), ...(ngDevMode ? [{ debugName: "hostAriaDisabled" }] : []));
2368
+ openPreview(event) {
2369
+ if (this.zDisabled()) {
2370
+ return;
2371
+ }
2372
+ if (event instanceof KeyboardEvent && this._isNativeInteractive()) {
2373
+ return;
2374
+ }
2375
+ const file = this.zGalleryPreviewItem();
2376
+ if (!isPreviewable(file)) {
2377
+ return;
2378
+ }
2379
+ if (event instanceof KeyboardEvent) {
2380
+ event.preventDefault();
2381
+ }
2382
+ this.zOnPreview.emit(file);
2383
+ this._previewService.open({
2384
+ ...this.zGalleryPreviewOptions(),
2385
+ file,
2386
+ files: this.zGalleryPreviewFiles() ?? undefined,
2387
+ });
2388
+ }
2389
+ _isNativeInteractive() {
2390
+ const tagName = this._elementRef.nativeElement.tagName.toLowerCase();
2391
+ return tagName === 'button' || tagName === 'a';
2392
+ }
2393
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2394
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.9", type: ZGalleryPreviewItemDirective, isStandalone: true, selector: "[zGalleryPreviewItem], [z-gallery-preview-item]", inputs: { zGalleryPreviewItem: { classPropertyName: "zGalleryPreviewItem", publicName: "zGalleryPreviewItem", isSignal: true, isRequired: true, transformFunction: null }, zGalleryPreviewFiles: { classPropertyName: "zGalleryPreviewFiles", publicName: "zGalleryPreviewFiles", isSignal: true, isRequired: false, transformFunction: null }, zGalleryPreviewOptions: { classPropertyName: "zGalleryPreviewOptions", publicName: "zGalleryPreviewOptions", isSignal: true, isRequired: false, transformFunction: null }, zDisabled: { classPropertyName: "zDisabled", publicName: "zDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zOnPreview: "zOnPreview" }, host: { listeners: { "click": "openPreview()", "keydown.enter": "openPreview($event)", "keydown.space": "openPreview($event)" }, properties: { "attr.role": "hostRole()", "attr.tabindex": "hostTabIndex()", "attr.aria-disabled": "hostAriaDisabled()" }, classAttribute: "z-gallery-preview-item" }, exportAs: ["zGalleryPreviewItem"], ngImport: i0 });
2395
+ }
2396
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewItemDirective, decorators: [{
2397
+ type: Directive,
2398
+ args: [{
2399
+ selector: '[zGalleryPreviewItem], [z-gallery-preview-item]',
2400
+ standalone: true,
2401
+ host: {
2402
+ class: 'z-gallery-preview-item',
2403
+ '[attr.role]': 'hostRole()',
2404
+ '[attr.tabindex]': 'hostTabIndex()',
2405
+ '[attr.aria-disabled]': 'hostAriaDisabled()',
2406
+ '(click)': 'openPreview()',
2407
+ '(keydown.enter)': 'openPreview($event)',
2408
+ '(keydown.space)': 'openPreview($event)',
2409
+ },
2410
+ exportAs: 'zGalleryPreviewItem',
2411
+ }]
2412
+ }], propDecorators: { zGalleryPreviewItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "zGalleryPreviewItem", required: true }] }], zGalleryPreviewFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "zGalleryPreviewFiles", required: false }] }], zGalleryPreviewOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "zGalleryPreviewOptions", required: false }] }], zDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDisabled", required: false }] }], zOnPreview: [{ type: i0.Output, args: ["zOnPreview"] }] } });
2413
+
2414
+ /**
2415
+ * Generated bundle index. Do not edit.
2416
+ */
2417
+
2418
+ export { FILE_CATEGORY_STYLES, ZGalleryComponent, ZGalleryFileIconComponent, ZGalleryItemComponent, ZGalleryPreviewComponent, ZGalleryPreviewItemDirective, ZGalleryPreviewRef, ZGalleryPreviewService, formatFileSize, getFileCategory, isImage, isPreviewable, zGalleryFileIconVariants, zGalleryItemVariants, zGalleryVariants };
2419
+ //# sourceMappingURL=shival99-z-ui-components-z-gallery.mjs.map