@propbinder/mobile-design 0.2.50 → 0.2.53

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 (221) hide show
  1. package/fesm2022/propbinder-mobile-design.mjs +26206 -0
  2. package/fesm2022/propbinder-mobile-design.mjs.map +1 -0
  3. package/index.d.ts +8193 -0
  4. package/package.json +39 -3
  5. package/ng-package.json +0 -24
  6. package/src/animations/page-transitions.ts +0 -165
  7. package/src/components/action-list-item/ds-mobile-action-list-item.ts +0 -102
  8. package/src/components/action-list-item/index.ts +0 -2
  9. package/src/components/app-icon/ds-app-icon.ts +0 -133
  10. package/src/components/app-icon/index.ts +0 -2
  11. package/src/components/attachment-preview/ds-mobile-attachment-preview.css +0 -139
  12. package/src/components/attachment-preview/ds-mobile-attachment-preview.ts +0 -164
  13. package/src/components/attachment-preview/index.ts +0 -1
  14. package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +0 -142
  15. package/src/components/avatar-with-badge/index.ts +0 -2
  16. package/src/components/booking-modal/ds-mobile-booking-confirmation-wrapper.ts +0 -71
  17. package/src/components/booking-modal/ds-mobile-booking-modal.service.ts +0 -121
  18. package/src/components/booking-modal/ds-mobile-booking-modal.ts +0 -598
  19. package/src/components/booking-modal/ds-mobile-booking-summary.ts +0 -161
  20. package/src/components/booking-modal/index.ts +0 -4
  21. package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +0 -266
  22. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-header.ts +0 -146
  23. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-wrapper.ts +0 -156
  24. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +0 -101
  25. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +0 -169
  26. package/src/components/bottom-sheet/ds-mobile-confirmation-sheet.ts +0 -211
  27. package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +0 -578
  28. package/src/components/bottom-sheet/ds-mobile-profile-actions-sheet.ts +0 -614
  29. package/src/components/bottom-sheet/index.ts +0 -8
  30. package/src/components/bottom-sheet/modal-shadow-fix.ts +0 -42
  31. package/src/components/card-inline/ds-mobile-card-inline.ts +0 -301
  32. package/src/components/card-inline/index.ts +0 -2
  33. package/src/components/card-inline-banner/ds-mobile-card-inline-banner.ts +0 -118
  34. package/src/components/card-inline-banner/index.ts +0 -1
  35. package/src/components/card-inline-contact/ds-mobile-card-inline-contact.ts +0 -120
  36. package/src/components/card-inline-contact/index.ts +0 -1
  37. package/src/components/card-inline-file/ds-mobile-card-inline-file.ts +0 -141
  38. package/src/components/card-inline-file/index.ts +0 -1
  39. package/src/components/chat-modal/ds-mobile-chat-modal.css +0 -159
  40. package/src/components/chat-modal/ds-mobile-chat-modal.service.ts +0 -105
  41. package/src/components/chat-modal/ds-mobile-chat-modal.ts +0 -918
  42. package/src/components/chat-modal/index.ts +0 -8
  43. package/src/components/comment/ds-mobile-comment.ts +0 -568
  44. package/src/components/comment/index.ts +0 -2
  45. package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +0 -182
  46. package/src/components/contact-list-item/index.ts +0 -2
  47. package/src/components/content/ds-mobile-content.ts +0 -139
  48. package/src/components/content/index.ts +0 -2
  49. package/src/components/dropdown/ds-mobile-dropdown.css +0 -199
  50. package/src/components/dropdown/ds-mobile-dropdown.ts +0 -340
  51. package/src/components/dropdown/index.ts +0 -2
  52. package/src/components/ds-mobile-tabs.css +0 -407
  53. package/src/components/ds-mobile-tabs.ts +0 -216
  54. package/src/components/empty-state/ds-mobile-empty-state.ts +0 -120
  55. package/src/components/empty-state/index.ts +0 -2
  56. package/src/components/fab/ds-mobile-fab.ts +0 -315
  57. package/src/components/fab/index.ts +0 -1
  58. package/src/components/facility-creation-modal/ds-mobile-facility-creation-confirmation-wrapper.ts +0 -121
  59. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.css +0 -189
  60. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.service.ts +0 -135
  61. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.ts +0 -656
  62. package/src/components/facility-creation-modal/index.ts +0 -9
  63. package/src/components/facility-creation-modal/sheets/ds-mobile-access-sheet.ts +0 -105
  64. package/src/components/facility-creation-modal/sheets/ds-mobile-price-sheet.ts +0 -188
  65. package/src/components/facility-creation-modal/sheets/ds-mobile-when-can-book-sheet.ts +0 -460
  66. package/src/components/facility-creation-modal/sheets/ds-mobile-who-can-book-sheet.ts +0 -134
  67. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.service.ts +0 -69
  68. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.ts +0 -379
  69. package/src/components/facility-detail-modal/index.ts +0 -2
  70. package/src/components/file-attachment/ds-mobile-file-attachment.ts +0 -164
  71. package/src/components/file-attachment/index.ts +0 -2
  72. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.css +0 -214
  73. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +0 -84
  74. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +0 -424
  75. package/src/components/handbook-detail-modal/index.ts +0 -3
  76. package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +0 -175
  77. package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +0 -533
  78. package/src/components/handbook-folder/index.ts +0 -4
  79. package/src/components/header-content/ds-mobile-header-content.ts +0 -222
  80. package/src/components/header-content/index.ts +0 -2
  81. package/src/components/illustration/ds-mobile-illustration.ts +0 -124
  82. package/src/components/illustration/index.ts +0 -2
  83. package/src/components/index.ts +0 -124
  84. package/src/components/inline-photo/ds-mobile-inline-photo.ts +0 -361
  85. package/src/components/inline-photo/index.ts +0 -1
  86. package/src/components/inline-tabs/ds-mobile-inline-tabs.ts +0 -132
  87. package/src/components/inline-tabs/index.ts +0 -2
  88. package/src/components/interactive-list-item-booking/ds-mobile-interactive-list-item-booking.ts +0 -350
  89. package/src/components/interactive-list-item-booking/index.ts +0 -1
  90. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +0 -321
  91. package/src/components/interactive-list-item-inquiry/index.ts +0 -2
  92. package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +0 -237
  93. package/src/components/interactive-list-item-message/index.ts +0 -2
  94. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +0 -549
  95. package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +0 -124
  96. package/src/components/interactive-list-item-post/index.ts +0 -13
  97. package/src/components/lightbox/ds-mobile-lightbox-footer.ts +0 -315
  98. package/src/components/lightbox/ds-mobile-lightbox-header.ts +0 -202
  99. package/src/components/lightbox/ds-mobile-lightbox-image.ts +0 -484
  100. package/src/components/lightbox/ds-mobile-lightbox-pdf.css +0 -377
  101. package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +0 -374
  102. package/src/components/lightbox/ds-mobile-lightbox.css +0 -587
  103. package/src/components/lightbox/ds-mobile-lightbox.service.ts +0 -296
  104. package/src/components/lightbox/ds-mobile-lightbox.ts +0 -529
  105. package/src/components/lightbox/index.ts +0 -22
  106. package/src/components/list-item/ds-mobile-list-item.ts +0 -603
  107. package/src/components/list-item/index.ts +0 -2
  108. package/src/components/list-item-static/ds-mobile-list-item-static.ts +0 -133
  109. package/src/components/list-item-static/index.ts +0 -2
  110. package/src/components/loader-overlay/ds-mobile-loader-overlay.css +0 -49
  111. package/src/components/loader-overlay/ds-mobile-loader-overlay.ts +0 -77
  112. package/src/components/loader-overlay/index.ts +0 -1
  113. package/src/components/logo/ds-logo.ts +0 -95
  114. package/src/components/logo/index.ts +0 -2
  115. package/src/components/message-bubble/ds-mobile-message-bubble.ts +0 -633
  116. package/src/components/message-bubble/index.ts +0 -7
  117. package/src/components/message-composer/ds-mobile-message-composer.ts +0 -1146
  118. package/src/components/message-composer/index.ts +0 -7
  119. package/src/components/modal/ds-mobile-modal.css +0 -163
  120. package/src/components/modal/ds-mobile-modal.service.ts +0 -329
  121. package/src/components/modal/index.ts +0 -8
  122. package/src/components/modal-base/ds-mobile-modal-base.css +0 -378
  123. package/src/components/modal-base/ds-mobile-modal-base.ts +0 -261
  124. package/src/components/modal-base/index.ts +0 -2
  125. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.css +0 -112
  126. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.service.ts +0 -93
  127. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.ts +0 -442
  128. package/src/components/new-inquiry-modal/index.ts +0 -4
  129. package/src/components/offline-banner/ds-mobile-offline-banner.ts +0 -135
  130. package/src/components/offline-banner/index.ts +0 -1
  131. package/src/components/page-details/ds-mobile-page-details.css +0 -83
  132. package/src/components/page-details/ds-mobile-page-details.ts +0 -282
  133. package/src/components/page-details/index.ts +0 -2
  134. package/src/components/page-main/ds-mobile-page-main.css +0 -68
  135. package/src/components/page-main/ds-mobile-page-main.ts +0 -421
  136. package/src/components/page-main/index.ts +0 -2
  137. package/src/components/post-composer/ds-mobile-post-composer.ts +0 -140
  138. package/src/components/post-composer/index.ts +0 -2
  139. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.css +0 -390
  140. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +0 -108
  141. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +0 -722
  142. package/src/components/post-detail-modal/index.ts +0 -9
  143. package/src/components/property-banner/ds-mobile-property-banner.ts +0 -95
  144. package/src/components/property-banner/index.ts +0 -2
  145. package/src/components/section/ds-mobile-section.ts +0 -263
  146. package/src/components/section/index.ts +0 -2
  147. package/src/components/shared/directives/index.ts +0 -2
  148. package/src/components/shared/directives/long-press.directive.ts +0 -212
  149. package/src/components/shared/index.ts +0 -3
  150. package/src/components/shared/mobile-modal-base.ts +0 -457
  151. package/src/components/shared/mobile-page-base.ts +0 -204
  152. package/src/components/swiper/ds-mobile-swiper-with-nav.ts +0 -160
  153. package/src/components/swiper/ds-mobile-swiper.ts +0 -327
  154. package/src/components/swiper/index.ts +0 -3
  155. package/src/components/system-message-banner/ds-mobile-system-message-banner.ts +0 -129
  156. package/src/components/system-message-banner/index.ts +0 -2
  157. package/src/components/tab-bar/ds-mobile-tab-bar.css +0 -533
  158. package/src/components/tab-bar/ds-mobile-tab-bar.ts +0 -735
  159. package/src/components/tab-bar/index.ts +0 -2
  160. package/src/components/tabs/ds-mobile-tabs.css +0 -25
  161. package/src/components/tabs/ds-mobile-tabs.ts +0 -89
  162. package/src/components/tabs/index.ts +0 -2
  163. package/src/components/text-input/ds-text-input.ts +0 -287
  164. package/src/components/text-input/index.ts +0 -2
  165. package/src/examples/booking.page.ts +0 -434
  166. package/src/examples/community.page.ts +0 -776
  167. package/src/examples/handbook.page.ts +0 -324
  168. package/src/examples/home.page.ts +0 -347
  169. package/src/examples/index.ts +0 -12
  170. package/src/examples/inquiries.example.ts +0 -273
  171. package/src/examples/inquiry-detail.example.css +0 -189
  172. package/src/examples/inquiry-detail.example.ts +0 -415
  173. package/src/examples/mobile-tabs-example.component.ts +0 -208
  174. package/src/examples/post-create.page.ts +0 -311
  175. package/src/examples/post-detail.page.ts +0 -296
  176. package/src/examples/sign-in.page.ts +0 -291
  177. package/src/examples/whitelabel-demo-modal.component.ts +0 -1094
  178. package/src/examples/whitelabel-demo-modal.service.ts +0 -77
  179. package/src/models/index.ts +0 -7
  180. package/src/models/post.model.ts +0 -41
  181. package/src/pages/community.page.ts +0 -769
  182. package/src/pages/handbook.page.ts +0 -388
  183. package/src/pages/home.page.ts +0 -303
  184. package/src/pages/index.ts +0 -11
  185. package/src/pages/inquiries.example.ts +0 -273
  186. package/src/pages/inquiry-detail.example.css +0 -189
  187. package/src/pages/inquiry-detail.example.ts +0 -415
  188. package/src/pages/mobile-tabs-example.component.ts +0 -179
  189. package/src/pages/post-create.page.ts +0 -311
  190. package/src/pages/post-detail.page.ts +0 -296
  191. package/src/pages/sign-in.page.ts +0 -291
  192. package/src/pages/whitelabel-demo-modal.component.ts +0 -1094
  193. package/src/pages/whitelabel-demo-modal.service.ts +0 -77
  194. package/src/public-api.ts +0 -6
  195. package/src/services/base-modal.service.ts +0 -101
  196. package/src/services/index.ts +0 -11
  197. package/src/services/posts.service.ts +0 -542
  198. package/src/services/tracking-permission.service.ts +0 -88
  199. package/src/services/user.service.ts +0 -60
  200. package/src/services/whitelabel.service.ts +0 -675
  201. package/tsconfig.lib.json +0 -17
  202. package/tsconfig.lib.prod.json +0 -9
  203. package/tsconfig.spec.json +0 -13
  204. /package/{src/assets → assets}/fonts/Brockmann-Bold.otf +0 -0
  205. /package/{src/assets → assets}/fonts/Brockmann-BoldItalic.otf +0 -0
  206. /package/{src/assets → assets}/fonts/Brockmann-Medium.otf +0 -0
  207. /package/{src/assets → assets}/fonts/Brockmann-MediumItalic.otf +0 -0
  208. /package/{src/assets → assets}/fonts/Brockmann-Regular.otf +0 -0
  209. /package/{src/assets → assets}/fonts/Brockmann-RegularItalic.otf +0 -0
  210. /package/{src/assets → assets}/fonts/Brockmann-SemiBold.otf +0 -0
  211. /package/{src/assets → assets}/fonts/Brockmann-SemiBoldItalic.otf +0 -0
  212. /package/{src/assets → assets}/fonts/Brockmann_desktop_license.pdf +0 -0
  213. /package/{src/assets → assets}/fonts/brockmann-medium-webfont.woff2 +0 -0
  214. /package/{src/assets → assets}/fonts/brockmann-mediumitalic-webfont.woff2 +0 -0
  215. /package/{src/assets → assets}/fonts/brockmann-regular-webfont.woff2 +0 -0
  216. /package/{src/assets → assets}/fonts/brockmann-regularitalic-webfont.woff2 +0 -0
  217. /package/{src/assets → assets}/fonts/brockmann-semibold-webfont.woff2 +0 -0
  218. /package/{src/assets → assets}/fonts/brockmann-semibolditalic-webfont.woff2 +0 -0
  219. /package/{src/styles → styles}/ionic.css +0 -0
  220. /package/{src/components/shared → styles}/mobile-common.css +0 -0
  221. /package/{src/components/shared → styles}/mobile-page-base.css +0 -0
