@propbinder/mobile-design 0.2.48 → 0.2.50

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/ng-package.json +24 -0
  2. package/package.json +3 -39
  3. package/src/animations/page-transitions.ts +165 -0
  4. package/src/assets/fonts/brockmann-mediumitalic-webfont.woff2 +0 -0
  5. package/src/assets/fonts/brockmann-regularitalic-webfont.woff2 +0 -0
  6. package/src/assets/fonts/brockmann-semibolditalic-webfont.woff2 +0 -0
  7. package/src/components/action-list-item/ds-mobile-action-list-item.ts +102 -0
  8. package/src/components/action-list-item/index.ts +2 -0
  9. package/src/components/app-icon/ds-app-icon.ts +133 -0
  10. package/src/components/app-icon/index.ts +2 -0
  11. package/src/components/attachment-preview/ds-mobile-attachment-preview.css +139 -0
  12. package/src/components/attachment-preview/ds-mobile-attachment-preview.ts +164 -0
  13. package/src/components/attachment-preview/index.ts +1 -0
  14. package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +142 -0
  15. package/src/components/avatar-with-badge/index.ts +2 -0
  16. package/src/components/booking-modal/ds-mobile-booking-confirmation-wrapper.ts +71 -0
  17. package/src/components/booking-modal/ds-mobile-booking-modal.service.ts +121 -0
  18. package/src/components/booking-modal/ds-mobile-booking-modal.ts +598 -0
  19. package/src/components/booking-modal/ds-mobile-booking-summary.ts +161 -0
  20. package/src/components/booking-modal/index.ts +4 -0
  21. package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +266 -0
  22. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-header.ts +146 -0
  23. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-wrapper.ts +156 -0
  24. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +101 -0
  25. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +169 -0
  26. package/src/components/bottom-sheet/ds-mobile-confirmation-sheet.ts +211 -0
  27. package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +578 -0
  28. package/src/components/bottom-sheet/ds-mobile-profile-actions-sheet.ts +614 -0
  29. package/src/components/bottom-sheet/index.ts +8 -0
  30. package/src/components/bottom-sheet/modal-shadow-fix.ts +42 -0
  31. package/src/components/card-inline/ds-mobile-card-inline.ts +301 -0
  32. package/src/components/card-inline/index.ts +2 -0
  33. package/src/components/card-inline-banner/ds-mobile-card-inline-banner.ts +118 -0
  34. package/src/components/card-inline-banner/index.ts +1 -0
  35. package/src/components/card-inline-contact/ds-mobile-card-inline-contact.ts +120 -0
  36. package/src/components/card-inline-contact/index.ts +1 -0
  37. package/src/components/card-inline-file/ds-mobile-card-inline-file.ts +141 -0
  38. package/src/components/card-inline-file/index.ts +1 -0
  39. package/src/components/chat-modal/ds-mobile-chat-modal.css +159 -0
  40. package/src/components/chat-modal/ds-mobile-chat-modal.service.ts +105 -0
  41. package/src/components/chat-modal/ds-mobile-chat-modal.ts +918 -0
  42. package/src/components/chat-modal/index.ts +8 -0
  43. package/src/components/comment/ds-mobile-comment.ts +568 -0
  44. package/src/components/comment/index.ts +2 -0
  45. package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +182 -0
  46. package/src/components/contact-list-item/index.ts +2 -0
  47. package/src/components/content/ds-mobile-content.ts +139 -0
  48. package/src/components/content/index.ts +2 -0
  49. package/src/components/dropdown/ds-mobile-dropdown.css +199 -0
  50. package/src/components/dropdown/ds-mobile-dropdown.ts +340 -0
  51. package/src/components/dropdown/index.ts +2 -0
  52. package/src/components/ds-mobile-tabs.css +407 -0
  53. package/src/components/ds-mobile-tabs.ts +216 -0
  54. package/src/components/empty-state/ds-mobile-empty-state.ts +120 -0
  55. package/src/components/empty-state/index.ts +2 -0
  56. package/src/components/fab/ds-mobile-fab.ts +315 -0
  57. package/src/components/fab/index.ts +1 -0
  58. package/src/components/facility-creation-modal/ds-mobile-facility-creation-confirmation-wrapper.ts +121 -0
  59. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.css +189 -0
  60. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.service.ts +135 -0
  61. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.ts +656 -0
  62. package/src/components/facility-creation-modal/index.ts +9 -0
  63. package/src/components/facility-creation-modal/sheets/ds-mobile-access-sheet.ts +105 -0
  64. package/src/components/facility-creation-modal/sheets/ds-mobile-price-sheet.ts +188 -0
  65. package/src/components/facility-creation-modal/sheets/ds-mobile-when-can-book-sheet.ts +460 -0
  66. package/src/components/facility-creation-modal/sheets/ds-mobile-who-can-book-sheet.ts +134 -0
  67. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.service.ts +69 -0
  68. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.ts +379 -0
  69. package/src/components/facility-detail-modal/index.ts +2 -0
  70. package/src/components/file-attachment/ds-mobile-file-attachment.ts +164 -0
  71. package/src/components/file-attachment/index.ts +2 -0
  72. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.css +214 -0
  73. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +84 -0
  74. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +424 -0
  75. package/src/components/handbook-detail-modal/index.ts +3 -0
  76. package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +175 -0
  77. package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +533 -0
  78. package/src/components/handbook-folder/index.ts +4 -0
  79. package/src/components/header-content/ds-mobile-header-content.ts +222 -0
  80. package/src/components/header-content/index.ts +2 -0
  81. package/src/components/illustration/ds-mobile-illustration.ts +124 -0
  82. package/src/components/illustration/index.ts +2 -0
  83. package/src/components/index.ts +124 -0
  84. package/src/components/inline-photo/ds-mobile-inline-photo.ts +361 -0
  85. package/src/components/inline-photo/index.ts +1 -0
  86. package/src/components/inline-tabs/ds-mobile-inline-tabs.ts +132 -0
  87. package/src/components/inline-tabs/index.ts +2 -0
  88. package/src/components/interactive-list-item-booking/ds-mobile-interactive-list-item-booking.ts +350 -0
  89. package/src/components/interactive-list-item-booking/index.ts +1 -0
  90. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +321 -0
  91. package/src/components/interactive-list-item-inquiry/index.ts +2 -0
  92. package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +237 -0
  93. package/src/components/interactive-list-item-message/index.ts +2 -0
  94. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +549 -0
  95. package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +124 -0
  96. package/src/components/interactive-list-item-post/index.ts +13 -0
  97. package/src/components/lightbox/ds-mobile-lightbox-footer.ts +315 -0
  98. package/src/components/lightbox/ds-mobile-lightbox-header.ts +202 -0
  99. package/src/components/lightbox/ds-mobile-lightbox-image.ts +484 -0
  100. package/src/components/lightbox/ds-mobile-lightbox-pdf.css +377 -0
  101. package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +374 -0
  102. package/src/components/lightbox/ds-mobile-lightbox.css +587 -0
  103. package/src/components/lightbox/ds-mobile-lightbox.service.ts +296 -0
  104. package/src/components/lightbox/ds-mobile-lightbox.ts +529 -0
  105. package/src/components/lightbox/index.ts +22 -0
  106. package/src/components/list-item/ds-mobile-list-item.ts +603 -0
  107. package/src/components/list-item/index.ts +2 -0
  108. package/src/components/list-item-static/ds-mobile-list-item-static.ts +133 -0
  109. package/src/components/list-item-static/index.ts +2 -0
  110. package/src/components/loader-overlay/ds-mobile-loader-overlay.css +49 -0
  111. package/src/components/loader-overlay/ds-mobile-loader-overlay.ts +77 -0
  112. package/src/components/loader-overlay/index.ts +1 -0
  113. package/src/components/logo/ds-logo.ts +95 -0
  114. package/src/components/logo/index.ts +2 -0
  115. package/src/components/message-bubble/ds-mobile-message-bubble.ts +633 -0
  116. package/src/components/message-bubble/index.ts +7 -0
  117. package/src/components/message-composer/ds-mobile-message-composer.ts +1146 -0
  118. package/src/components/message-composer/index.ts +7 -0
  119. package/src/components/modal/ds-mobile-modal.css +163 -0
  120. package/src/components/modal/ds-mobile-modal.service.ts +329 -0
  121. package/src/components/modal/index.ts +8 -0
  122. package/src/components/modal-base/ds-mobile-modal-base.css +378 -0
  123. package/src/components/modal-base/ds-mobile-modal-base.ts +261 -0
  124. package/src/components/modal-base/index.ts +2 -0
  125. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.css +112 -0
  126. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.service.ts +93 -0
  127. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.ts +442 -0
  128. package/src/components/new-inquiry-modal/index.ts +4 -0
  129. package/src/components/offline-banner/ds-mobile-offline-banner.ts +135 -0
  130. package/src/components/offline-banner/index.ts +1 -0
  131. package/src/components/page-details/ds-mobile-page-details.css +83 -0
  132. package/src/components/page-details/ds-mobile-page-details.ts +282 -0
  133. package/src/components/page-details/index.ts +2 -0
  134. package/src/components/page-main/ds-mobile-page-main.css +68 -0
  135. package/src/components/page-main/ds-mobile-page-main.ts +421 -0
  136. package/src/components/page-main/index.ts +2 -0
  137. package/src/components/post-composer/ds-mobile-post-composer.ts +140 -0
  138. package/src/components/post-composer/index.ts +2 -0
  139. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.css +390 -0
  140. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +108 -0
  141. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +722 -0
  142. package/src/components/post-detail-modal/index.ts +9 -0
  143. package/src/components/property-banner/ds-mobile-property-banner.ts +95 -0
  144. package/src/components/property-banner/index.ts +2 -0
  145. package/src/components/section/ds-mobile-section.ts +263 -0
  146. package/src/components/section/index.ts +2 -0
  147. package/src/components/shared/directives/index.ts +2 -0
  148. package/src/components/shared/directives/long-press.directive.ts +212 -0
  149. package/src/components/shared/index.ts +3 -0
  150. package/src/components/shared/mobile-modal-base.ts +457 -0
  151. package/src/components/shared/mobile-page-base.ts +204 -0
  152. package/src/components/swiper/ds-mobile-swiper-with-nav.ts +160 -0
  153. package/src/components/swiper/ds-mobile-swiper.ts +327 -0
  154. package/src/components/swiper/index.ts +3 -0
  155. package/src/components/system-message-banner/ds-mobile-system-message-banner.ts +129 -0
  156. package/src/components/system-message-banner/index.ts +2 -0
  157. package/src/components/tab-bar/ds-mobile-tab-bar.css +533 -0
  158. package/src/components/tab-bar/ds-mobile-tab-bar.ts +735 -0
  159. package/src/components/tab-bar/index.ts +2 -0
  160. package/src/components/tabs/ds-mobile-tabs.css +25 -0
  161. package/src/components/tabs/ds-mobile-tabs.ts +89 -0
  162. package/src/components/tabs/index.ts +2 -0
  163. package/src/components/text-input/ds-text-input.ts +287 -0
  164. package/src/components/text-input/index.ts +2 -0
  165. package/src/examples/booking.page.ts +434 -0
  166. package/src/examples/community.page.ts +776 -0
  167. package/src/examples/handbook.page.ts +324 -0
  168. package/src/examples/home.page.ts +347 -0
  169. package/src/examples/index.ts +12 -0
  170. package/src/examples/inquiries.example.ts +273 -0
  171. package/src/examples/inquiry-detail.example.css +189 -0
  172. package/src/examples/inquiry-detail.example.ts +415 -0
  173. package/src/examples/mobile-tabs-example.component.ts +208 -0
  174. package/src/examples/post-create.page.ts +311 -0
  175. package/src/examples/post-detail.page.ts +296 -0
  176. package/src/examples/sign-in.page.ts +291 -0
  177. package/src/examples/whitelabel-demo-modal.component.ts +1094 -0
  178. package/src/examples/whitelabel-demo-modal.service.ts +77 -0
  179. package/src/models/index.ts +7 -0
  180. package/src/models/post.model.ts +41 -0
  181. package/src/pages/community.page.ts +769 -0
  182. package/src/pages/handbook.page.ts +388 -0
  183. package/src/pages/home.page.ts +303 -0
  184. package/src/pages/index.ts +11 -0
  185. package/src/pages/inquiries.example.ts +273 -0
  186. package/src/pages/inquiry-detail.example.css +189 -0
  187. package/src/pages/inquiry-detail.example.ts +415 -0
  188. package/src/pages/mobile-tabs-example.component.ts +179 -0
  189. package/src/pages/post-create.page.ts +311 -0
  190. package/src/pages/post-detail.page.ts +296 -0
  191. package/src/pages/sign-in.page.ts +291 -0
  192. package/src/pages/whitelabel-demo-modal.component.ts +1094 -0
  193. package/src/pages/whitelabel-demo-modal.service.ts +77 -0
  194. package/src/public-api.ts +6 -0
  195. package/src/services/base-modal.service.ts +101 -0
  196. package/src/services/index.ts +11 -0
  197. package/src/services/posts.service.ts +542 -0
  198. package/src/services/tracking-permission.service.ts +88 -0
  199. package/src/services/user.service.ts +60 -0
  200. package/src/services/whitelabel.service.ts +675 -0
  201. package/{styles → src/styles}/ionic.css +25 -0
  202. package/tsconfig.lib.json +17 -0
  203. package/tsconfig.lib.prod.json +9 -0
  204. package/tsconfig.spec.json +13 -0
  205. package/fesm2022/propbinder-mobile-design.mjs +0 -26168
  206. package/fesm2022/propbinder-mobile-design.mjs.map +0 -1
  207. package/index.d.ts +0 -8169
  208. /package/{assets → src/assets}/fonts/Brockmann-Bold.otf +0 -0
  209. /package/{assets → src/assets}/fonts/Brockmann-BoldItalic.otf +0 -0
  210. /package/{assets → src/assets}/fonts/Brockmann-Medium.otf +0 -0
  211. /package/{assets → src/assets}/fonts/Brockmann-MediumItalic.otf +0 -0
  212. /package/{assets → src/assets}/fonts/Brockmann-Regular.otf +0 -0
  213. /package/{assets → src/assets}/fonts/Brockmann-RegularItalic.otf +0 -0
  214. /package/{assets → src/assets}/fonts/Brockmann-SemiBold.otf +0 -0
  215. /package/{assets → src/assets}/fonts/Brockmann-SemiBoldItalic.otf +0 -0
  216. /package/{assets → src/assets}/fonts/Brockmann_desktop_license.pdf +0 -0
  217. /package/{assets → src/assets}/fonts/brockmann-medium-webfont.woff2 +0 -0
  218. /package/{assets → src/assets}/fonts/brockmann-regular-webfont.woff2 +0 -0
  219. /package/{assets → src/assets}/fonts/brockmann-semibold-webfont.woff2 +0 -0
  220. /package/{styles → src/components/shared}/mobile-common.css +0 -0
  221. /package/{styles → src/components/shared}/mobile-page-base.css +0 -0
