@propbinder/mobile-design 0.0.2 → 0.0.21

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 (123) hide show
  1. package/fesm2022/propbinder-mobile-design.mjs +12596 -0
  2. package/fesm2022/propbinder-mobile-design.mjs.map +1 -0
  3. package/index.d.ts +3214 -0
  4. package/package.json +39 -12
  5. package/ng-package.json +0 -7
  6. package/src/animations/page-transitions.ts +0 -86
  7. package/src/assets/fonts/Brockmann-Bold.otf +0 -0
  8. package/src/assets/fonts/Brockmann-BoldItalic.otf +0 -0
  9. package/src/assets/fonts/Brockmann-Medium.otf +0 -0
  10. package/src/assets/fonts/Brockmann-MediumItalic.otf +0 -0
  11. package/src/assets/fonts/Brockmann-Regular.otf +0 -0
  12. package/src/assets/fonts/Brockmann-RegularItalic.otf +0 -0
  13. package/src/assets/fonts/Brockmann-SemiBold.otf +0 -0
  14. package/src/assets/fonts/Brockmann-SemiBoldItalic.otf +0 -0
  15. package/src/assets/fonts/Brockmann_desktop_license.pdf +0 -0
  16. package/src/assets/fonts/brockmann-medium-webfont.woff2 +0 -0
  17. package/src/assets/fonts/brockmann-regular-webfont.woff2 +0 -0
  18. package/src/assets/fonts/brockmann-semibold-webfont.woff2 +0 -0
  19. package/src/components/action-list-item/ds-mobile-action-list-item.ts +0 -83
  20. package/src/components/action-list-item/index.ts +0 -2
  21. package/src/components/app-layout/ds-mobile-app-layout.css +0 -343
  22. package/src/components/app-layout/ds-mobile-app-layout.ts +0 -271
  23. package/src/components/app-layout/index.ts +0 -2
  24. package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +0 -130
  25. package/src/components/avatar-with-badge/index.ts +0 -2
  26. package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +0 -273
  27. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +0 -110
  28. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +0 -167
  29. package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +0 -656
  30. package/src/components/bottom-sheet/index.ts +0 -3
  31. package/src/components/comment/ds-mobile-comment.ts +0 -516
  32. package/src/components/comment/index.ts +0 -2
  33. package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +0 -182
  34. package/src/components/contact-list-item/index.ts +0 -2
  35. package/src/components/content/ds-mobile-content.ts +0 -158
  36. package/src/components/content/index.ts +0 -2
  37. package/src/components/ds-mobile-tabs.css +0 -372
  38. package/src/components/ds-mobile-tabs.ts +0 -217
  39. package/src/components/file-attachment/ds-mobile-file-attachment.ts +0 -164
  40. package/src/components/file-attachment/index.ts +0 -2
  41. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +0 -98
  42. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +0 -514
  43. package/src/components/handbook-detail-modal/index.ts +0 -3
  44. package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +0 -130
  45. package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +0 -444
  46. package/src/components/handbook-folder/index.ts +0 -4
  47. package/src/components/header-content/ds-mobile-header-content.ts +0 -211
  48. package/src/components/header-content/index.ts +0 -2
  49. package/src/components/index.ts +0 -45
  50. package/src/components/inline-photo/ds-mobile-inline-photo.ts +0 -269
  51. package/src/components/inline-photo/index.ts +0 -1
  52. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.css +0 -60
  53. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +0 -280
  54. package/src/components/interactive-list-item-inquiry/index.ts +0 -2
  55. package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +0 -197
  56. package/src/components/interactive-list-item-message/index.ts +0 -2
  57. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.css +0 -70
  58. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +0 -594
  59. package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +0 -124
  60. package/src/components/interactive-list-item-post/index.ts +0 -13
  61. package/src/components/lightbox/ds-mobile-lightbox-footer.ts +0 -331
  62. package/src/components/lightbox/ds-mobile-lightbox-header.ts +0 -173
  63. package/src/components/lightbox/ds-mobile-lightbox-image.ts +0 -464
  64. package/src/components/lightbox/ds-mobile-lightbox-pdf.css +0 -375
  65. package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +0 -374
  66. package/src/components/lightbox/ds-mobile-lightbox.css +0 -587
  67. package/src/components/lightbox/ds-mobile-lightbox.service.ts +0 -293
  68. package/src/components/lightbox/ds-mobile-lightbox.ts +0 -529
  69. package/src/components/lightbox/index.ts +0 -22
  70. package/src/components/list-item/ds-mobile-list-item.ts +0 -499
  71. package/src/components/list-item/index.ts +0 -2
  72. package/src/components/list-item-static/ds-mobile-list-item-static.ts +0 -133
  73. package/src/components/list-item-static/index.ts +0 -2
  74. package/src/components/logo/ds-logo.ts +0 -85
  75. package/src/components/logo/index.ts +0 -2
  76. package/src/components/modal/ds-mobile-modal.css +0 -163
  77. package/src/components/modal/ds-mobile-modal.service.ts +0 -329
  78. package/src/components/modal/index.ts +0 -8
  79. package/src/components/page-details/ds-mobile-page-details.css +0 -285
  80. package/src/components/page-details/ds-mobile-page-details.ts +0 -128
  81. package/src/components/page-details/index.ts +0 -2
  82. package/src/components/page-main/ds-mobile-page-main.css +0 -346
  83. package/src/components/page-main/ds-mobile-page-main.ts +0 -331
  84. package/src/components/page-main/index.ts +0 -2
  85. package/src/components/post-card/ds-mobile-post-card.ts +0 -685
  86. package/src/components/post-card/ds-mobile-post-pdf-attachment.ts +0 -124
  87. package/src/components/post-card/index.ts +0 -11
  88. package/src/components/post-composer/ds-mobile-post-composer.ts +0 -140
  89. package/src/components/post-composer/index.ts +0 -2
  90. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +0 -104
  91. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +0 -1273
  92. package/src/components/post-detail-modal/index.ts +0 -9
  93. package/src/components/shared/directives/index.ts +0 -2
  94. package/src/components/shared/directives/long-press.directive.ts +0 -208
  95. package/src/components/shared/index.ts +0 -3
  96. package/src/components/shared/mobile-common.css +0 -94
  97. package/src/components/shared/mobile-page-base.css +0 -315
  98. package/src/components/shared/mobile-page-base.ts +0 -70
  99. package/src/components/swiper/ds-mobile-swiper.ts +0 -123
  100. package/src/components/swiper/index.ts +0 -2
  101. package/src/components/tab-bar/ds-mobile-tab-bar.ts +0 -132
  102. package/src/components/tab-bar/index.ts +0 -2
  103. package/src/components/tabs/ds-mobile-tabs.css +0 -405
  104. package/src/components/tabs/ds-mobile-tabs.ts +0 -204
  105. package/src/components/tabs/index.ts +0 -2
  106. package/src/pages/community.page.ts +0 -768
  107. package/src/pages/handbook.page.ts +0 -298
  108. package/src/pages/home.page.ts +0 -192
  109. package/src/pages/index.ts +0 -9
  110. package/src/pages/inquiries.example.ts +0 -212
  111. package/src/pages/inquiry-detail.example.css +0 -434
  112. package/src/pages/inquiry-detail.example.ts +0 -416
  113. package/src/pages/mobile-tabs-example.component.ts +0 -146
  114. package/src/pages/post-create.page.ts +0 -311
  115. package/src/pages/post-detail.page.ts +0 -295
  116. package/src/pages/whitelabel-demo.page.ts +0 -548
  117. package/src/public-api.ts +0 -5
  118. package/src/services/user.service.ts +0 -35
  119. package/src/services/whitelabel.service.ts +0 -171
  120. package/src/styles/ionic.css +0 -673
  121. package/tsconfig.lib.json +0 -17
  122. package/tsconfig.lib.prod.json +0 -9
  123. package/tsconfig.spec.json +0 -13
