@eternalheart/angular-file-preview 1.6.5

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 (119) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +879 -0
  3. package/README.zh-CN.md +876 -0
  4. package/lib/LICENSE +22 -0
  5. package/lib/README.md +879 -0
  6. package/lib/components/preview/file-preview-toolbar.d.ts +19 -0
  7. package/lib/components/preview/nav-arrows.d.ts +25 -0
  8. package/lib/components/preview/renderer-outlet.d.ts +23 -0
  9. package/lib/components/preview/toolbar-button.d.ts +12 -0
  10. package/lib/components/resizable-split.d.ts +32 -0
  11. package/lib/di/locale.service.d.ts +12 -0
  12. package/lib/di/request.service.d.ts +20 -0
  13. package/lib/di/theme-mode.d.ts +6 -0
  14. package/lib/di/theme.service.d.ts +9 -0
  15. package/lib/fesm2022/eternalheart-angular-file-preview-avifLoader-BP3fgcMm-CZsJ9svm.mjs +55 -0
  16. package/lib/fesm2022/eternalheart-angular-file-preview-avifLoader-BP3fgcMm-CZsJ9svm.mjs.map +1 -0
  17. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-RendererError-DtNihCIX-DtNihCIX.mjs +58 -0
  18. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-RendererError-DtNihCIX-DtNihCIX.mjs.map +1 -0
  19. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-UobTf36G.mjs +5835 -0
  20. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-UobTf36G.mjs.map +1 -0
  21. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-base.types-D5x7QPey-D5x7QPey.mjs +17 -0
  22. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-base.types-D5x7QPey-D5x7QPey.mjs.map +1 -0
  23. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index--7d8Hgi0-D-sg24Qs.mjs +284 -0
  24. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index--7d8Hgi0-D-sg24Qs.mjs.map +1 -0
  25. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-6dZS_Cfs-B1itLV5R.mjs +703 -0
  26. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-6dZS_Cfs-B1itLV5R.mjs.map +1 -0
  27. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-B1ANUCTy-BRs7TMLn.mjs +231 -0
  28. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-B1ANUCTy-BRs7TMLn.mjs.map +1 -0
  29. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-BEaqpRV8-BidVIVlO.mjs +552 -0
  30. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-BEaqpRV8-BidVIVlO.mjs.map +1 -0
  31. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-BGqTRZbm-CAOLRw20.mjs +688 -0
  32. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-BGqTRZbm-CAOLRw20.mjs.map +1 -0
  33. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-Bv3JRXKn-B4Wewc-4.mjs +273 -0
  34. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-Bv3JRXKn-B4Wewc-4.mjs.map +1 -0
  35. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-C0McUoqT-DJ35bhIz.mjs +288 -0
  36. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-C0McUoqT-DJ35bhIz.mjs.map +1 -0
  37. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-C518mdUd-B5SCzrzU.mjs +550 -0
  38. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-C518mdUd-B5SCzrzU.mjs.map +1 -0
  39. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-CDjKPqyW-CmX5sdkL.mjs +102 -0
  40. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-CDjKPqyW-CmX5sdkL.mjs.map +1 -0
  41. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-CHi9tOe0-NOeQYAnM.mjs +516 -0
  42. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-CHi9tOe0-NOeQYAnM.mjs.map +1 -0
  43. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-CQwhffym-DAGw4Xy_.mjs +823 -0
  44. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-CQwhffym-DAGw4Xy_.mjs.map +1 -0
  45. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-CSCTj7ft-BfqruUyY.mjs +164 -0
  46. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-CSCTj7ft-BfqruUyY.mjs.map +1 -0
  47. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-Cb1RLXeO-Bj9gjS1Z.mjs +655 -0
  48. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-Cb1RLXeO-Bj9gjS1Z.mjs.map +1 -0
  49. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-Cw90Kdyg-BzrW_cyx.mjs +207 -0
  50. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-Cw90Kdyg-BzrW_cyx.mjs.map +1 -0
  51. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-D35x1nwM-CugEEXjg.mjs +199 -0
  52. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-D35x1nwM-CugEEXjg.mjs.map +1 -0
  53. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-D9jJNzeM-mWX59Aj2.mjs +194 -0
  54. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-D9jJNzeM-mWX59Aj2.mjs.map +1 -0
  55. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-DbmuvdvN-C29uLyt2.mjs +94 -0
  56. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-DbmuvdvN-C29uLyt2.mjs.map +1 -0
  57. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-DsNNZ59Q-C8MaSME6.mjs +468 -0
  58. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-DsNNZ59Q-C8MaSME6.mjs.map +1 -0
  59. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-DufW2Fuc-CTosCut6.mjs +193 -0
  60. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-DufW2Fuc-CTosCut6.mjs.map +1 -0
  61. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-TSTa_Q7E-DBhkL6pV.mjs +184 -0
  62. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-TSTa_Q7E-DBhkL6pV.mjs.map +1 -0
  63. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-pG0Ko5mI-DthQJg-X.mjs +492 -0
  64. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-pG0Ko5mI-DthQJg-X.mjs.map +1 -0
  65. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-shiki-highlight-CL9cG481-BKfwdOpN.mjs +68 -0
  66. package/lib/fesm2022/eternalheart-angular-file-preview-eternalheart-angular-file-preview-shiki-highlight-CL9cG481-BKfwdOpN.mjs.map +1 -0
  67. package/lib/fesm2022/eternalheart-angular-file-preview-heicLoader-CH_raQNn-BSXHd_oi.mjs +36 -0
  68. package/lib/fesm2022/eternalheart-angular-file-preview-heicLoader-CH_raQNn-BSXHd_oi.mjs.map +1 -0
  69. package/lib/fesm2022/eternalheart-angular-file-preview-jp2Loader-ldvCSsvm-DJEhfimG.mjs +121 -0
  70. package/lib/fesm2022/eternalheart-angular-file-preview-jp2Loader-ldvCSsvm-DJEhfimG.mjs.map +1 -0
  71. package/lib/fesm2022/eternalheart-angular-file-preview-psdLoader-D5CkupyY-D5Gegcdg.mjs +78 -0
  72. package/lib/fesm2022/eternalheart-angular-file-preview-psdLoader-D5CkupyY-D5Gegcdg.mjs.map +1 -0
  73. package/lib/fesm2022/eternalheart-angular-file-preview-rawLoader-0mLvxCNp-CCXn9Rdp.mjs +81 -0
  74. package/lib/fesm2022/eternalheart-angular-file-preview-rawLoader-0mLvxCNp-CCXn9Rdp.mjs.map +1 -0
  75. package/lib/fesm2022/eternalheart-angular-file-preview-tiffLoader-CmUAD1vO-0JqIws9t.mjs +59 -0
  76. package/lib/fesm2022/eternalheart-angular-file-preview-tiffLoader-CmUAD1vO-0JqIws9t.mjs.map +1 -0
  77. package/lib/fesm2022/eternalheart-angular-file-preview.mjs +2 -0
  78. package/lib/fesm2022/eternalheart-angular-file-preview.mjs.map +1 -0
  79. package/lib/file-preview-content.d.ts +65 -0
  80. package/lib/file-preview-embed.d.ts +30 -0
  81. package/lib/file-preview-modal.d.ts +34 -0
  82. package/lib/fp-core.d.ts +1 -0
  83. package/lib/index.css +2119 -0
  84. package/lib/index.d.ts +11 -0
  85. package/lib/renderers/Audio/index.d.ts +74 -0
  86. package/lib/renderers/Cad/index.d.ts +45 -0
  87. package/lib/renderers/Cad/toolbar.d.ts +15 -0
  88. package/lib/renderers/Csv/index.d.ts +26 -0
  89. package/lib/renderers/Doc/index.d.ts +19 -0
  90. package/lib/renderers/Docx/index.d.ts +42 -0
  91. package/lib/renderers/Epub/index.d.ts +57 -0
  92. package/lib/renderers/Font/font-preview-line.d.ts +26 -0
  93. package/lib/renderers/Font/index.d.ts +52 -0
  94. package/lib/renderers/Image/index.d.ts +79 -0
  95. package/lib/renderers/Json/index.d.ts +61 -0
  96. package/lib/renderers/Markdown/index.d.ts +35 -0
  97. package/lib/renderers/Mobi/index.d.ts +51 -0
  98. package/lib/renderers/Msg/index.d.ts +47 -0
  99. package/lib/renderers/Pdf/index.d.ts +55 -0
  100. package/lib/renderers/Ppt/index.d.ts +19 -0
  101. package/lib/renderers/Pptx/index.d.ts +29 -0
  102. package/lib/renderers/RendererError.d.ts +9 -0
  103. package/lib/renderers/RendererLoading.d.ts +7 -0
  104. package/lib/renderers/Subtitle/index.d.ts +25 -0
  105. package/lib/renderers/Text/index.d.ts +29 -0
  106. package/lib/renderers/Unsupported/index.d.ts +15 -0
  107. package/lib/renderers/Video/index.d.ts +28 -0
  108. package/lib/renderers/Xlsx/index.d.ts +25 -0
  109. package/lib/renderers/Xml/index.d.ts +26 -0
  110. package/lib/renderers/Zip/index.d.ts +58 -0
  111. package/lib/renderers/Zip/tree-item.d.ts +29 -0
  112. package/lib/renderers/base.types.d.ts +10 -0
  113. package/lib/renderers/lazy.d.ts +23 -0
  114. package/lib/renderers/registry.d.ts +13 -0
  115. package/lib/renderers/toolbar.types.d.ts +19 -0
  116. package/lib/types.d.ts +26 -0
  117. package/lib/utils/audio-player.d.ts +20 -0
  118. package/lib/utils/shiki-highlight.d.ts +7 -0
  119. package/package.json +119 -0