@@ -1,484 +0,0 @@
1
- import {
2
- Component,
3
- signal,
4
- computed,
5
- ViewChild,
6
- ElementRef,
7
- AfterViewInit,
8
- OnDestroy,
9
- OnInit,
10
- CUSTOM_ELEMENTS_SCHEMA,
11
- HostListener
12
- } from '@angular/core';
13
- import { CommonModule } from '@angular/common';
14
- import {
15
- IonSpinner,
16
- GestureController,
17
- Gesture
18
- } from '@ionic/angular/standalone';
19
- import { Share } from '@capacitor/share';
20
- import { Haptics, ImpactStyle } from '@capacitor/haptics';
21
- import { DsMobileLightboxHeaderComponent } from './ds-mobile-lightbox-header';
22
- import { DsMobileLightboxFooterComponent } from './ds-mobile-lightbox-footer';
23
- import type { LightboxImage, LightboxAuthor } from './ds-mobile-lightbox.service';
24
- import Swiper from 'swiper';
25
- import type { SwiperOptions } from 'swiper/types';
26
-
27
- /**
28
- * DsMobileLightboxImageComponent
29
- *
30
- * Full-screen image lightbox component with Swiper.js navigation and pinch-zoom.
31
- *
32
- * This component is typically not used directly - use DsMobileLightboxService instead.
33
- *
34
- * Features:
35
- * - Swiper.js for smooth image navigation
36
- * - Pinch to zoom in/out
37
- * - Double-tap to toggle zoom
38
- * - Swipe down to close (when not zoomed)
39
- * - Image counter and navigation controls
40
- *
41
- * @example
42
- * ```typescript
43
- * // Don't instantiate directly - use the service:
44
- * constructor(private lightbox: DsMobileLightboxService) {}
45
- *
46
- * openImage() {
47
- * this.lightbox.openImages({
48
- * images: [{ type: 'image', src: 'image.jpg', title: 'My Image' }]
49
- * });
50
- * }
51
- * ```
52
- */
53
- @Component({
54
- selector: 'ds-mobile-lightbox-image',
55
- standalone: true,
56
- imports: [
57
- CommonModule,
58
- IonSpinner,
59
- DsMobileLightboxHeaderComponent,
60
- DsMobileLightboxFooterComponent
61
- ],
62
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
63
- template: `
64
- <div class="lightbox-overlay"
65
- [class.zoomed]="isZoomed()">
66
-
67
- <div class="lightbox-wrapper">
68
- <!-- Header with author info and action buttons -->
69
- <ds-mobile-lightbox-header
70
- [author]="author"
71
- (closeClick)="close()"
72
- (shareClick)="onShare()"
73
- />
74
-
75
- <!-- Swiper container -->
76
- <div class="swiper-container" #swiperContainer>
77
- <div class="swiper-wrapper">
78
- @for (image of images; track image.src; let i = $index) {
79
- <div class="swiper-slide">
80
- <div class="image-zoom-container" [attr.data-index]="i">
81
- <img
82
- [src]="image.src"
83
- [alt]="image.alt || 'Lightbox image'"
84
- class="lightbox-image"
85
- (load)="onImageLoad(i)"
86
- (error)="onImageError(i)">
87
- </div>
88
- </div>
89
- }
90
- </div>
91
- </div>
92
-
93
- <!-- Loading indicator -->
94
- @if (isLoading()) {
95
- <div class="loading-spinner">
96
- <ion-spinner name="crescent"></ion-spinner>
97
- </div>
98
- }
99
-
100
- <!-- Footer with navigation and actions -->
101
- <ds-mobile-lightbox-footer
102
- [showNavigation]="showControls && images.length > 1"
103
- [showActions]="showActions"
104
- [currentIndex]="currentIndex()"
105
- [totalImages]="images.length"
106
- [isLiked]="isLiked()"
107
- [likeCount]="likeCount()"
108
- [commentCount]="commentCount()"
109
- (prevClick)="previousImage()"
110
- (nextClick)="nextImage()"
111
- (likeClick)="onLikeToggle()"
112
- (commentClick)="onReply()"
113
- />
114
- </div>
115
- </div>
116
- `,
117
- styleUrl: './ds-mobile-lightbox.css'
118
- })
119
- export class DsMobileLightboxImageComponent implements OnInit, AfterViewInit, OnDestroy {
120
- // Inputs (passed from service as regular properties, not signals)
121
- images!: LightboxImage[];
122
- author?: LightboxAuthor;
123
- initialIndex: number = 0;
124
- enableZoom: boolean = true;
125
- showControls: boolean = true;
126
- enableSwipe: boolean = true;
127
- showInfo: boolean = true;
128
- showActions: boolean = false;
129
- animation: 'fade' | 'zoom' | 'slide' = 'fade';
130
- onCloseRequested?: () => void;
131
-
132
- // View children
133
- @ViewChild('swiperContainer', { read: ElementRef }) swiperContainer!: ElementRef<HTMLDivElement>;
134
-
135
- // State
136
- currentIndex = signal(0);
137
- scale = signal(1);
138
- isZoomed = signal(false);
139
- isLoading = signal(true);
140
- hasError = signal(false);
141
-
142
- // Action states
143
- isLiked = signal(false);
144
- likeCount = signal(0);
145
- commentCount = signal(0);
146
-
147
- // Computed
148
- currentImage = computed(() => this.images[this.currentIndex()]);
149
-
150
- // Swiper instance
151
- private swiper?: Swiper;
152
- private zoomData: Map<number, { scale: number; x: number; y: number }> = new Map();
153
-
154
- constructor(
155
- private gestureCtrl: GestureController
156
- ) {}
157
-
158
- ngOnInit(): void {
159
- // Set initial index from the passed property
160
- if (this.initialIndex !== undefined) {
161
- this.currentIndex.set(this.initialIndex);
162
- }
163
-
164
- // Initialize action states from current image
165
- const currentImg = this.images[this.currentIndex()];
166
- if (currentImg) {
167
- this.isLiked.set(currentImg.isLiked ?? false);
168
- this.likeCount.set(currentImg.likeCount ?? 0);
169
- this.commentCount.set(currentImg.commentCount ?? 0);
170
- }
171
- }
172
-
173
- ngAfterViewInit(): void {
174
- setTimeout(() => {
175
- this.initializeSwiper();
176
- this.initializeZoomGestures();
177
- }, 100);
178
- }
179
-
180
- ngOnDestroy(): void {
181
- // Clean up Swiper
182
- if (this.swiper) {
183
- this.swiper.destroy();
184
- this.swiper = undefined;
185
- }
186
- }
187
- /**
188
- * Initialize Swiper for image navigation
189
- */
190
- private initializeSwiper(): void {
191
- if (!this.swiperContainer) {
192
- console.error('[Lightbox] Swiper container not found');
193
- return;
194
- }
195
-
196
- const swiperOptions: SwiperOptions = {
197
- initialSlide: this.initialIndex,
198
- speed: 300,
199
- resistance: true,
200
- resistanceRatio: 0.85,
201
- slidesPerView: 1,
202
- spaceBetween: 0,
203
- touchRatio: 1,
204
- longSwipesRatio: 0.5,
205
- threshold: 10,
206
- on: {
207
- slideChange: (swiper) => {
208
- this.currentIndex.set(swiper.activeIndex);
209
- this.updateActionStates();
210
-
211
- // Check if the image is already loaded
212
- const currentSlide = swiper.slides[swiper.activeIndex];
213
- const img = currentSlide?.querySelector('img');
214
- if (img && img.complete && img.naturalHeight !== 0) {
215
- // Image is already loaded
216
- this.isLoading.set(false);
217
- }
218
- },
219
- slideChangeTransitionStart: () => {
220
- // Don't show loading spinner if image is already loaded
221
- const currentSlide = this.swiper?.slides[this.swiper.activeIndex];
222
- const img = currentSlide?.querySelector('img');
223
- if (!img || !img.complete || img.naturalHeight === 0) {
224
- this.isLoading.set(true);
225
- }
226
- }
227
- }
228
- };
229
-
230
- this.swiper = new Swiper(this.swiperContainer.nativeElement, swiperOptions);
231
-
232
- // Check if the initial image is already loaded
233
- setTimeout(() => {
234
- const currentSlide = this.swiper?.slides[this.currentIndex()];
235
- const img = currentSlide?.querySelector('img');
236
- if (img && img.complete && img.naturalHeight !== 0) {
237
- this.isLoading.set(false);
238
- }
239
- }, 0);
240
- }
241
-
242
- /**
243
- * Initialize pinch-zoom gestures for all slides
244
- */
245
- private initializeZoomGestures(): void {
246
- if (!this.enableZoom) return;
247
-
248
- const slides = this.swiperContainer.nativeElement.querySelectorAll('.image-zoom-container');
249
-
250
- slides.forEach((slide, index) => {
251
- this.initializeZoomForSlide(slide as HTMLElement, index);
252
- });
253
- }
254
-
255
- /**
256
- * Initialize zoom gestures for a specific slide
257
- */
258
- private initializeZoomForSlide(container: HTMLElement, index: number): void {
259
- let initialDistance = 0;
260
- let initialScale = 1;
261
- let currentScale = 1;
262
- let lastTap = 0;
263
-
264
- // Double-tap to zoom
265
- container.addEventListener('click', (event: MouseEvent) => {
266
- const now = Date.now();
267
- const timeSinceLastTap = now - lastTap;
268
-
269
- if (timeSinceLastTap < 300 && timeSinceLastTap > 0) {
270
- event.preventDefault();
271
- this.toggleZoom(container, index);
272
- }
273
-
274
- lastTap = now;
275
- });
276
-
277
- // Pinch to zoom
278
- const getTouchDistance = (touches: TouchList) => {
279
- const dx = touches[0].clientX - touches[1].clientX;
280
- const dy = touches[0].clientY - touches[1].clientY;
281
- return Math.sqrt(dx * dx + dy * dy);
282
- };
283
-
284
- container.addEventListener('touchstart', (event: TouchEvent) => {
285
- if (event.touches.length === 2) {
286
- event.preventDefault();
287
- initialDistance = getTouchDistance(event.touches);
288
- const zoomData = this.zoomData.get(index) || { scale: 1, x: 0, y: 0 };
289
- initialScale = zoomData.scale;
290
-
291
- // Disable Swiper when zooming
292
- if (this.swiper) {
293
- this.swiper.allowTouchMove = false;
294
- }
295
- }
296
- }, { passive: false });
297
-
298
- container.addEventListener('touchmove', (event: TouchEvent) => {
299
- if (event.touches.length === 2) {
300
- event.preventDefault();
301
-
302
- const currentDistance = getTouchDistance(event.touches);
303
- const pinchScale = currentDistance / initialDistance;
304
-
305
- currentScale = Math.max(1, Math.min(initialScale * pinchScale, 4));
306
-
307
- const img = container.querySelector('img');
308
- if (img) {
309
- img.style.transform = `scale(${currentScale})`;
310
- }
311
-
312
- if (currentScale > 1) {
313
- this.isZoomed.set(true);
314
- } else {
315
- this.isZoomed.set(false);
316
- }
317
- }
318
- }, { passive: false });
319
-
320
- container.addEventListener('touchend', (event: TouchEvent) => {
321
- if (event.touches.length < 2) {
322
- // Save zoom state
323
- this.zoomData.set(index, { scale: currentScale, x: 0, y: 0 });
324
-
325
- // Re-enable Swiper if not zoomed
326
- if (this.swiper && currentScale <= 1) {
327
- this.swiper.allowTouchMove = true;
328
- }
329
- }
330
- });
331
- }
332
-
333
- /**
334
- * Toggle zoom on double-tap
335
- */
336
- private toggleZoom(container: HTMLElement, index: number): void {
337
- const zoomData = this.zoomData.get(index) || { scale: 1, x: 0, y: 0 };
338
- const img = container.querySelector('img');
339
-
340
- if (!img) return;
341
-
342
- if (zoomData.scale > 1) {
343
- // Zoom out
344
- img.style.transform = 'scale(1)';
345
- this.zoomData.set(index, { scale: 1, x: 0, y: 0 });
346
- this.isZoomed.set(false);
347
- if (this.swiper) {
348
- this.swiper.allowTouchMove = true;
349
- }
350
- } else {
351
- // Zoom in
352
- img.style.transform = 'scale(2)';
353
- this.zoomData.set(index, { scale: 2, x: 0, y: 0 });
354
- this.isZoomed.set(true);
355
- if (this.swiper) {
356
- this.swiper.allowTouchMove = false;
357
- }
358
- }
359
- }
360
-
361
- /**
362
- * Update action states (like, comments) when slide changes
363
- */
364
- private updateActionStates(): void {
365
- const currentImg = this.images[this.currentIndex()];
366
- if (currentImg) {
367
- this.isLiked.set(currentImg.isLiked ?? false);
368
- this.likeCount.set(currentImg.likeCount ?? 0);
369
- this.commentCount.set(currentImg.commentCount ?? 0);
370
- }
371
- }
372
-
373
- /**
374
- * Close the lightbox
375
- */
376
- close(): void {
377
- if (this.onCloseRequested) {
378
- this.onCloseRequested();
379
- }
380
- }
381
-
382
- /**
383
- * Handle share button click
384
- */
385
- async onShare(): Promise<void> {
386
- console.log('[Lightbox] Share button clicked');
387
- const currentImg = this.currentImage();
388
-
389
- if (!currentImg?.src) {
390
- console.warn('[Lightbox] No image to share');
391
- return;
392
- }
393
-
394
- try {
395
- // Check if Web Share API is available (for browser)
396
- if (navigator.share) {
397
- await navigator.share({
398
- title: currentImg.title || 'Shared Image',
399
- text: currentImg.description || '',
400
- url: currentImg.src,
401
- });
402
- console.log('[Lightbox] Shared via Web Share API');
403
- } else {
404
- // Fallback to Capacitor Share API (for native apps)
405
- await Share.share({
406
- title: currentImg.title || 'Shared Image',
407
- url: currentImg.src,
408
- dialogTitle: 'Share Image',
409
- });
410
- console.log('[Lightbox] Shared via Capacitor Share API');
411
- }
412
- } catch (error: any) {
413
- // User cancellation is expected and not an error
414
- if (error?.message?.includes('cancel') || error?.code === 'USER_CANCELLED') {
415
- console.log('[Lightbox] Share cancelled by user');
416
- return;
417
- }
418
- console.error('[Lightbox] Share failed:', error);
419
- }
420
- }
421
-
422
- /**
423
- * Handle like button toggle
424
- */
425
- onLikeToggle(): void {
426
- console.log('[Lightbox] Like button toggled');
427
- this.isLiked.update(liked => !liked);
428
-
429
- if (this.isLiked()) {
430
- this.likeCount.update(count => count + 1);
431
- } else {
432
- this.likeCount.update(count => Math.max(0, count - 1));
433
- }
434
- }
435
-
436
- /**
437
- * Handle reply/comment button click
438
- */
439
- onReply(): void {
440
- console.log('[Lightbox] Reply button clicked');
441
- if (this.onCloseRequested) {
442
- this.onCloseRequested();
443
- }
444
- }
445
-
446
- /**
447
- * Navigate to the next image
448
- */
449
- nextImage(): void {
450
- if (this.swiper && this.currentIndex() < this.images.length - 1) {
451
- this.swiper.slideNext();
452
- }
453
- }
454
-
455
- /**
456
- * Navigate to the previous image
457
- */
458
- previousImage(): void {
459
- if (this.swiper && this.currentIndex() > 0) {
460
- this.swiper.slidePrev();
461
- }
462
- }
463
-
464
- /**
465
- * Handle image load success
466
- */
467
- onImageLoad(index: number): void {
468
- if (index === this.currentIndex()) {
469
- this.isLoading.set(false);
470
- }
471
- }
472
-
473
- /**
474
- * Handle image load error
475
- */
476
- onImageError(index: number): void {
477
- if (index === this.currentIndex()) {
478
- console.error(`[Lightbox] Image ${index} failed to load`);
479
- this.isLoading.set(false);
480
- this.hasError.set(true);
481
- }
482
- }
483
- }
484
-