@@ -1,1273 +0,0 @@
1
- import {
2
- Component,
3
- signal,
4
- computed,
5
- CUSTOM_ELEMENTS_SCHEMA,
6
- Input,
7
- ViewChild,
8
- ElementRef,
9
- AfterViewInit,
10
- OnDestroy
11
- } from '@angular/core';
12
- import { CommonModule } from '@angular/common';
13
- import { FormsModule } from '@angular/forms';
14
- import {
15
- IonContent,
16
- ModalController
17
- } from '@ionic/angular/standalone';
18
- import { Keyboard } from '@capacitor/keyboard';
19
- import { DsIconButtonComponent } from '@propbinder/design-system';
20
- import { DsIconComponent } from '@propbinder/design-system';
21
- import { DsAvatarComponent } from '@propbinder/design-system';
22
- import {
23
- DsMobilePostCardComponent,
24
- PostContentComponent,
25
- PostTextComponent,
26
- PostMediaComponent,
27
- PostActionsComponent,
28
- ActionLikeComponent,
29
- ActionCommentComponent
30
- } from '../post-card/ds-mobile-post-card';
31
- import { DsMobileCommentComponent } from '../comment/ds-mobile-comment';
32
- import { DsMobileLightboxService, LightboxAuthor } from '../lightbox';
33
- import {
34
- DsMobileBottomSheetService,
35
- DsMobileCommentActionsBottomSheetComponent,
36
- CommentActionResult
37
- } from '../bottom-sheet';
38
-
39
- /**
40
- * Post data interface for the modal
41
- */
42
- export interface PostDetailData {
43
- postId: string;
44
- authorName: string;
45
- authorRole: string;
46
- timestamp: string;
47
- avatarInitials?: string;
48
- avatarType?: 'photo' | 'initials';
49
- avatarSrc?: string;
50
- content: string;
51
- imageSrc?: string;
52
- imageAlt?: string;
53
- isLiked?: boolean;
54
- likeCount?: number;
55
- commentCount?: number;
56
- comments?: CommentData[];
57
- focusComment?: boolean; // Auto-focus comment input when modal opens
58
- }
59
-
60
- export interface CommentData {
61
- authorName: string;
62
- authorRole: string;
63
- timestamp: string;
64
- avatarInitials: string;
65
- content: string;
66
- isLiked?: boolean;
67
- likeCount?: number;
68
- isOwnComment?: boolean;
69
- }
70
-
71
- /**
72
- * DsMobilePostDetailModalComponent
73
- *
74
- * Modal wrapper for displaying post details with comments.
75
- * Follows the same pattern as the lightbox modal for consistent behavior.
76
- *
77
- * Features:
78
- * - Full post content display
79
- * - Comments section
80
- * - Image lightbox integration
81
- * - Native modal controls (close, swipe down)
82
- * - Safe area support
83
- *
84
- * This component is typically not used directly - use DsMobilePostDetailModalService instead.
85
- *
86
- * @example
87
- * ```typescript
88
- * // Don't instantiate directly - use the service:
89
- * constructor(private postModal: DsMobilePostDetailModalService) {}
90
- *
91
- * openPost() {
92
- * this.postModal.open({
93
- * postId: '123',
94
- * authorName: 'John Doe',
95
- * content: 'Post content...'
96
- * });
97
- * }
98
- * ```
99
- */
100
- @Component({
101
- selector: 'ds-mobile-post-detail-modal',
102
- standalone: true,
103
- imports: [
104
- CommonModule,
105
- FormsModule,
106
- IonContent,
107
- DsIconButtonComponent,
108
- DsIconComponent,
109
- DsAvatarComponent,
110
- PostTextComponent,
111
- PostMediaComponent,
112
- ActionLikeComponent,
113
- ActionCommentComponent,
114
- DsMobileCommentComponent
115
- ],
116
- styleUrls: ['../shared/mobile-common.css'],
117
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
118
- template: `
119
- <ion-content [fullscreen]="true" [scrollY]="true" class="post-modal-content">
120
- <div class="post-modal-wrapper">
121
- <!-- Header with post author info -->
122
- <div class="post-modal-header">
123
- <div class="header-content">
124
- <!-- Post author info -->
125
- <div class="post-author-info">
126
- <ds-avatar
127
- [initials]="post().avatarInitials || ''"
128
- [type]="post().avatarType || 'initials'"
129
- [src]="post().avatarSrc || ''"
130
- size="md"
131
- />
132
- <div class="author-details">
133
- <div class="author-name">{{ post().authorName }}</div>
134
- <div class="author-meta">
135
- <span>{{ post().authorRole }}</span>
136
- <span class="separator">·</span>
137
- <span>{{ post().timestamp }}</span>
138
- </div>
139
- </div>
140
- </div>
141
-
142
- <!-- Close button -->
143
- <ds-icon-button
144
- icon="remixCloseLine"
145
- variant="secondary"
146
- size="lg"
147
- (click)="close()"
148
- class="close-button"
149
- aria-label="Luk opslag">
150
- </ds-icon-button>
151
- </div>
152
- </div>
153
-
154
- <!-- Post content -->
155
- <div class="post-detail-container">
156
- <!-- Post Section -->
157
- <div class="post-section">
158
- <div class="post-content-only">
159
- <post-text>{{ post().content }}</post-text>
160
- @if (post().imageSrc) {
161
- <post-media>
162
- <img
163
- [src]="post().imageSrc"
164
- [alt]="post().imageAlt || 'Post image'"
165
- class="clickable-image"
166
- (click)="openImageLightbox()"
167
- />
168
- </post-media>
169
- }
170
- </div>
171
-
172
- <!-- Post actions -->
173
- <div class="post-actions">
174
- <action-like
175
- [active]="post().isLiked || false"
176
- [count]="post().likeCount || 0" />
177
- <action-comment
178
- [count]="post().commentCount || 0"
179
- (commentClick)="focusCommentInput()" />
180
- </div>
181
- </div>
182
-
183
- <!-- Comments Section -->
184
- <div class="comments-section">
185
- @if (post().comments && post().comments!.length > 0) {
186
- <h2 class="comments-header">{{ post().comments!.length }} {{ post().comments!.length === 1 ? 'reply' : 'replies' }}</h2>
187
-
188
- <div class="comments-list">
189
- @for (comment of post().comments!; track comment.authorName + comment.timestamp) {
190
- <ds-mobile-comment
191
- [authorName]="comment.authorName"
192
- [authorRole]="comment.authorRole"
193
- [timestamp]="comment.timestamp"
194
- [avatarInitials]="comment.avatarInitials"
195
- [content]="comment.content"
196
- [isLiked]="comment.isLiked || false"
197
- [likeCount]="comment.likeCount || 0"
198
- [clickable]="true"
199
- [isOwnComment]="comment.isOwnComment || false"
200
- (replyClick)="handleReply(comment.authorName, comment.content)"
201
- (editClick)="handleEditComment(comment.authorName, comment.content, comment.timestamp)"
202
- (longPress)="handleCommentLongPress(comment.authorName, comment.content, comment.isOwnComment || false)" />
203
- }
204
- </div>
205
- } @else {
206
- <!-- Empty State -->
207
- <div class="comments-empty-state">
208
- <img
209
- src="/Assets/Empty state-chat.png"
210
- alt="Ingen kommentarer endnu"
211
- class="empty-state-image"
212
- />
213
- <h3 class="empty-state-title">Ingen svar endnu</h3>
214
- <p class="empty-state-description">Vær den første til at svare på dette opslag</p>
215
- </div>
216
- }
217
-
218
- <!-- Bottom spacer for fixed composer -->
219
- <div class="composer-spacer"></div>
220
- </div>
221
- </div>
222
- </div>
223
- </ion-content>
224
-
225
- <!-- Fixed comment composer -->
226
- <div class="comment-composer-fixed">
227
- <div class="comment-composer">
228
- <!-- Edit indicator -->
229
- @if (editingComment()) {
230
- <div class="edit-indicator">
231
- <div class="edit-indicator-content">
232
- <ds-icon name="remixEditLine" size="16px" />
233
- <span class="edit-text">Redigerer kommentar</span>
234
- </div>
235
- <button class="cancel-edit" (click)="cancelEdit()">
236
- <ds-icon name="remixCloseLine" size="16px" />
237
- </button>
238
- </div>
239
- } @else if (replyingTo()) {
240
- <!-- Reply indicator -->
241
- <div class="reply-indicator">
242
- <div class="reply-indicator-content">
243
- <ds-icon name="remixReplyLine" size="16px" />
244
- <span class="reply-to-text">
245
- Svarer til <span class="reply-author">{{ replyingTo()!.authorName }}</span>
246
- </span>
247
- </div>
248
- <button class="cancel-reply" (click)="cancelReply()">
249
- <ds-icon name="remixCloseLine" size="16px" />
250
- </button>
251
- </div>
252
- }
253
-
254
- <div class="composer-content">
255
- <ds-avatar
256
- [initials]="currentUserInitials()"
257
- [type]="'initials'"
258
- size="md"
259
- />
260
- <div class="composer-input-wrapper">
261
- <!-- Mention menu -->
262
- @if (showMentionMenu() && filteredUsers().length > 0 && !editingComment()) {
263
- <div class="mention-menu">
264
- @for (user of filteredUsers(); track user.name) {
265
- <button
266
- class="mention-menu-item"
267
- (click)="selectMention(user.name)">
268
- <ds-avatar
269
- [initials]="user.initials"
270
- [type]="'initials'"
271
- size="sm" />
272
- <div class="mention-user-info">
273
- <span class="mention-user-name">{{ user.name }}</span>
274
- <span class="mention-user-role">{{ user.role }}</span>
275
- </div>
276
- </button>
277
- }
278
- </div>
279
- }
280
-
281
- <textarea
282
- #commentInput
283
- class="composer-input"
284
- [placeholder]="editingComment() ? 'Rediger din kommentar...' : (replyingTo() ? 'Tilføj et svar...' : 'Tilføj et svar...')"
285
- [(ngModel)]="commentText"
286
- (input)="handleInput($event)"
287
- (focus)="showKeyboard()"
288
- (click)="showKeyboard()"
289
- rows="1"
290
- ></textarea>
291
- </div>
292
- @if (commentText().trim().length > 0) {
293
- <ds-icon-button
294
- icon="remixCheckLine"
295
- variant="primary"
296
- size="sm"
297
- (clicked)="submitComment()"
298
- aria-label="Send kommentar"
299
- class="send-button-fixed">
300
- </ds-icon-button>
301
- }
302
- </div>
303
- </div>
304
- </div>
305
- `,
306
- styles: [`
307
- :host {
308
- display: block;
309
- position: relative;
310
- height: 100%;
311
- width: 100%;
312
- }
313
-
314
- .post-modal-content {
315
- --background: var(--color-background-neutral-primary, #ffffff);
316
- }
317
-
318
- .post-modal-wrapper {
319
- display: flex;
320
- flex-direction: column;
321
- min-height: 100%;
322
- min-height: 100dvh; /* Use dynamic viewport height for proper iOS safe area handling */
323
- background: var(--color-background-neutral-primary, #ffffff);
324
- }
325
-
326
- .post-modal-header {
327
- position: sticky;
328
- top: 0;
329
- z-index: 10;
330
- background: var(--color-background-neutral-primary, #ffffff);
331
- border-bottom: 1px solid var(--border-color-default);
332
- padding: 0 16px;
333
- }
334
-
335
- .header-content {
336
- display: flex;
337
- align-items: center;
338
- justify-content: space-between;
339
- gap: 12px;
340
- min-height: 72px;
341
- /* No padding needed - StatusBar.setOverlaysWebView(false) handles all spacing */
342
- }
343
-
344
- .post-author-info {
345
- display: flex;
346
- align-items: center;
347
- gap: 12px;
348
- flex: 1;
349
- min-width: 0;
350
- }
351
-
352
- .author-details {
353
- display: flex;
354
- flex-direction: column;
355
- min-width: 0;
356
- flex: 1;
357
- }
358
-
359
- /* Author name and meta styles imported from mobile-common.css */
360
-
361
- .author-meta .separator {
362
- color: var(--color-text-tertiary, #a0a0a0);
363
- }
364
-
365
- .close-button {
366
- flex-shrink: 0;
367
- border-radius: 50%;
368
- }
369
-
370
- .close-button::ng-deep button {
371
- border-radius: 50% !important;
372
- width: 36px !important;
373
- height: 36px !important;
374
- min-width: 36px !important;
375
- min-height: 36px !important;
376
- padding: 0 !important;
377
- display: flex !important;
378
- align-items: center !important;
379
- justify-content: center !important;
380
- }
381
-
382
- .post-detail-container {
383
- display: flex;
384
- flex-direction: column;
385
- gap: 16px;
386
- width: 100%;
387
- max-width: 640px;
388
- margin: 0 auto;
389
- padding: 16px 0 20px 0;
390
- flex: 1;
391
- }
392
-
393
- .post-section {
394
- width: 100%;
395
- border-bottom: 1px solid var(--border-color-default);
396
- padding: 0 0 16px 0;
397
- }
398
-
399
- .post-content-only {
400
- font-size: var(--font-size-sm);
401
- line-height: 24px;
402
- color: var(--color-text-primary, #1a1a1a);
403
- margin-bottom: 16px;
404
- padding: 0 20px;
405
- }
406
-
407
- .post-content-only post-media {
408
- margin-top: 16px;
409
- }
410
-
411
- .post-actions {
412
- display: flex;
413
- align-items: center;
414
- gap: 16px;
415
- padding: 0 20px;
416
- }
417
-
418
- .clickable-image {
419
- cursor: pointer;
420
- transition: transform 0.2s ease, opacity 0.2s ease;
421
- border-radius: 8px;
422
- display: block;
423
- width: 100%;
424
- aspect-ratio: 16/9;
425
- object-fit: cover;
426
- }
427
-
428
- .clickable-image:active {
429
- transform: scale(0.98);
430
- opacity: 0.9;
431
- }
432
-
433
- .comments-section {
434
- display: flex;
435
- flex-direction: column;
436
- margin-left: 0;
437
- margin-right: 0;
438
- padding: 0 20px;
439
- padding-bottom: 0;
440
- }
441
-
442
- .comments-header {
443
- font-family: 'Brockmann', sans-serif;
444
- font-size: var(--font-size-base);
445
- font-weight: 600;
446
- line-height: 24px;
447
- color: var(--color-text-primary, #1a1a1a);
448
- margin: 0 0 16px 0;
449
- padding-left: 0;
450
- padding-right: 0;
451
- }
452
-
453
- .comments-list {
454
- display: flex;
455
- flex-direction: column;
456
- }
457
-
458
- /* Empty State */
459
- .comments-empty-state {
460
- display: flex;
461
- flex-direction: column;
462
- align-items: center;
463
- justify-content: center;
464
- padding: 60px 20px;
465
- text-align: center;
466
- }
467
-
468
- .empty-state-image {
469
- width: 96px;
470
- height: 96px;
471
- margin-bottom: 24px;
472
- }
473
-
474
- .empty-state-title {
475
- font-family: 'Brockmann', sans-serif;
476
- font-size: var(--font-size-base);
477
- font-weight: 600;
478
- line-height: 1.3;
479
- color: var(--color-text-primary, #1a1a1a);
480
- margin: 0 0 8px 0;
481
- }
482
-
483
- .empty-state-description {
484
- font-family: 'Brockmann', sans-serif;
485
- font-size: var(--font-size-sm);
486
- font-weight: 400;
487
- line-height: 1.4;
488
- color: var(--color-text-secondary, #737373);
489
- margin: 0;
490
- }
491
-
492
- .composer-spacer {
493
- /* Match full composer height:
494
- - Border: 1px
495
- - Top padding: 12px
496
- - Composer content: ~56px (avatar + input wrapper)
497
- - Bottom padding: 12px + safe area
498
- Total: ~81px + safe area */
499
- height: calc(81px + env(safe-area-inset-bottom, 0px));
500
- }
501
-
502
- .bottom-spacer {
503
- height: 0px;
504
- }
505
-
506
- /* Fixed Comment Composer Container */
507
- .comment-composer-fixed {
508
- position: fixed;
509
- bottom: 48px; /* Compensate for modal's margin-top: 48px */
510
- left: 0;
511
- right: 0;
512
- z-index: 1000;
513
- pointer-events: none;
514
- /* Slide up with keyboard on native apps */
515
- transform: translateY(calc(-1 * var(--keyboard-height, 0px)));
516
- transition: transform 0.3s ease-out;
517
- /* Ensure it's within the modal viewport */
518
- max-width: 100vw;
519
- }
520
-
521
- /* Comment Composer */
522
- .comment-composer {
523
- pointer-events: auto;
524
- background: var(--color-background-neutral-primary, #ffffff);
525
- border-top: 1px solid var(--border-color-default);
526
- padding: 12px 16px;
527
- /* Use dynamic viewport height safe area - matches tabs fix */
528
- /* For web browsers: 12px default; for native iOS: env(safe-area-inset-bottom) */
529
- padding-bottom: max(12px, env(safe-area-inset-bottom, 0px));
530
- width: 100%;
531
- display: flex;
532
- flex-direction: column;
533
- gap: 8px;
534
- /* White box shadow to cover content gap between keyboard and composer */
535
- box-shadow: 100px 150px 0 150px var(--color-background-neutral-primary, #ffffff);
536
- }
537
-
538
- /* Edit indicator */
539
- .edit-indicator {
540
- display: flex;
541
- align-items: center;
542
- justify-content: space-between;
543
- padding: 8px 12px;
544
- background: var(--color-background-brand-subtle, #f0edfe);
545
- border-radius: 8px;
546
- animation: slideDown 0.2s ease-out;
547
- }
548
-
549
- .edit-indicator-content {
550
- display: flex;
551
- align-items: center;
552
- gap: 8px;
553
- color: var(--color-brand-base, #6B5FF5);
554
- flex: 1;
555
- min-width: 0;
556
- }
557
-
558
- .edit-text {
559
- font-family: 'Brockmann', sans-serif;
560
- font-size: var(--font-size-sm);
561
- font-weight: 500;
562
- line-height: 18px;
563
- color: var(--color-brand-base, #6B5FF5);
564
- }
565
-
566
- .cancel-edit {
567
- background: none;
568
- border: none;
569
- padding: 4px;
570
- cursor: pointer;
571
- display: flex;
572
- align-items: center;
573
- justify-content: center;
574
- color: var(--color-brand-base, #6B5FF5);
575
- border-radius: 4px;
576
- transition: background 0.2s ease;
577
- flex-shrink: 0;
578
- }
579
-
580
- .cancel-edit:active {
581
- background: var(--color-brand-subtle, #e0dbfe);
582
- }
583
-
584
- /* Reply indicator */
585
- .reply-indicator {
586
- display: flex;
587
- align-items: center;
588
- justify-content: space-between;
589
- padding: 8px 12px;
590
- background: var(--color-background-neutral-secondary, #f5f5f5);
591
- border-radius: 8px;
592
- animation: slideDown 0.2s ease-out;
593
- }
594
-
595
- .reply-indicator-content {
596
- display: flex;
597
- align-items: center;
598
- gap: 4px;
599
- color: var(--color-text-secondary, #737373);
600
- flex: 1;
601
- min-width: 0;
602
- }
603
-
604
- .reply-to-text {
605
- font-family: 'Brockmann', sans-serif;
606
- font-size: var(--font-size-sm);
607
- line-height: 18px;
608
- color: var(--color-text-secondary, #737373);
609
- white-space: nowrap;
610
- overflow: hidden;
611
- text-overflow: ellipsis;
612
- }
613
-
614
- .reply-author {
615
- color: var(--color-brand-base, #6B5FF5);
616
- font-weight: 600;
617
- }
618
-
619
- .cancel-reply {
620
- background: none;
621
- border: none;
622
- padding: 4px;
623
- cursor: pointer;
624
- display: flex;
625
- align-items: center;
626
- justify-content: center;
627
- color: var(--color-text-secondary, #737373);
628
- border-radius: 4px;
629
- transition: background 0.2s ease;
630
- flex-shrink: 0;
631
- }
632
-
633
- .cancel-reply:active {
634
- background: var(--color-background-neutral-secondary, #f5f5f5);
635
- }
636
-
637
- @keyframes slideDown {
638
- from {
639
- opacity: 0;
640
- transform: translateY(-10px);
641
- }
642
- to {
643
- opacity: 1;
644
- transform: translateY(0);
645
- }
646
- }
647
-
648
- .composer-content {
649
- display: flex;
650
- align-items: flex-start;
651
- gap: 12px;
652
- width: 100%;
653
- position: relative;
654
- }
655
-
656
- .composer-content ds-avatar {
657
- position: relative;
658
- top: 6px;
659
- }
660
-
661
- .composer-input-wrapper {
662
- flex: 1;
663
- display: flex;
664
- align-items: flex-start;
665
- gap: 8px;
666
- background: var(--color-background-neutral-secondary, #f5f5f5);
667
- border-radius: 24px;
668
- padding: 12px 16px;
669
- padding-right: 48px; /* Extra padding for fixed send button */
670
- min-height: 44px;
671
- position: relative;
672
- }
673
-
674
- /* Mention menu */
675
- .mention-menu {
676
- position: absolute;
677
- bottom: 100%;
678
- left: 0;
679
- right: 0;
680
- background: var(--color-background-neutral-primary, #ffffff);
681
- border-radius: 12px;
682
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
683
- margin-bottom: 8px;
684
- max-height: 200px;
685
- overflow-y: auto;
686
- z-index: 10;
687
- animation: slideUp 0.2s ease-out;
688
- }
689
-
690
- @keyframes slideUp {
691
- from {
692
- opacity: 0;
693
- transform: translateY(10px);
694
- }
695
- to {
696
- opacity: 1;
697
- transform: translateY(0);
698
- }
699
- }
700
-
701
- .mention-menu-item {
702
- display: flex;
703
- align-items: center;
704
- gap: 12px;
705
- padding: 12px;
706
- border: none;
707
- background: none;
708
- width: 100%;
709
- text-align: left;
710
- cursor: pointer;
711
- transition: background 0.2s ease;
712
- border-bottom: 1px solid var(--border-color-default);
713
- }
714
-
715
- .mention-menu-item:last-child {
716
- border-bottom: none;
717
- }
718
-
719
- .mention-menu-item:active {
720
- background: var(--color-background-neutral-secondary, #f5f5f5);
721
- }
722
-
723
- .mention-user-info {
724
- display: flex;
725
- align-items: center;
726
- gap: 8px;
727
- flex: 1;
728
- min-width: 0;
729
- }
730
-
731
- .mention-user-name {
732
- font-family: 'Brockmann', sans-serif;
733
- font-size: var(--font-size-base);
734
- font-weight: 600;
735
- line-height: 20px;
736
- color: var(--color-text-primary, #1a1a1a);
737
- }
738
-
739
- .mention-user-role {
740
- font-family: 'Brockmann', sans-serif;
741
- font-size: var(--font-size-sm);
742
- line-height: 18px;
743
- color: var(--color-text-secondary, #737373);
744
- }
745
-
746
- .composer-input {
747
- flex: 1;
748
- border: none;
749
- background: transparent;
750
- font-family: 'Brockmann', sans-serif;
751
- font-size: var(--font-size-sm);
752
- line-height: 20px;
753
- color: var(--color-text-primary, #1a1a1a);
754
- outline: none;
755
- resize: none;
756
- min-height: 20px;
757
- max-height: 120px;
758
- overflow-y: auto;
759
- padding: 0;
760
- margin: 0;
761
- }
762
-
763
- .composer-input::placeholder {
764
- color: var(--color-text-tertiary, #a0a0a0);
765
- font-size: var(--font-size-sm);
766
- }
767
-
768
- /* Style the send button (ds-icon-button) - positioned in top right corner */
769
- .send-button-fixed {
770
- position: absolute;
771
- top: 6px;
772
- right: 6px;
773
- z-index: 10;
774
- flex-shrink: 0;
775
- animation: slideInFromRight 0.2s ease-out;
776
- }
777
-
778
- .send-button-fixed::ng-deep button {
779
- width: 32px !important;
780
- height: 32px !important;
781
- min-width: 32px !important;
782
- min-height: 32px !important;
783
- padding: 0 !important;
784
- border-radius: 50% !important;
785
- }
786
-
787
- /* Keep old style for reference but won't be used */
788
- .composer-input-wrapper ds-icon-button {
789
- flex-shrink: 0;
790
- animation: slideInFromRight 0.2s ease-out;
791
- }
792
-
793
- .composer-input-wrapper ds-icon-button::ng-deep button {
794
- width: 32px !important;
795
- height: 32px !important;
796
- min-width: 32px !important;
797
- min-height: 32px !important;
798
- padding: 0 !important;
799
- border-radius: 50% !important;
800
- }
801
-
802
- /* Slide in animation from right */
803
- @keyframes slideInFromRight {
804
- from {
805
- opacity: 0;
806
- transform: translateX(20px) scale(0.8);
807
- }
808
- to {
809
- opacity: 1;
810
- transform: translateX(0) scale(1);
811
- }
812
- }
813
-
814
- /* Safe area support */
815
- @supports (padding: env(safe-area-inset-bottom)) {
816
- .post-detail-container {
817
- padding-bottom: calc(20px + env(safe-area-inset-bottom));
818
- }
819
- }
820
- `]
821
- })
822
- export class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestroy {
823
- // Post data passed from service
824
- @Input() postData!: PostDetailData;
825
-
826
- // ViewChild for comment input
827
- @ViewChild('commentInput') commentInput?: ElementRef<HTMLTextAreaElement>;
828
-
829
- // Signal for reactive post data
830
- post = signal<PostDetailData>({
831
- postId: '',
832
- authorName: '',
833
- authorRole: '',
834
- timestamp: '',
835
- content: '',
836
- comments: []
837
- });
838
-
839
- // Comment composer state
840
- commentText = signal('');
841
- currentUserInitials = signal('LM');
842
- replyingTo = signal<{ authorName: string; content: string } | null>(null);
843
- editingComment = signal<{ authorName: string; originalContent: string; timestamp: string } | null>(null);
844
-
845
- // Mention menu state
846
- showMentionMenu = signal(false);
847
- mentionQuery = signal('');
848
-
849
- // Get available users to mention (post author + commenters)
850
- availableUsers = computed(() => {
851
- const post = this.post();
852
- const users: Array<{ name: string; initials: string; role: string }> = [];
853
-
854
- // Add post author
855
- users.push({
856
- name: post.authorName,
857
- initials: post.avatarInitials || post.authorName.split(' ').map(n => n[0]).join(''),
858
- role: post.authorRole
859
- });
860
-
861
- // Add unique commenters
862
- const commenterNames = new Set<string>();
863
- post.comments?.forEach(comment => {
864
- if (!commenterNames.has(comment.authorName)) {
865
- commenterNames.add(comment.authorName);
866
- users.push({
867
- name: comment.authorName,
868
- initials: comment.avatarInitials,
869
- role: comment.authorRole
870
- });
871
- }
872
- });
873
-
874
- return users;
875
- });
876
-
877
- // Filtered users based on mention query
878
- filteredUsers = computed(() => {
879
- const query = this.mentionQuery().toLowerCase();
880
- if (!query) return this.availableUsers();
881
- return this.availableUsers().filter(user =>
882
- user.name.toLowerCase().includes(query)
883
- );
884
- });
885
-
886
- constructor(
887
- private modalController: ModalController,
888
- private lightbox: DsMobileLightboxService,
889
- private bottomSheet: DsMobileBottomSheetService
890
- ) {}
891
-
892
- ngOnInit(): void {
893
- // Initialize post data from input
894
- if (this.postData) {
895
- this.post.set(this.postData);
896
- }
897
-
898
- // Set up keyboard listeners to update CSS variable for composer positioning
899
- this.setupKeyboardListeners();
900
- }
901
-
902
- ngAfterViewInit(): void {
903
- // Auto-focus comment input if requested
904
- if (this.postData?.focusComment) {
905
- // Small delay to ensure modal animation is complete
906
- setTimeout(() => {
907
- this.commentInput?.nativeElement.focus();
908
- // Show keyboard on mobile
909
- this.showKeyboard();
910
- }, 300);
911
- }
912
- }
913
-
914
- ngOnDestroy(): void {
915
- // Clean up keyboard listeners when modal is destroyed
916
- this.cleanupKeyboardListeners();
917
- }
918
-
919
- /**
920
- * Set up keyboard event listeners to adjust composer position
921
- * The CSS uses --keyboard-height variable to translate the composer up
922
- */
923
- private setupKeyboardListeners(): void {
924
- Keyboard.addListener('keyboardWillShow', (info) => {
925
- document.documentElement.style.setProperty('--keyboard-height', `${info.keyboardHeight}px`);
926
- }).catch(e => console.log('Keyboard listeners not available:', e));
927
-
928
- Keyboard.addListener('keyboardWillHide', () => {
929
- document.documentElement.style.setProperty('--keyboard-height', '0px');
930
- }).catch(e => console.log('Keyboard listeners not available:', e));
931
- }
932
-
933
- /**
934
- * Clean up keyboard event listeners
935
- */
936
- private cleanupKeyboardListeners(): void {
937
- Keyboard.removeAllListeners().catch(e => console.log('Keyboard cleanup not available:', e));
938
- }
939
-
940
- /**
941
- * Show the keyboard when user interacts with input
942
- */
943
- showKeyboard(): void {
944
- Keyboard.show().catch(e => console.log('Keyboard.show() not available'));
945
- }
946
-
947
- /**
948
- * Focus the comment input when comment icon is tapped
949
- */
950
- focusCommentInput(): void {
951
- // Focus the input
952
- this.commentInput?.nativeElement.focus();
953
- // Show keyboard on mobile
954
- this.showKeyboard();
955
- }
956
-
957
- /**
958
- * Handle input changes and detect @ mentions
959
- */
960
- handleInput(event: Event): void {
961
- const textarea = event.target as HTMLTextAreaElement;
962
- const text = textarea.value;
963
- const cursorPosition = textarea.selectionStart || 0;
964
-
965
- // Auto-resize textarea
966
- textarea.style.height = 'auto';
967
- textarea.style.height = textarea.scrollHeight + 'px';
968
-
969
- // Find the last @ before cursor
970
- const textBeforeCursor = text.substring(0, cursorPosition);
971
- const lastAtIndex = textBeforeCursor.lastIndexOf('@');
972
-
973
- if (lastAtIndex !== -1) {
974
- // Check if there's a space after @
975
- const textAfterAt = textBeforeCursor.substring(lastAtIndex + 1);
976
- const hasSpace = textAfterAt.includes(' ');
977
-
978
- if (!hasSpace) {
979
- // Show mention menu
980
- this.showMentionMenu.set(true);
981
- this.mentionQuery.set(textAfterAt);
982
- } else {
983
- this.showMentionMenu.set(false);
984
- }
985
- } else {
986
- this.showMentionMenu.set(false);
987
- }
988
- }
989
-
990
- /**
991
- * Select a user from mention menu - show as reply indicator instead of inline mention
992
- */
993
- selectMention(userName: string): void {
994
- // Set as reply (similar to clicking Reply on a comment)
995
- this.replyingTo.set({ authorName: userName, content: '' });
996
-
997
- // Clear the @ from the input
998
- const currentText = this.commentText();
999
- const textWithoutMention = currentText.substring(0, currentText.lastIndexOf('@'));
1000
- this.commentText.set(textWithoutMention);
1001
-
1002
- // Hide mention menu
1003
- this.showMentionMenu.set(false);
1004
-
1005
- // Focus back on input
1006
- setTimeout(() => {
1007
- this.commentInput?.nativeElement.focus();
1008
- }, 0);
1009
- }
1010
-
1011
- /**
1012
- * Handle reply to a comment
1013
- */
1014
- handleReply(authorName: string, content: string): void {
1015
- this.replyingTo.set({ authorName, content });
1016
- // Focus the input and show keyboard
1017
- setTimeout(() => {
1018
- this.commentInput?.nativeElement.focus();
1019
- this.showKeyboard();
1020
- }, 100);
1021
- }
1022
-
1023
- /**
1024
- * Cancel reply
1025
- */
1026
- cancelReply(): void {
1027
- this.replyingTo.set(null);
1028
- }
1029
-
1030
- /**
1031
- * Cancel edit
1032
- */
1033
- cancelEdit(): void {
1034
- this.editingComment.set(null);
1035
- this.commentText.set('');
1036
- }
1037
-
1038
- /**
1039
- * Handle edit comment
1040
- */
1041
- handleEditComment(authorName: string, originalContent: string, timestamp: string): void {
1042
- // Clear reply state if active
1043
- this.replyingTo.set(null);
1044
-
1045
- // Remove @mention from the content if it exists
1046
- let contentToEdit = originalContent;
1047
- const mentionMatch = originalContent.match(/^@([A-Za-z]+(?:\s+[A-Za-z]+)?)\s+/);
1048
- if (mentionMatch) {
1049
- contentToEdit = originalContent.substring(mentionMatch[0].length);
1050
- }
1051
-
1052
- // Set edit state
1053
- this.editingComment.set({ authorName, originalContent, timestamp });
1054
-
1055
- // Populate the input with existing content
1056
- this.commentText.set(contentToEdit);
1057
-
1058
- // Focus the input, show keyboard, and auto-resize
1059
- setTimeout(() => {
1060
- if (this.commentInput?.nativeElement) {
1061
- const textarea = this.commentInput.nativeElement;
1062
- textarea.focus();
1063
-
1064
- // Auto-resize textarea to fit content
1065
- textarea.style.height = 'auto';
1066
- textarea.style.height = textarea.scrollHeight + 'px';
1067
-
1068
- this.showKeyboard();
1069
- }
1070
- }, 100);
1071
- }
1072
-
1073
- /**
1074
- * Close the modal
1075
- */
1076
- close(): void {
1077
- this.modalController.dismiss();
1078
- }
1079
-
1080
- /**
1081
- * Submit a comment
1082
- */
1083
- submitComment(): void {
1084
- const text = this.commentText().trim();
1085
- if (!text) return;
1086
-
1087
- const currentPost = this.post();
1088
-
1089
- // Check if we're editing an existing comment
1090
- if (this.editingComment()) {
1091
- console.log('[PostDetailModal] Updating comment:', text);
1092
-
1093
- const editing = this.editingComment()!;
1094
-
1095
- // Update the existing comment
1096
- const updatedComments = currentPost.comments?.map(comment => {
1097
- if (comment.authorName === editing.authorName &&
1098
- comment.content === editing.originalContent &&
1099
- comment.timestamp === editing.timestamp) {
1100
- return {
1101
- ...comment,
1102
- content: text,
1103
- timestamp: 'Just now (edited)'
1104
- };
1105
- }
1106
- return comment;
1107
- });
1108
-
1109
- this.post.set({
1110
- ...currentPost,
1111
- comments: updatedComments
1112
- });
1113
-
1114
- // Clear edit state
1115
- this.editingComment.set(null);
1116
- } else {
1117
- // Create new comment
1118
- console.log('[PostDetailModal] Submitting comment:', text);
1119
-
1120
- const newComment: CommentData = {
1121
- authorName: 'Lars Mikkelsen',
1122
- authorRole: 'You',
1123
- timestamp: 'Just now',
1124
- avatarInitials: this.currentUserInitials(),
1125
- content: this.replyingTo()
1126
- ? `@${this.replyingTo()!.authorName} ${text}`
1127
- : text,
1128
- isLiked: false,
1129
- likeCount: 0,
1130
- isOwnComment: true
1131
- };
1132
-
1133
- // Add comment to the list
1134
- const updatedComments = [...(currentPost.comments || []), newComment];
1135
-
1136
- this.post.set({
1137
- ...currentPost,
1138
- comments: updatedComments,
1139
- commentCount: updatedComments.length
1140
- });
1141
-
1142
- // Clear reply state
1143
- this.replyingTo.set(null);
1144
- }
1145
-
1146
- // Clear the input
1147
- this.commentText.set('');
1148
- this.showMentionMenu.set(false);
1149
-
1150
- // Reset textarea height to initial state
1151
- if (this.commentInput?.nativeElement) {
1152
- this.commentInput.nativeElement.style.height = 'auto';
1153
- }
1154
-
1155
- // Blur the input to hide the keyboard
1156
- this.commentInput?.nativeElement.blur();
1157
-
1158
- // Hide keyboard explicitly
1159
- Keyboard.hide().catch(e => console.log('Keyboard.hide() not available'));
1160
-
1161
- // In a real app, you would also send this to your backend
1162
- // this.commentService.addComment(currentPost.postId, text);
1163
- }
1164
-
1165
- /**
1166
- * Open image in lightbox
1167
- */
1168
- openImageLightbox(): void {
1169
- const postData = this.post();
1170
-
1171
- if (!postData.imageSrc) return;
1172
-
1173
- const authorMeta: LightboxAuthor = {
1174
- name: postData.authorName,
1175
- role: postData.authorRole,
1176
- avatarInitials: postData.avatarInitials || '',
1177
- avatarType: postData.avatarType || 'initials',
1178
- avatarSrc: postData.avatarSrc || '',
1179
- timestamp: postData.timestamp
1180
- };
1181
-
1182
- this.lightbox.open({
1183
- images: [
1184
- {
1185
- type: 'image',
1186
- src: postData.imageSrc,
1187
- alt: postData.imageAlt || 'Post image',
1188
- title: postData.imageAlt || '',
1189
- description: postData.content,
1190
- isLiked: postData.isLiked || false,
1191
- likeCount: postData.likeCount || 0,
1192
- commentCount: postData.commentCount || 0
1193
- }
1194
- ],
1195
- author: authorMeta,
1196
- enableZoom: true,
1197
- showControls: false,
1198
- showInfo: true
1199
- });
1200
- }
1201
-
1202
- /**
1203
- * Handle long press on a comment to show action sheet
1204
- */
1205
- async handleCommentLongPress(authorName: string, content: string, isOwnComment: boolean): Promise<void> {
1206
- const sheet = await this.bottomSheet.create({
1207
- component: DsMobileCommentActionsBottomSheetComponent,
1208
- componentProps: {
1209
- isOwnContent: isOwnComment
1210
- },
1211
- breakpoints: [0, 1],
1212
- initialBreakpoint: 1,
1213
- handle: true,
1214
- backdropDismiss: true,
1215
- cssClass: 'auto-height'
1216
- });
1217
-
1218
- const result = await sheet.onWillDismiss();
1219
-
1220
- if (result.role === 'select' && result.data) {
1221
- const action = (result.data as CommentActionResult).action;
1222
- const currentPost = this.post();
1223
-
1224
- switch (action) {
1225
- case 'like':
1226
- console.log('Like comment by', authorName);
1227
- // Find and toggle like on the comment
1228
- const updatedComments = currentPost.comments?.map(comment => {
1229
- if (comment.authorName === authorName && comment.content === content) {
1230
- const isLiked = !comment.isLiked;
1231
- return {
1232
- ...comment,
1233
- isLiked,
1234
- likeCount: isLiked ? (comment.likeCount || 0) + 1 : Math.max(0, (comment.likeCount || 0) - 1)
1235
- };
1236
- }
1237
- return comment;
1238
- });
1239
- this.post.set({ ...currentPost, comments: updatedComments });
1240
- break;
1241
- case 'reply':
1242
- console.log('Reply to comment by', authorName);
1243
- this.handleReply(authorName, content);
1244
- break;
1245
- case 'edit':
1246
- console.log('Edit comment by', authorName);
1247
- // Find the full comment data to get timestamp
1248
- const commentToEdit = currentPost.comments?.find(
1249
- comment => comment.authorName === authorName && comment.content === content
1250
- );
1251
- if (commentToEdit) {
1252
- this.handleEditComment(authorName, content, commentToEdit.timestamp);
1253
- }
1254
- break;
1255
- case 'delete':
1256
- console.log('Delete comment by', authorName);
1257
- // Show confirmation before deleting
1258
- if (confirm('Are you sure you want to delete this comment?')) {
1259
- const updatedCommentsAfterDelete = currentPost.comments?.filter(
1260
- comment => !(comment.authorName === authorName && comment.content === content)
1261
- );
1262
- this.post.set({
1263
- ...currentPost,
1264
- comments: updatedCommentsAfterDelete,
1265
- commentCount: updatedCommentsAfterDelete?.length || 0
1266
- });
1267
- }
1268
- break;
1269
- }
1270
- }
1271
- }
1272
- }
1273
-