@@ -0,0 +1,688 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, inject, viewChild, signal, computed, effect, untracked, DestroyRef, output, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { L as LocaleService, R as RequestService, g as getFallbackTranslator, d as jM, w as wg, f as ZI, I as Ig, K as Kg, F as FilePreviewContent, a as R0, V as V0 } from './eternalheart-angular-file-preview-eternalheart-angular-file-preview-UobTf36G.mjs';
4
+ import { R as RendererError } from './eternalheart-angular-file-preview-eternalheart-angular-file-preview-RendererError-DtNihCIX-DtNihCIX.mjs';
5
+ import { T as ToolbarEventEmitter } from './eternalheart-angular-file-preview-eternalheart-angular-file-preview-base.types-D5x7QPey-D5x7QPey.mjs';
6
+ import * as i1 from 'lucide-angular';
7
+ import { ChevronRight, Folder, FolderOpen, FileImage, FileText, FileCode, File, LucideAngularModule } from 'lucide-angular';
8
+
9
+ class ResizableSplit {
10
+ constructor() {
11
+ this.initialLeftWidth = input(280);
12
+ this.minLeftWidth = input(160);
13
+ this.maxLeftWidth = input(640);
14
+ this.minRightWidth = input(200);
15
+ this.storageKey = input(undefined);
16
+ this.desktopMedia = input('(min-width: 768px)');
17
+ this.mobileTabMode = input(false);
18
+ this.leftTabLabel = input('文件树');
19
+ this.rightTabLabel = input('预览');
20
+ this.container = viewChild('containerRef');
21
+ this.destroyRef = inject(DestroyRef);
22
+ this.leftWidth = signal(280);
23
+ this.dragging = signal(false);
24
+ this.isDesktop = signal(false);
25
+ this.activeTab = signal('left');
26
+ this.isMobileTab = computed(() => this.mobileTabMode() && !this.isDesktop());
27
+ this.leftStyle = computed(() => this.isDesktop() ? { width: `${this.leftWidth()}px` } : undefined);
28
+ this.leftPaneClass = computed(() => this.isMobileTab()
29
+ ? 'afp-flex-1 afp-min-h-0 afp-min-w-0 afp-w-full afp-overflow-hidden'
30
+ : 'afp-min-h-0 afp-min-w-0 afp-flex-shrink-0 afp-w-full afp-max-h-60 md:afp-h-full md:afp-max-h-none');
31
+ this.rightPaneClass = computed(() => this.isMobileTab()
32
+ ? 'afp-flex-1 afp-min-h-0 afp-min-w-0 afp-w-full afp-overflow-hidden'
33
+ : 'afp-flex-1 afp-min-w-0 afp-min-h-0 afp-overflow-hidden');
34
+ this.storageApplied = false;
35
+ this.onMove = (e) => {
36
+ const el = this.container()?.nativeElement;
37
+ if (!el)
38
+ return;
39
+ const rect = el.getBoundingClientRect();
40
+ const x = e.clientX - rect.left;
41
+ const cap = rect.width - this.minRightWidth() - 6;
42
+ const effectiveMax = Math.min(this.maxLeftWidth(), cap);
43
+ this.leftWidth.set(Math.max(this.minLeftWidth(), Math.min(effectiveMax, x)));
44
+ };
45
+ this.onUp = () => {
46
+ if (!this.dragging())
47
+ return;
48
+ this.dragging.set(false);
49
+ window.removeEventListener('mousemove', this.onMove);
50
+ window.removeEventListener('mouseup', this.onUp);
51
+ document.body.style.cursor = '';
52
+ document.body.style.userSelect = '';
53
+ const key = this.storageKey();
54
+ if (key) {
55
+ try {
56
+ window.localStorage.setItem(key, String(this.leftWidth()));
57
+ }
58
+ catch {
59
+ /* ignore */
60
+ }
61
+ }
62
+ };
63
+ effect(() => {
64
+ const key = this.storageKey();
65
+ const initial = this.initialLeftWidth();
66
+ if (!this.storageApplied) {
67
+ this.storageApplied = true;
68
+ if (key && typeof window !== 'undefined') {
69
+ const saved = Number(window.localStorage.getItem(key));
70
+ if (!isNaN(saved) && saved > 0) {
71
+ this.leftWidth.set(saved);
72
+ return;
73
+ }
74
+ }
75
+ this.leftWidth.set(initial);
76
+ return;
77
+ }
78
+ if (!key)
79
+ this.leftWidth.set(initial);
80
+ });
81
+ effect((onCleanup) => {
82
+ const media = this.desktopMedia();
83
+ if (typeof window === 'undefined')
84
+ return;
85
+ const mq = window.matchMedia(media);
86
+ const handler = () => {
87
+ this.isDesktop.set(mq.matches);
88
+ };
89
+ handler();
90
+ mq.addEventListener('change', handler);
91
+ onCleanup(() => mq.removeEventListener('change', handler));
92
+ });
93
+ this.destroyRef.onDestroy(() => {
94
+ window.removeEventListener('mousemove', this.onMove);
95
+ window.removeEventListener('mouseup', this.onUp);
96
+ if (this.dragging()) {
97
+ document.body.style.cursor = '';
98
+ document.body.style.userSelect = '';
99
+ }
100
+ });
101
+ }
102
+ switchTab(tab) {
103
+ this.activeTab.set(tab);
104
+ }
105
+ onDividerDown(e) {
106
+ e.preventDefault();
107
+ this.dragging.set(true);
108
+ window.addEventListener('mousemove', this.onMove);
109
+ window.addEventListener('mouseup', this.onUp);
110
+ document.body.style.cursor = 'col-resize';
111
+ document.body.style.userSelect = 'none';
112
+ }
113
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ResizableSplit, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
114
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: ResizableSplit, isStandalone: true, selector: "afp-resizable-split", inputs: { initialLeftWidth: { classPropertyName: "initialLeftWidth", publicName: "initialLeftWidth", isSignal: true, isRequired: false, transformFunction: null }, minLeftWidth: { classPropertyName: "minLeftWidth", publicName: "minLeftWidth", isSignal: true, isRequired: false, transformFunction: null }, maxLeftWidth: { classPropertyName: "maxLeftWidth", publicName: "maxLeftWidth", isSignal: true, isRequired: false, transformFunction: null }, minRightWidth: { classPropertyName: "minRightWidth", publicName: "minRightWidth", isSignal: true, isRequired: false, transformFunction: null }, storageKey: { classPropertyName: "storageKey", publicName: "storageKey", isSignal: true, isRequired: false, transformFunction: null }, desktopMedia: { classPropertyName: "desktopMedia", publicName: "desktopMedia", isSignal: true, isRequired: false, transformFunction: null }, mobileTabMode: { classPropertyName: "mobileTabMode", publicName: "mobileTabMode", isSignal: true, isRequired: false, transformFunction: null }, leftTabLabel: { classPropertyName: "leftTabLabel", publicName: "leftTabLabel", isSignal: true, isRequired: false, transformFunction: null }, rightTabLabel: { classPropertyName: "rightTabLabel", publicName: "rightTabLabel", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["containerRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
115
+ <div
116
+ #containerRef
117
+ class="afp-w-full afp-h-full afp-flex afp-flex-col md:afp-flex-row afp-min-h-0 afp-min-w-0"
118
+ >
119
+ @if (isMobileTab()) {
120
+ <div class="afp-flex afp-flex-shrink-0 afp-border-b afp-border-line-weak afp-bg-surface-toolbar">
121
+ <button
122
+ type="button"
123
+ class="afp-flex-1 afp-py-2.5 afp-text-sm afp-transition-colors"
124
+ [class.afp-text-fg-primary]="activeTab() === 'left'"
125
+ [class.afp-border-b-2]="activeTab() === 'left'"
126
+ [class.afp-border-fg-primary]="activeTab() === 'left'"
127
+ [class.-afp-mb-px]="activeTab() === 'left'"
128
+ [class.afp-text-fg-secondary]="activeTab() !== 'left'"
129
+ (click)="switchTab('left')"
130
+ >
131
+ {{ leftTabLabel() }}
132
+ </button>
133
+ <button
134
+ type="button"
135
+ class="afp-flex-1 afp-py-2.5 afp-text-sm afp-transition-colors"
136
+ [class.afp-text-fg-primary]="activeTab() === 'right'"
137
+ [class.afp-border-b-2]="activeTab() === 'right'"
138
+ [class.afp-border-fg-primary]="activeTab() === 'right'"
139
+ [class.-afp-mb-px]="activeTab() === 'right'"
140
+ [class.afp-text-fg-secondary]="activeTab() !== 'right'"
141
+ (click)="switchTab('right')"
142
+ >
143
+ {{ rightTabLabel() }}
144
+ </button>
145
+ </div>
146
+ }
147
+ <div
148
+ [class]="leftPaneClass()"
149
+ [style]="isMobileTab() ? null : leftStyle()"
150
+ [hidden]="isMobileTab() && activeTab() !== 'left'"
151
+ >
152
+ <ng-content select="[splitLeft]" />
153
+ </div>
154
+ @if (!isMobileTab()) {
155
+ <div
156
+ role="separator"
157
+ aria-orientation="vertical"
158
+ class="split-divider afp-hidden md:afp-block afp-relative afp-w-1.5 afp-flex-shrink-0 afp-cursor-col-resize afp-transition-colors"
159
+ [class.dragging]="dragging()"
160
+ (mousedown)="onDividerDown($event)"
161
+ >
162
+ <span class="afp-absolute afp-inset-y-0 hit-area"></span>
163
+ </div>
164
+ }
165
+ <div
166
+ [class]="rightPaneClass()"
167
+ [hidden]="isMobileTab() && activeTab() !== 'right'"
168
+ >
169
+ <ng-content select="[splitRight]" />
170
+ </div>
171
+ </div>
172
+ `, isInline: true, styles: [":host{display:block;width:100%;height:100%}.split-divider{background:var(--fp-line-weak)}.split-divider:hover{background:var(--fp-line)}.split-divider.dragging{background:var(--fp-line-strong)}.hit-area{left:-4px;right:-4px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
173
+ }
174
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ResizableSplit, decorators: [{
175
+ type: Component,
176
+ args: [{ selector: 'afp-resizable-split', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
177
+ <div
178
+ #containerRef
179
+ class="afp-w-full afp-h-full afp-flex afp-flex-col md:afp-flex-row afp-min-h-0 afp-min-w-0"
180
+ >
181
+ @if (isMobileTab()) {
182
+ <div class="afp-flex afp-flex-shrink-0 afp-border-b afp-border-line-weak afp-bg-surface-toolbar">
183
+ <button
184
+ type="button"
185
+ class="afp-flex-1 afp-py-2.5 afp-text-sm afp-transition-colors"
186
+ [class.afp-text-fg-primary]="activeTab() === 'left'"
187
+ [class.afp-border-b-2]="activeTab() === 'left'"
188
+ [class.afp-border-fg-primary]="activeTab() === 'left'"
189
+ [class.-afp-mb-px]="activeTab() === 'left'"
190
+ [class.afp-text-fg-secondary]="activeTab() !== 'left'"
191
+ (click)="switchTab('left')"
192
+ >
193
+ {{ leftTabLabel() }}
194
+ </button>
195
+ <button
196
+ type="button"
197
+ class="afp-flex-1 afp-py-2.5 afp-text-sm afp-transition-colors"
198
+ [class.afp-text-fg-primary]="activeTab() === 'right'"
199
+ [class.afp-border-b-2]="activeTab() === 'right'"
200
+ [class.afp-border-fg-primary]="activeTab() === 'right'"
201
+ [class.-afp-mb-px]="activeTab() === 'right'"
202
+ [class.afp-text-fg-secondary]="activeTab() !== 'right'"
203
+ (click)="switchTab('right')"
204
+ >
205
+ {{ rightTabLabel() }}
206
+ </button>
207
+ </div>
208
+ }
209
+ <div
210
+ [class]="leftPaneClass()"
211
+ [style]="isMobileTab() ? null : leftStyle()"
212
+ [hidden]="isMobileTab() && activeTab() !== 'left'"
213
+ >
214
+ <ng-content select="[splitLeft]" />
215
+ </div>
216
+ @if (!isMobileTab()) {
217
+ <div
218
+ role="separator"
219
+ aria-orientation="vertical"
220
+ class="split-divider afp-hidden md:afp-block afp-relative afp-w-1.5 afp-flex-shrink-0 afp-cursor-col-resize afp-transition-colors"
221
+ [class.dragging]="dragging()"
222
+ (mousedown)="onDividerDown($event)"
223
+ >
224
+ <span class="afp-absolute afp-inset-y-0 hit-area"></span>
225
+ </div>
226
+ }
227
+ <div
228
+ [class]="rightPaneClass()"
229
+ [hidden]="isMobileTab() && activeTab() !== 'right'"
230
+ >
231
+ <ng-content select="[splitRight]" />
232
+ </div>
233
+ </div>
234
+ `, styles: [":host{display:block;width:100%;height:100%}.split-divider{background:var(--fp-line-weak)}.split-divider:hover{background:var(--fp-line)}.split-divider.dragging{background:var(--fp-line-strong)}.hit-area{left:-4px;right:-4px}\n"] }]
235
+ }], ctorParameters: () => [] });
236
+
237
+ class ZipTreeItem {
238
+ constructor() {
239
+ this.node = input.required();
240
+ this.depth = input.required();
241
+ this.selectedPath = input(null);
242
+ this.expanded = input.required();
243
+ this.toggle = output();
244
+ this.select = output();
245
+ this.hover = output();
246
+ this.leave = output();
247
+ this.chevronRight = ChevronRight;
248
+ this.folder = Folder;
249
+ this.folderOpen = FolderOpen;
250
+ this.formatFileSize = R0;
251
+ this.padStyle = computed(() => ({ paddingLeft: `${this.depth() * 14 + 10}px` }));
252
+ this.isOpen = computed(() => this.expanded().has(this.node().path));
253
+ this.isSelected = computed(() => this.selectedPath() === this.node().path);
254
+ this.fileIcon = computed(() => {
255
+ const name = this.node().name;
256
+ const ft = V0({ name, type: '' });
257
+ if (ft === 'image')
258
+ return FileImage;
259
+ if (ft === 'text' || ft === 'markdown' || ft === 'json' || ft === 'csv' || ft === 'xml' || ft === 'subtitle') {
260
+ return (name.endsWith('.md') || name.endsWith('.markdown')) ? FileText : FileCode;
261
+ }
262
+ return File;
263
+ });
264
+ }
265
+ handleEnter(e) {
266
+ const rect = e.currentTarget.getBoundingClientRect();
267
+ this.hover.emit({ text: this.node().name || '/', rect });
268
+ }
269
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ZipTreeItem, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
270
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: ZipTreeItem, isStandalone: true, selector: "afp-zip-tree-item", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, depth: { classPropertyName: "depth", publicName: "depth", isSignal: true, isRequired: true, transformFunction: null }, selectedPath: { classPropertyName: "selectedPath", publicName: "selectedPath", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { toggle: "toggle", select: "select", hover: "hover", leave: "leave" }, ngImport: i0, template: `
271
+ @if (node().isDir) {
272
+ <div>
273
+ <button
274
+ type="button"
275
+ class="tree-row dir-row"
276
+ [style]="padStyle()"
277
+ (click)="toggle.emit(node().path)"
278
+ (mouseenter)="handleEnter($event)"
279
+ (mouseleave)="leave.emit()"
280
+ >
281
+ <i-lucide
282
+ [img]="chevronRight"
283
+ class="afp-w-3.5 afp-h-3.5 afp-flex-shrink-0 afp-transition-transform"
284
+ [class.afp-rotate-90]="isOpen()"
285
+ />
286
+ <i-lucide
287
+ [img]="isOpen() ? folderOpen : folder"
288
+ class="afp-w-4 afp-h-4 afp-flex-shrink-0 afp-text-amber-300/80"
289
+ />
290
+ <span class="afp-truncate afp-flex-1 afp-min-w-0">{{ node().name || '/' }}</span>
291
+ </button>
292
+ @if (isOpen() && node().children) {
293
+ @for (child of node().children; track child.path) {
294
+ <afp-zip-tree-item
295
+ [node]="child"
296
+ [depth]="depth() + 1"
297
+ [selectedPath]="selectedPath()"
298
+ [expanded]="expanded()"
299
+ (toggle)="toggle.emit($event)"
300
+ (select)="select.emit($event)"
301
+ (hover)="hover.emit($event)"
302
+ (leave)="leave.emit()"
303
+ />
304
+ }
305
+ }
306
+ </div>
307
+ } @else {
308
+ <button
309
+ type="button"
310
+ class="tree-row file-row"
311
+ [class.selected]="isSelected()"
312
+ [style]="padStyle()"
313
+ (click)="select.emit(node())"
314
+ (mouseenter)="handleEnter($event)"
315
+ (mouseleave)="leave.emit()"
316
+ >
317
+ <span class="afp-w-3.5 afp-h-3.5 afp-flex-shrink-0"></span>
318
+ <i-lucide [img]="fileIcon()" class="afp-w-4 afp-h-4 afp-flex-shrink-0 afp-text-fg-tertiary" />
319
+ <span class="afp-flex-1 afp-truncate afp-min-w-0">{{ node().name }}</span>
320
+ <span class="afp-text-xs afp-text-fg-disabled afp-flex-shrink-0 afp-ml-2">{{ formatFileSize(node().size) }}</span>
321
+ </button>
322
+ }
323
+ `, isInline: true, styles: [":host{display:block;width:100%}.tree-row{width:100%;display:flex;align-items:center;gap:.375rem;padding-top:.375rem;padding-bottom:.375rem;padding-right:.5rem;text-align:left;font-size:.875rem;background:transparent;border:0;cursor:pointer}.dir-row,.file-row{color:var(--fp-fg-secondary)}.tree-row:hover{background:var(--fp-surface-1)}.file-row.selected{background:var(--fp-line);color:var(--fp-fg-inverse)}\n"], dependencies: [{ kind: "component", type: ZipTreeItem, selector: "afp-zip-tree-item", inputs: ["node", "depth", "selectedPath", "expanded"], outputs: ["toggle", "select", "hover", "leave"] }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
324
+ }
325
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ZipTreeItem, decorators: [{
326
+ type: Component,
327
+ args: [{ selector: 'afp-zip-tree-item', standalone: true, imports: [LucideAngularModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
328
+ @if (node().isDir) {
329
+ <div>
330
+ <button
331
+ type="button"
332
+ class="tree-row dir-row"
333
+ [style]="padStyle()"
334
+ (click)="toggle.emit(node().path)"
335
+ (mouseenter)="handleEnter($event)"
336
+ (mouseleave)="leave.emit()"
337
+ >
338
+ <i-lucide
339
+ [img]="chevronRight"
340
+ class="afp-w-3.5 afp-h-3.5 afp-flex-shrink-0 afp-transition-transform"
341
+ [class.afp-rotate-90]="isOpen()"
342
+ />
343
+ <i-lucide
344
+ [img]="isOpen() ? folderOpen : folder"
345
+ class="afp-w-4 afp-h-4 afp-flex-shrink-0 afp-text-amber-300/80"
346
+ />
347
+ <span class="afp-truncate afp-flex-1 afp-min-w-0">{{ node().name || '/' }}</span>
348
+ </button>
349
+ @if (isOpen() && node().children) {
350
+ @for (child of node().children; track child.path) {
351
+ <afp-zip-tree-item
352
+ [node]="child"
353
+ [depth]="depth() + 1"
354
+ [selectedPath]="selectedPath()"
355
+ [expanded]="expanded()"
356
+ (toggle)="toggle.emit($event)"
357
+ (select)="select.emit($event)"
358
+ (hover)="hover.emit($event)"
359
+ (leave)="leave.emit()"
360
+ />
361
+ }
362
+ }
363
+ </div>
364
+ } @else {
365
+ <button
366
+ type="button"
367
+ class="tree-row file-row"
368
+ [class.selected]="isSelected()"
369
+ [style]="padStyle()"
370
+ (click)="select.emit(node())"
371
+ (mouseenter)="handleEnter($event)"
372
+ (mouseleave)="leave.emit()"
373
+ >
374
+ <span class="afp-w-3.5 afp-h-3.5 afp-flex-shrink-0"></span>
375
+ <i-lucide [img]="fileIcon()" class="afp-w-4 afp-h-4 afp-flex-shrink-0 afp-text-fg-tertiary" />
376
+ <span class="afp-flex-1 afp-truncate afp-min-w-0">{{ node().name }}</span>
377
+ <span class="afp-text-xs afp-text-fg-disabled afp-flex-shrink-0 afp-ml-2">{{ formatFileSize(node().size) }}</span>
378
+ </button>
379
+ }
380
+ `, styles: [":host{display:block;width:100%}.tree-row{width:100%;display:flex;align-items:center;gap:.375rem;padding-top:.375rem;padding-bottom:.375rem;padding-right:.5rem;text-align:left;font-size:.875rem;background:transparent;border:0;cursor:pointer}.dir-row,.file-row{color:var(--fp-fg-secondary)}.tree-row:hover{background:var(--fp-surface-1)}.file-row.selected{background:var(--fp-line);color:var(--fp-fg-inverse)}\n"] }]
381
+ }] });
382
+
383
+ const ZIP_TIP_STYLE_ID = 'afp-zip-tip-styles';
384
+ function ensureZipTipStyles() {
385
+ if (typeof document === 'undefined')
386
+ return;
387
+ if (document.getElementById(ZIP_TIP_STYLE_ID))
388
+ return;
389
+ const el = document.createElement('style');
390
+ el.id = ZIP_TIP_STYLE_ID;
391
+ el.textContent = `
392
+ .afp-zip-tip {
393
+ position: fixed;
394
+ z-index: 9999;
395
+ pointer-events: none;
396
+ transform: translateY(-50%);
397
+ padding: 4px 8px;
398
+ background: rgba(0, 0, 0, 0.85);
399
+ color: var(--fp-fg-inverse, #fff);
400
+ font-size: 12px;
401
+ line-height: 1.5;
402
+ border-radius: 4px;
403
+ white-space: nowrap;
404
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
405
+ }
406
+ `;
407
+ document.head.appendChild(el);
408
+ }
409
+ class ZipRenderer {
410
+ constructor() {
411
+ this.url = input.required();
412
+ this.nestingDepth = input(0);
413
+ this.emitter = new ToolbarEventEmitter();
414
+ this.locale = inject(LocaleService, { optional: true });
415
+ this.request = inject(RequestService, { optional: true });
416
+ this.t = this.locale?.t() ?? getFallbackTranslator();
417
+ this.splitRef = viewChild(ResizableSplit);
418
+ this.zip = signal(null);
419
+ this.tree = signal(null);
420
+ this.loading = signal(true);
421
+ this.error = signal(null);
422
+ this.expanded = signal(new Set(['']));
423
+ this.selected = signal(null);
424
+ this.previewLoading = signal(false);
425
+ this.previewError = signal(null);
426
+ this.hoverTip = signal(null);
427
+ this.totalStats = computed(() => {
428
+ const root = this.tree();
429
+ if (!root)
430
+ return null;
431
+ let files = 0, dirs = 0, size = 0;
432
+ const walk = (n) => {
433
+ if (n.isDir) {
434
+ if (n.path)
435
+ dirs++;
436
+ n.children?.forEach(walk);
437
+ }
438
+ else {
439
+ files++;
440
+ size += n.size;
441
+ }
442
+ };
443
+ walk(root);
444
+ return { files, dirs, size };
445
+ });
446
+ this.previewFiles = computed(() => {
447
+ const sel = this.selected();
448
+ if (!sel)
449
+ return [];
450
+ return [{ name: sel.name, url: sel.blobUrl, type: jM(sel.name) }];
451
+ });
452
+ this.tipEl = null;
453
+ this.getToolbarGroups = () => [];
454
+ this.onToolbarChange = (listener) => this.emitter.subscribe(listener);
455
+ ensureZipTipStyles();
456
+ effect(() => {
457
+ const url = this.url();
458
+ if (!url)
459
+ return;
460
+ untracked(() => { void this.load(); });
461
+ });
462
+ effect(() => {
463
+ this.totalStats();
464
+ this.emitter.notify();
465
+ });
466
+ effect(() => {
467
+ const tip = this.hoverTip();
468
+ untracked(() => this.syncTip(tip));
469
+ });
470
+ inject(DestroyRef).onDestroy(() => {
471
+ this.revokeCurrent();
472
+ this.syncTip(null);
473
+ });
474
+ }
475
+ handleToggle(path) {
476
+ const next = new Set(this.expanded());
477
+ if (next.has(path))
478
+ next.delete(path);
479
+ else
480
+ next.add(path);
481
+ this.expanded.set(next);
482
+ }
483
+ handleHover(payload) {
484
+ this.hoverTip.set({ text: payload.text, x: payload.rect.right + 8, y: payload.rect.top + payload.rect.height / 2 });
485
+ }
486
+ handleLeave() {
487
+ this.hoverTip.set(null);
488
+ }
489
+ async handleSelect(node) {
490
+ const z = this.zip();
491
+ if (!z || node.isDir)
492
+ return;
493
+ this.revokeCurrent();
494
+ this.previewLoading.set(true);
495
+ this.previewError.set(null);
496
+ try {
497
+ const mime = jM(node.name);
498
+ const blob = await wg(z, node.path, mime !== 'application/octet-stream' ? mime : undefined);
499
+ const blobUrl = URL.createObjectURL(blob);
500
+ this.selected.set({ path: node.path, name: node.name, size: node.size, blobUrl });
501
+ this.splitRef()?.switchTab('right');
502
+ }
503
+ catch (err) {
504
+ console.error(err);
505
+ this.previewError.set('条目读取失败');
506
+ }
507
+ finally {
508
+ this.previewLoading.set(false);
509
+ }
510
+ }
511
+ revokeCurrent() {
512
+ const sel = this.selected();
513
+ if (sel?.blobUrl)
514
+ URL.revokeObjectURL(sel.blobUrl);
515
+ }
516
+ syncTip(tip) {
517
+ if (!tip) {
518
+ this.tipEl?.remove();
519
+ this.tipEl = null;
520
+ return;
521
+ }
522
+ if (!this.tipEl) {
523
+ this.tipEl = document.createElement('div');
524
+ this.tipEl.className = 'afp-zip-tip';
525
+ document.body.appendChild(this.tipEl);
526
+ }
527
+ this.tipEl.textContent = tip.text;
528
+ this.tipEl.style.left = `${tip.x}px`;
529
+ this.tipEl.style.top = `${tip.y}px`;
530
+ }
531
+ async load() {
532
+ this.revokeCurrent();
533
+ this.selected.set(null);
534
+ this.loading.set(true);
535
+ this.error.set(null);
536
+ try {
537
+ const fetcher = this.request?.fetcher() ?? ((u, init) => fetch(u, init));
538
+ const res = await fetcher(this.url());
539
+ if (!res.ok)
540
+ throw new Error('加载失败');
541
+ const buf = await res.arrayBuffer();
542
+ const z = await ZI(buf);
543
+ const entries = Ig(z);
544
+ const root = Kg(entries);
545
+ this.zip.set(z);
546
+ this.tree.set(root);
547
+ const init = new Set(['']);
548
+ if (root.children)
549
+ for (const c of root.children)
550
+ if (c.isDir)
551
+ init.add(c.path);
552
+ this.expanded.set(init);
553
+ }
554
+ catch (err) {
555
+ console.error(err);
556
+ this.error.set(this.t('zip.load_failed'));
557
+ }
558
+ finally {
559
+ this.loading.set(false);
560
+ }
561
+ }
562
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ZipRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
563
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: ZipRenderer, isStandalone: true, selector: "afp-zip-renderer", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, nestingDepth: { classPropertyName: "nestingDepth", publicName: "nestingDepth", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "afp-block afp-w-full afp-h-full" }, viewQueries: [{ propertyName: "splitRef", first: true, predicate: ResizableSplit, descendants: true, isSignal: true }], ngImport: i0, template: `
564
+ @if (loading()) {
565
+ <div class="afp-flex afp-items-center afp-justify-center afp-w-full afp-h-full">
566
+ <div class="afp-w-12 afp-h-12 afp-border-4 afp-border-line-strong afp-border-t-spinner-head afp-rounded-full afp-animate-spin"></div>
567
+ </div>
568
+ } @else if (error() || !tree()) {
569
+ <afp-renderer-error [message]="error() || t('zip.parse_failed')" />
570
+ } @else {
571
+ <afp-resizable-split
572
+ [initialLeftWidth]="280"
573
+ [minLeftWidth]="180"
574
+ [maxLeftWidth]="560"
575
+ storageKey="afp-zip-split-left"
576
+ [mobileTabMode]="true"
577
+ leftTabLabel="文件树"
578
+ rightTabLabel="预览"
579
+ >
580
+ <div splitLeft class="afp-w-full afp-h-full afp-overflow-auto">
581
+ @for (child of tree()!.children || []; track child.path) {
582
+ <afp-zip-tree-item
583
+ [node]="child"
584
+ [depth]="0"
585
+ [selectedPath]="selected()?.path ?? null"
586
+ [expanded]="expanded()"
587
+ (toggle)="handleToggle($event)"
588
+ (select)="handleSelect($event)"
589
+ (hover)="handleHover($event)"
590
+ (leave)="handleLeave()"
591
+ />
592
+ }
593
+ </div>
594
+ <div splitRight class="afp-w-full afp-h-full afp-flex afp-flex-col">
595
+ @if (!selected()) {
596
+ <div class="afp-flex-1 afp-flex afp-items-center afp-justify-center afp-text-fg-muted afp-text-sm afp-p-6">
597
+ 从左侧选择一个文件以预览
598
+ </div>
599
+ } @else if (previewLoading()) {
600
+ <div class="afp-flex-1 afp-flex afp-items-center afp-justify-center">
601
+ <div class="afp-w-8 afp-h-8 afp-border-4 afp-border-line-strong afp-border-t-spinner-head afp-rounded-full afp-animate-spin"></div>
602
+ </div>
603
+ } @else if (previewError()) {
604
+ <div class="afp-flex-1 afp-flex afp-items-center afp-justify-center afp-text-fg-secondary">{{ previewError() }}</div>
605
+ } @else {
606
+ <div class="afp-flex-1 afp-min-h-0 afp-overflow-hidden afp-flex afp-relative afp-z-0">
607
+ <FilePreviewContent
608
+ mode="embed"
609
+ [files]="previewFiles()"
610
+ [currentIndex]="0"
611
+ [zipNestingDepth]="nestingDepth() + 1"
612
+ />
613
+ </div>
614
+ }
615
+ </div>
616
+ </afp-resizable-split>
617
+ }
618
+ `, isInline: true, dependencies: [{ kind: "component", type: RendererError, selector: "afp-renderer-error", inputs: ["message", "detail", "showIcon"] }, { kind: "component", type: ResizableSplit, selector: "afp-resizable-split", inputs: ["initialLeftWidth", "minLeftWidth", "maxLeftWidth", "minRightWidth", "storageKey", "desktopMedia", "mobileTabMode", "leftTabLabel", "rightTabLabel"] }, { kind: "component", type: ZipTreeItem, selector: "afp-zip-tree-item", inputs: ["node", "depth", "selectedPath", "expanded"], outputs: ["toggle", "select", "hover", "leave"] }, { kind: "component", type: FilePreviewContent, selector: "FilePreviewContent, afp-file-preview-content", inputs: ["files", "currentIndex", "customRenderers", "mode", "zipNestingDepth", "locale", "messages", "headless", "theme", "requestInit", "requestHandler", "shouldFetchAsBlob", "onDownload", "showClose", "showDownload"], outputs: ["navigate", "close", "customEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
619
+ }
620
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ZipRenderer, decorators: [{
621
+ type: Component,
622
+ args: [{
623
+ selector: 'afp-zip-renderer',
624
+ standalone: true,
625
+ imports: [RendererError, ResizableSplit, ZipTreeItem, FilePreviewContent],
626
+ changeDetection: ChangeDetectionStrategy.OnPush,
627
+ host: { class: 'afp-block afp-w-full afp-h-full' },
628
+ template: `
629
+ @if (loading()) {
630
+ <div class="afp-flex afp-items-center afp-justify-center afp-w-full afp-h-full">
631
+ <div class="afp-w-12 afp-h-12 afp-border-4 afp-border-line-strong afp-border-t-spinner-head afp-rounded-full afp-animate-spin"></div>
632
+ </div>
633
+ } @else if (error() || !tree()) {
634
+ <afp-renderer-error [message]="error() || t('zip.parse_failed')" />
635
+ } @else {
636
+ <afp-resizable-split
637
+ [initialLeftWidth]="280"
638
+ [minLeftWidth]="180"
639
+ [maxLeftWidth]="560"
640
+ storageKey="afp-zip-split-left"
641
+ [mobileTabMode]="true"
642
+ leftTabLabel="文件树"
643
+ rightTabLabel="预览"
644
+ >
645
+ <div splitLeft class="afp-w-full afp-h-full afp-overflow-auto">
646
+ @for (child of tree()!.children || []; track child.path) {
647
+ <afp-zip-tree-item
648
+ [node]="child"
649
+ [depth]="0"
650
+ [selectedPath]="selected()?.path ?? null"
651
+ [expanded]="expanded()"
652
+ (toggle)="handleToggle($event)"
653
+ (select)="handleSelect($event)"
654
+ (hover)="handleHover($event)"
655
+ (leave)="handleLeave()"
656
+ />
657
+ }
658
+ </div>
659
+ <div splitRight class="afp-w-full afp-h-full afp-flex afp-flex-col">
660
+ @if (!selected()) {
661
+ <div class="afp-flex-1 afp-flex afp-items-center afp-justify-center afp-text-fg-muted afp-text-sm afp-p-6">
662
+ 从左侧选择一个文件以预览
663
+ </div>
664
+ } @else if (previewLoading()) {
665
+ <div class="afp-flex-1 afp-flex afp-items-center afp-justify-center">
666
+ <div class="afp-w-8 afp-h-8 afp-border-4 afp-border-line-strong afp-border-t-spinner-head afp-rounded-full afp-animate-spin"></div>
667
+ </div>
668
+ } @else if (previewError()) {
669
+ <div class="afp-flex-1 afp-flex afp-items-center afp-justify-center afp-text-fg-secondary">{{ previewError() }}</div>
670
+ } @else {
671
+ <div class="afp-flex-1 afp-min-h-0 afp-overflow-hidden afp-flex afp-relative afp-z-0">
672
+ <FilePreviewContent
673
+ mode="embed"
674
+ [files]="previewFiles()"
675
+ [currentIndex]="0"
676
+ [zipNestingDepth]="nestingDepth() + 1"
677
+ />
678
+ </div>
679
+ }
680
+ </div>
681
+ </afp-resizable-split>
682
+ }
683
+ `,
684
+ }]
685
+ }], ctorParameters: () => [] });
686
+
687
+ export { ZipRenderer };
688
+ //# sourceMappingURL=eternalheart-angular-file-preview-eternalheart-angular-file-preview-index-BGqTRZbm-CAOLRw20.mjs.map