@@ -0,0 +1,161 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { DsIconComponent } from '@propbinder/design-system';
4
+
5
+ /**
6
+ * DsMobileBookingSummaryComponent
7
+ *
8
+ * Displays a booking summary with facility info, thumbnail, date and time.
9
+ * Designed to be used within the generic confirmation sheet.
10
+ *
11
+ * @example
12
+ * ```html
13
+ * <ds-mobile-booking-summary
14
+ * [facilityTitle]="'Festlokale på taget'"
15
+ * [facilityThumbnail]="'/path/to/image.jpg'"
16
+ * [date]="'Tue 19 Nov'"
17
+ * [time]="'14:00 - 16:00'"
18
+ * />
19
+ * ```
20
+ */
21
+ @Component({
22
+ selector: 'ds-mobile-booking-summary',
23
+ standalone: true,
24
+ imports: [CommonModule, DsIconComponent],
25
+ styles: [`
26
+ .booking-summary {
27
+ width: 100%;
28
+ background: var(--color-background-neutral-secondary, #f5f5f5);
29
+ border-radius: 16px;
30
+ padding: 12px;
31
+ }
32
+
33
+ .summary-item {
34
+ display: flex;
35
+ gap: 12px;
36
+ align-items: flex-start;
37
+ }
38
+
39
+ .summary-thumbnail {
40
+ width: 48px;
41
+ height: 48px;
42
+ border-radius: 8px;
43
+ object-fit: cover;
44
+ flex-shrink: 0;
45
+ background: var(--color-background-neutral-tertiary, #e5e5e5);
46
+ }
47
+
48
+ .summary-thumbnail-placeholder {
49
+ width: 48px;
50
+ height: 48px;
51
+ border-radius: 8px;
52
+ flex-shrink: 0;
53
+ background: var(--color-background-neutral-tertiary, #e5e5e5);
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ }
58
+
59
+ .summary-details {
60
+ flex: 1;
61
+ display: flex;
62
+ flex-direction: column;
63
+ gap: 8px;
64
+ }
65
+
66
+ .summary-title {
67
+ font-family: 'Brockmann', sans-serif;
68
+ font-size: var(--font-size-base, 16px);
69
+ font-weight: 600;
70
+ color: var(--text-color-default-primary, #202227);
71
+ margin: 0;
72
+ }
73
+
74
+ .summary-datetime-container {
75
+ display: flex;
76
+ align-items: center;
77
+ gap: 12px;
78
+ flex-wrap: wrap;
79
+ }
80
+
81
+ .summary-datetime {
82
+ display: flex;
83
+ align-items: center;
84
+ gap: 6px;
85
+ }
86
+
87
+ .summary-datetime-text {
88
+ font-family: 'Brockmann', sans-serif;
89
+ font-size: var(--font-size-sm, 14px);
90
+ font-weight: 400;
91
+ color: var(--text-color-default-secondary, #71727a);
92
+ }
93
+
94
+ .summary-datetime ds-icon {
95
+ flex-shrink: 0;
96
+ }
97
+ `],
98
+ template: `
99
+ <div class="booking-summary">
100
+ <div class="summary-item">
101
+ @if (facilityThumbnail) {
102
+ <img
103
+ [src]="facilityThumbnail"
104
+ [alt]="facilityTitle"
105
+ class="summary-thumbnail" />
106
+ } @else {
107
+ <div class="summary-thumbnail-placeholder">
108
+ <ds-icon name="remixImageLine" size="24px" />
109
+ </div>
110
+ }
111
+
112
+ <div class="summary-details">
113
+ <h3 class="summary-title">{{ facilityTitle }}</h3>
114
+
115
+ <div class="summary-datetime-container">
116
+ @if (date) {
117
+ <div class="summary-datetime">
118
+ <ds-icon
119
+ name="remixCalendarLine"
120
+ size="16px"
121
+ color="var(--text-color-default-secondary, #71727a)" />
122
+ <span class="summary-datetime-text">{{ date }}</span>
123
+ </div>
124
+ }
125
+
126
+ @if (time) {
127
+ <div class="summary-datetime">
128
+ <ds-icon
129
+ name="remixTimeLine"
130
+ size="16px"
131
+ color="var(--text-color-default-secondary, #71727a)" />
132
+ <span class="summary-datetime-text">{{ time }}</span>
133
+ </div>
134
+ }
135
+ </div>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ `
140
+ })
141
+ export class DsMobileBookingSummaryComponent {
142
+ /**
143
+ * Facility title
144
+ */
145
+ @Input({ required: true }) facilityTitle!: string;
146
+
147
+ /**
148
+ * Optional facility thumbnail URL
149
+ */
150
+ @Input() facilityThumbnail?: string;
151
+
152
+ /**
153
+ * Formatted date string (e.g., "Tue 19 Nov")
154
+ */
155
+ @Input() date?: string;
156
+
157
+ /**
158
+ * Formatted time string (e.g., "14:00 - 16:00")
159
+ */
160
+ @Input() time?: string;
161
+ }
@@ -0,0 +1,4 @@
1
+ export * from './ds-mobile-booking-modal';
2
+ export * from './ds-mobile-booking-modal.service';
3
+ export * from './ds-mobile-booking-summary';
4
+ export * from './ds-mobile-booking-confirmation-wrapper';
@@ -0,0 +1,266 @@
1
+ import { Component, Input, computed, signal } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { ModalController } from '@ionic/angular/standalone';
4
+ import { DsIconComponent } from '@propbinder/design-system';
5
+ import { DsMobileActionListItemComponent } from '../action-list-item/ds-mobile-action-list-item';
6
+ import { DsMobileBottomSheetWrapperComponent } from './ds-mobile-bottom-sheet-wrapper';
7
+
8
+ export interface ActionResult {
9
+ action: string;
10
+ }
11
+
12
+ export interface ActionItem {
13
+ action: string;
14
+ title: string;
15
+ icon: string;
16
+ destructive?: boolean;
17
+ subtitle?: string; // Optional subtitle text (e.g., current language)
18
+ showChevron?: boolean; // Show chevron indicator for navigation
19
+ flagIcon?: string; // Optional flag icon path (e.g., for language selection)
20
+ }
21
+
22
+ export interface ActionGroup {
23
+ actions: ActionItem[];
24
+ }
25
+
26
+ /**
27
+ * DsMobileActionsBottomSheetComponent
28
+ *
29
+ * Generic bottom sheet for displaying action lists.
30
+ * Supports custom action groups or preset content actions (posts/comments).
31
+ * Action groups are automatically separated by full-width dividers.
32
+ *
33
+ * @example Custom actions with auto-height (recommended to avoid cropping)
34
+ * ```typescript
35
+ * const sheet = await this.modalController.create({
36
+ * component: DsMobileActionsBottomSheetComponent,
37
+ * componentProps: {
38
+ * customActionGroups: [
39
+ * {
40
+ * actions: [
41
+ * { action: 'profile', title: 'Min profil', icon: 'remixUser3Line' },
42
+ * { action: 'settings', title: 'Indstillinger', icon: 'remixSettings3Line' }
43
+ * ]
44
+ * },
45
+ * {
46
+ * actions: [
47
+ * { action: 'logout', title: 'Log ud', icon: 'remixLogoutBoxLine', destructive: true }
48
+ * ]
49
+ * }
50
+ * ]
51
+ * },
52
+ * breakpoints: [0, 1],
53
+ * initialBreakpoint: 1,
54
+ * handle: true,
55
+ * cssClass: 'auto-height'
56
+ * });
57
+ *
58
+ * const result = await sheet.onWillDismiss();
59
+ * if (result.data?.action) {
60
+ * // Handle the action
61
+ * }
62
+ * ```
63
+ *
64
+ * @example Preset content actions
65
+ * ```typescript
66
+ * const sheet = await this.modalController.create({
67
+ * component: DsMobileActionsBottomSheetComponent,
68
+ * componentProps: {
69
+ * isOwnContent: false
70
+ * },
71
+ * breakpoints: [0, 1],
72
+ * initialBreakpoint: 1,
73
+ * handle: true,
74
+ * cssClass: 'auto-height'
75
+ * });
76
+ * ```
77
+ */
78
+ @Component({
79
+ selector: 'ds-mobile-actions-bottom-sheet',
80
+ standalone: true,
81
+ imports: [CommonModule, DsIconComponent, DsMobileActionListItemComponent, DsMobileBottomSheetWrapperComponent],
82
+ template: `
83
+ <ds-mobile-bottom-sheet-wrapper>
84
+ <!-- Actions List -->
85
+ <div class="actions-list">
86
+ @for (group of actionGroups(); track $index; let isLast = $last) {
87
+ <!-- Action Group -->
88
+ <div class="action-group">
89
+ @for (actionItem of group.actions; track actionItem.action; let isLastInGroup = $last) {
90
+ <ds-mobile-action-list-item
91
+ [title]="actionItem.title"
92
+ [showDivider]="!isLastInGroup"
93
+ [class.destructive]="actionItem.destructive"
94
+ (itemClick)="selectAction(actionItem.action)"
95
+ >
96
+ <ds-icon action-icon [name]="actionItem.icon" size="20px" [class.destructive-icon]="actionItem.destructive" />
97
+ </ds-mobile-action-list-item>
98
+ }
99
+ </div>
100
+
101
+ <!-- Full-width divider between groups -->
102
+ @if (!isLast) {
103
+ <div class="action-group-divider"></div>
104
+ } }
105
+ </div>
106
+ </ds-mobile-bottom-sheet-wrapper>
107
+ `,
108
+ styles: [
109
+ `
110
+ :host {
111
+ display: block;
112
+ height: auto;
113
+ }
114
+
115
+ /* Actions List */
116
+ .actions-list {
117
+ display: flex;
118
+ flex-direction: column;
119
+ padding-top: 16px;
120
+ }
121
+
122
+ /* Action Group - padding on groups instead of list */
123
+ .action-group {
124
+ display: flex;
125
+ flex-direction: column;
126
+ padding: 0 16px; /* Horizontal padding on each group */
127
+ }
128
+
129
+ /* Override default background color to transparent so hover state is visible */
130
+ /* Need ::ng-deep because ds-mobile-list-item uses :host styles internally */
131
+ ::ng-deep ds-mobile-action-list-item ds-mobile-list-item {
132
+ --color-background-primary: transparent;
133
+ --color-background-neutral-primary-hover: var(--color-background-neutral-secondary, #f5f5f5);
134
+ }
135
+
136
+ /* Ensure the interactive background is visible */
137
+ ::ng-deep ds-mobile-action-list-item ds-mobile-list-item .list-item-inner::before {
138
+ z-index: 0 !important;
139
+ }
140
+
141
+ /* Ensure content is above the background */
142
+ ::ng-deep ds-mobile-action-list-item ds-mobile-list-item .content-leading,
143
+ ::ng-deep ds-mobile-action-list-item ds-mobile-list-item .content-main,
144
+ ::ng-deep ds-mobile-action-list-item ds-mobile-list-item .content-trailing {
145
+ position: relative;
146
+ z-index: 1;
147
+ }
148
+
149
+ /* Hide divider on last list item using CSS variable */
150
+ ds-mobile-action-list-item:last-of-type {
151
+ --divider-display: none;
152
+ }
153
+
154
+ /* Destructive action styling */
155
+ ds-mobile-action-list-item.destructive {
156
+ --text-color-default-primary: var(--color-error-base, #ef4444);
157
+ }
158
+
159
+ .destructive-icon {
160
+ color: var(--color-error-base, #ef4444);
161
+ }
162
+
163
+ /* Full-width divider between action groups */
164
+ .action-group-divider {
165
+ height: 1px;
166
+ background: var(--color-border-subtle, #e5e5e5);
167
+ margin: 8px 0;
168
+ }
169
+ `,
170
+ ],
171
+ })
172
+ export class DsMobileActionsBottomSheetComponent {
173
+ /**
174
+ * Custom action groups to display (overrides isOwnContent)
175
+ */
176
+ @Input() customActionGroups?: ActionGroup[];
177
+
178
+ /**
179
+ * Whether this content belongs to the current user (for preset content actions)
180
+ */
181
+ @Input() isOwnContent: boolean = false;
182
+
183
+ /**
184
+ * Computed action groups - uses custom groups if provided, otherwise falls back to preset content actions
185
+ */
186
+ actionGroups = computed<ActionGroup[]>(() => {
187
+ // Use custom action groups if provided
188
+ if (this.customActionGroups) {
189
+ return this.customActionGroups;
190
+ }
191
+
192
+ // Otherwise fall back to preset content actions
193
+ if (this.isOwnContent) {
194
+ // Own content: Group 1 (Edit, Delete) + Group 2 (Like, Reply)
195
+ return [
196
+ {
197
+ actions: [
198
+ {
199
+ action: 'edit',
200
+ title: 'Rediger',
201
+ icon: 'remixEditLine',
202
+ destructive: false,
203
+ },
204
+ {
205
+ action: 'delete',
206
+ title: 'Slet',
207
+ icon: 'remixDeleteBinLine',
208
+ destructive: true,
209
+ },
210
+ ],
211
+ },
212
+ {
213
+ actions: [
214
+ {
215
+ action: 'like',
216
+ title: 'Synes om',
217
+ icon: 'remixHeart3Line',
218
+ destructive: false,
219
+ },
220
+ {
221
+ action: 'reply',
222
+ title: 'Svar',
223
+ icon: 'remixReplyLine',
224
+ destructive: false,
225
+ },
226
+ ],
227
+ },
228
+ ];
229
+ } else {
230
+ // Other users' content: Group 1 (Like, Reply)
231
+ return [
232
+ {
233
+ actions: [
234
+ {
235
+ action: 'like',
236
+ title: 'Synes om',
237
+ icon: 'remixHeart3Line',
238
+ destructive: false,
239
+ },
240
+ {
241
+ action: 'reply',
242
+ title: 'Svar',
243
+ icon: 'remixReplyLine',
244
+ destructive: false,
245
+ },
246
+ ],
247
+ },
248
+ ];
249
+ }
250
+ });
251
+
252
+ constructor(private modalController: ModalController) {}
253
+
254
+ /**
255
+ * Handle action selection and dismiss with result
256
+ */
257
+ selectAction(action: string): void {
258
+ this.modalController.dismiss({ action } as ActionResult, 'select');
259
+ }
260
+ }
261
+
262
+ // Legacy exports for backwards compatibility
263
+ export { DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent };
264
+ export { DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent };
265
+ export type { ActionResult as PostActionResult };
266
+ export type { ActionResult as CommentActionResult };
@@ -0,0 +1,146 @@
1
+ import { Component, Input, Output, EventEmitter, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { IonHeader, IonToolbar, IonTitle, IonButtons } from '@ionic/angular/standalone';
4
+ import { DsButtonComponent } from '@propbinder/design-system';
5
+
6
+ /**
7
+ * DsMobileBottomSheetHeaderComponent
8
+ *
9
+ * Reusable header component for bottom sheets with left button, center title, and right button.
10
+ * Styling matches the language switcher pattern (source of truth).
11
+ *
12
+ * Usage:
13
+ * ```html
14
+ * <ds-mobile-bottom-sheet-header
15
+ * title="Sheet Title"
16
+ * leftButtonLabel="Tilbage"
17
+ * rightButtonLabel="Færdig"
18
+ * [rightButtonDisabled]="!isValid()"
19
+ * (leftButtonClick)="handleCancel()"
20
+ * (rightButtonClick)="handleConfirm()">
21
+ * </ds-mobile-bottom-sheet-header>
22
+ * ```
23
+ */
24
+ @Component({
25
+ selector: 'ds-mobile-bottom-sheet-header',
26
+ standalone: true,
27
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
28
+ imports: [
29
+ CommonModule,
30
+ IonHeader,
31
+ IonToolbar,
32
+ IonTitle,
33
+ IonButtons,
34
+ DsButtonComponent
35
+ ],
36
+ template: `
37
+ <ion-header>
38
+ <ion-toolbar>
39
+ <ion-buttons slot="start">
40
+ <ds-button
41
+ variant="secondary"
42
+ size="sm"
43
+ (clicked)="leftButtonClick.emit()">
44
+ {{ leftButtonLabel }}
45
+ </ds-button>
46
+ </ion-buttons>
47
+ <ion-title>{{ title }}</ion-title>
48
+ <ion-buttons slot="end">
49
+ <ds-button
50
+ variant="primary"
51
+ size="sm"
52
+ [disabled]="rightButtonDisabled"
53
+ (clicked)="rightButtonClick.emit()">
54
+ {{ rightButtonLabel }}
55
+ </ds-button>
56
+ </ion-buttons>
57
+ </ion-toolbar>
58
+ </ion-header>
59
+ `,
60
+ styles: [`
61
+ /* Styles copied 1:1 from language switcher (lines 200-249) */
62
+ ion-header {
63
+ box-shadow: none;
64
+ }
65
+
66
+ /* Override Ionic's default iOS header border */
67
+ :host ::ng-deep .header-ios ion-toolbar:last-of-type {
68
+ --border-width: 0 !important;
69
+ }
70
+
71
+ ion-toolbar {
72
+ --background: var(--color-background-neutral-primary, #ffffff);
73
+ --border-width: 0 !important;
74
+ --border-color: var(--color-border-default, #e5e7eb) !important;
75
+ --padding-top: 12px;
76
+ --padding-bottom: 8px;
77
+ --min-height: 56px;
78
+ border-bottom: 1px solid var(--color-border-default, #e5e7eb) !important;
79
+ }
80
+
81
+ /* Ensure the border is applied correctly */
82
+ ion-toolbar::part(native) {
83
+ border-bottom: 1px solid var(--color-border-default, #e5e7eb) !important;
84
+ }
85
+
86
+ ion-title {
87
+ font-family: 'Brockmann', sans-serif;
88
+ font-size: var(--font-size-base);
89
+ font-weight: 600;
90
+ line-height: 22px;
91
+ letter-spacing: -0.4px;
92
+ color: var(--color-text-primary, #1a1a1a);
93
+ }
94
+
95
+ /* Make buttons pill-shaped - both start and end */
96
+ ion-buttons[slot='start'] ds-button {
97
+ --border-radius: 100px;
98
+ }
99
+
100
+ ion-buttons[slot='start'] ds-button::ng-deep button {
101
+ border-radius: 100px;
102
+ }
103
+
104
+ ion-buttons[slot='end'] ds-button {
105
+ --border-radius: 100px;
106
+ }
107
+
108
+ ion-buttons[slot='end'] ds-button::ng-deep button {
109
+ border-radius: 100px;
110
+ }
111
+ `]
112
+ })
113
+ export class DsMobileBottomSheetHeaderComponent {
114
+ /**
115
+ * Center title text
116
+ */
117
+ @Input() title!: string;
118
+
119
+ /**
120
+ * Left button label
121
+ * @default 'Tilbage'
122
+ */
123
+ @Input() leftButtonLabel: string = 'Tilbage';
124
+
125
+ /**
126
+ * Right button label
127
+ * @default 'Færdig'
128
+ */
129
+ @Input() rightButtonLabel: string = 'Færdig';
130
+
131
+ /**
132
+ * Disable right button
133
+ * @default false
134
+ */
135
+ @Input() rightButtonDisabled: boolean = false;
136
+
137
+ /**
138
+ * Emitted when left button is clicked
139
+ */
140
+ @Output() leftButtonClick = new EventEmitter<void>();
141
+
142
+ /**
143
+ * Emitted when right button is clicked
144
+ */
145
+ @Output() rightButtonClick = new EventEmitter<void>();
146
+ }