@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,120 @@
1
+ import { Component, input } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+
4
+ /**
5
+ * DsMobileEmptyStateComponent
6
+ *
7
+ * Reusable empty state component for displaying when there's no content.
8
+ * Used in chat modals, comment sections, and other list-based views.
9
+ *
10
+ * Features:
11
+ * - Optional image display
12
+ * - Customizable title and description
13
+ * - Consistent styling across the app
14
+ * - Flexible image sizing
15
+ *
16
+ * @example
17
+ * ```html
18
+ * <!-- With image -->
19
+ * <ds-mobile-empty-state
20
+ * [imageSrc]="'/Assets/empty-state-inquiry.svg'"
21
+ * [imageAlt]="'No messages'"
22
+ * [title]="'Ingen beskeder endnu'"
23
+ * [description]="'Start samtalen ved at sende en besked'">
24
+ * </ds-mobile-empty-state>
25
+ *
26
+ * <!-- Without image -->
27
+ * <ds-mobile-empty-state
28
+ * [title]="'Ingen resultater'"
29
+ * [description]="'Prøv at justere dine søgekriterier'">
30
+ * </ds-mobile-empty-state>
31
+ * ```
32
+ */
33
+ @Component({
34
+ selector: 'ds-mobile-empty-state',
35
+ standalone: true,
36
+ imports: [CommonModule],
37
+ styles: [`
38
+ :host {
39
+ display: block;
40
+ }
41
+
42
+ .empty-state {
43
+ display: flex;
44
+ flex-direction: column;
45
+ align-items: center;
46
+ justify-content: center;
47
+ padding: 60px 20px;
48
+ text-align: center;
49
+ gap: 24px;
50
+ }
51
+
52
+ .empty-state-image {
53
+ width: 96px;
54
+ height: 96px;
55
+ margin: 0 auto;
56
+ }
57
+
58
+ .empty-state-text {
59
+ display: flex;
60
+ flex-direction: column;
61
+ gap: 8px;
62
+ }
63
+
64
+ .empty-state-title {
65
+ font-family: 'Brockmann', sans-serif;
66
+ font-size: var(--font-size-base);
67
+ font-weight: 600;
68
+ line-height: 1.3;
69
+ color: var(--color-text-primary, #1a1a1a);
70
+ margin: 0;
71
+ }
72
+
73
+ .empty-state-description {
74
+ font-family: 'Brockmann', sans-serif;
75
+ font-size: var(--font-size-sm);
76
+ font-weight: 400;
77
+ line-height: 1.4;
78
+ color: var(--color-text-secondary, #737373);
79
+ margin: 0;
80
+ }
81
+ `],
82
+ template: `
83
+ <div class="empty-state">
84
+ @if (imageSrc()) {
85
+ <img
86
+ [src]="imageSrc()"
87
+ [alt]="imageAlt()"
88
+ class="empty-state-image" />
89
+ }
90
+ <div class="empty-state-text">
91
+ <h3 class="empty-state-title">{{ title() }}</h3>
92
+ @if (description()) {
93
+ <p class="empty-state-description">{{ description() }}</p>
94
+ }
95
+ </div>
96
+ </div>
97
+ `
98
+ })
99
+ export class DsMobileEmptyStateComponent {
100
+ /**
101
+ * Source URL for the empty state image (optional)
102
+ */
103
+ imageSrc = input<string>('');
104
+
105
+ /**
106
+ * Alt text for the image
107
+ */
108
+ imageAlt = input<string>('Empty state');
109
+
110
+ /**
111
+ * Title text for the empty state
112
+ */
113
+ title = input.required<string>();
114
+
115
+ /**
116
+ * Description text for the empty state (optional)
117
+ */
118
+ description = input<string>('');
119
+ }
120
+
@@ -0,0 +1,2 @@
1
+ export * from './ds-mobile-empty-state';
2
+
@@ -0,0 +1,315 @@
1
+ import { Component, input, output, ElementRef, OnInit, OnDestroy, AfterViewInit, inject } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { DsIconButtonComponent } from '@propbinder/design-system';
4
+ import { Platform } from '@ionic/angular/standalone';
5
+
6
+ /**
7
+ * DsMobileFabComponent
8
+ *
9
+ * Floating Action Button component for mobile interfaces.
10
+ * A prominent circular button that floats above the content.
11
+ *
12
+ * Features:
13
+ * - Configurable positioning (bottom-right, bottom-left, bottom-center)
14
+ * - Uses design system theming variables
15
+ * - Dynamically calculates position above tab bar (including safe areas)
16
+ * - Maintains consistent 20px gap from tab bar
17
+ * - Handles iOS safe areas
18
+ * - Accessible with ARIA labels
19
+ * - Smooth entrance animation
20
+ *
21
+ * @example
22
+ * ```html
23
+ * <ds-mobile-fab
24
+ * icon="remixAddLine"
25
+ * [position]="'bottom-right'"
26
+ * (fabClick)="handleAddClick()"
27
+ * ariaLabel="Add new inquiry">
28
+ * </ds-mobile-fab>
29
+ * ```
30
+ */
31
+ @Component({
32
+ selector: 'ds-mobile-fab',
33
+ standalone: true,
34
+ imports: [CommonModule, DsIconButtonComponent],
35
+ host: {
36
+ '[class.fab-bottom-right]': 'position() === "bottom-right"',
37
+ '[class.fab-bottom-left]': 'position() === "bottom-left"',
38
+ '[class.fab-bottom-center]': 'position() === "bottom-center"'
39
+ },
40
+ template: `
41
+ <div class="fab-container">
42
+ <ds-icon-button
43
+ [icon]="icon()"
44
+ variant="primary"
45
+ [size]="size()"
46
+ [ariaLabel]="ariaLabel()"
47
+ [disabled]="disabled()"
48
+ (clicked)="handleClick()"
49
+ class="fab-button">
50
+ </ds-icon-button>
51
+ </div>
52
+ `,
53
+ styles: [`
54
+ :host {
55
+ display: block;
56
+ position: fixed;
57
+ z-index: 1000;
58
+ pointer-events: none;
59
+ }
60
+
61
+ .fab-container {
62
+ position: relative;
63
+ pointer-events: none;
64
+ animation: fabEnter 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
65
+ }
66
+
67
+ @keyframes fabEnter {
68
+ from {
69
+ opacity: 0;
70
+ transform: scale(0.8);
71
+ }
72
+ to {
73
+ opacity: 1;
74
+ transform: scale(1);
75
+ }
76
+ }
77
+
78
+ /* Position variants - now applied to :host */
79
+
80
+ /* MOBILE: Use dynamically calculated position based on actual tab bar height */
81
+ /* The JavaScript calculates the actual tab bar height (including padding) and sets --fab-calculated-bottom */
82
+ /* Fallback to 84px (64px base + 20px gap) if calculation hasn't run yet */
83
+ :host(.fab-bottom-right) {
84
+ bottom: var(--fab-calculated-bottom, 84px);
85
+ right: 20px;
86
+ }
87
+
88
+ :host(.fab-bottom-left) {
89
+ bottom: var(--fab-calculated-bottom, 84px);
90
+ left: 20px;
91
+ }
92
+
93
+ :host(.fab-bottom-center) {
94
+ bottom: var(--fab-calculated-bottom, 84px);
95
+ left: 50%;
96
+ transform: translateX(-50%);
97
+ }
98
+
99
+ /* Horizontal safe area support (all platforms) */
100
+ @supports (padding-right: env(safe-area-inset-right)) {
101
+ :host(.fab-bottom-right) {
102
+ right: calc(20px + env(safe-area-inset-right));
103
+ }
104
+ }
105
+
106
+ @supports (padding-left: env(safe-area-inset-left)) {
107
+ :host(.fab-bottom-left) {
108
+ left: calc(20px + env(safe-area-inset-left));
109
+ }
110
+ }
111
+
112
+ /* DESKTOP: Larger spacing for desktop screens */
113
+ @media (min-width: 768px) {
114
+ :host-context(.plt-desktop).fab-bottom-right {
115
+ bottom: 40px;
116
+ right: 40px;
117
+ }
118
+
119
+ :host-context(.plt-desktop).fab-bottom-left {
120
+ bottom: 40px;
121
+ left: 40px;
122
+ }
123
+
124
+ :host-context(.plt-desktop).fab-bottom-center {
125
+ bottom: 40px;
126
+ }
127
+
128
+ @supports (padding-right: env(safe-area-inset-right)) {
129
+ :host-context(.plt-desktop).fab-bottom-right {
130
+ right: calc(40px + env(safe-area-inset-right));
131
+ }
132
+ }
133
+
134
+ @supports (padding-left: env(safe-area-inset-left)) {
135
+ :host-context(.plt-desktop).fab-bottom-left {
136
+ left: calc(40px + env(safe-area-inset-left));
137
+ }
138
+ }
139
+ }
140
+
141
+ /* FAB Button Styling */
142
+ .fab-button {
143
+ pointer-events: auto;
144
+ display: block;
145
+ }
146
+
147
+ /* Override icon button to be circular and use brand colors */
148
+ .fab-button::ng-deep button {
149
+ width: 56px !important;
150
+ height: 56px !important;
151
+ min-width: 56px !important;
152
+ min-height: 56px !important;
153
+ border-radius: 50% !important;
154
+ padding: 0 !important;
155
+ display: flex !important;
156
+ align-items: center !important;
157
+ justify-content: center !important;
158
+
159
+ /* Use whitelabel theming variables */
160
+ background: var(--color-accent) !important;
161
+ color: var(--color-on-accent) !important;
162
+ border: none !important;
163
+
164
+ /* Elevation shadow for prominence */
165
+ box-shadow:
166
+ 0 3px 5px -1px rgba(0, 0, 0, 0.2),
167
+ 0 6px 10px 0 rgba(0, 0, 0, 0.14),
168
+ 0 1px 18px 0 rgba(0, 0, 0, 0.12);
169
+
170
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
171
+ }
172
+
173
+ /* Hover state */
174
+ .fab-button::ng-deep button:hover:not(:disabled) {
175
+ background: var(--color-accent-hover) !important;
176
+ box-shadow:
177
+ 0 5px 7px -2px rgba(0, 0, 0, 0.2),
178
+ 0 8px 14px 0 rgba(0, 0, 0, 0.14),
179
+ 0 2px 22px 0 rgba(0, 0, 0, 0.12);
180
+ transform: scale(1.05);
181
+ }
182
+
183
+ /* Active state */
184
+ .fab-button::ng-deep button:active:not(:disabled) {
185
+ background: var(--color-accent-active) !important;
186
+ box-shadow:
187
+ 0 2px 4px -1px rgba(0, 0, 0, 0.2),
188
+ 0 4px 8px 0 rgba(0, 0, 0, 0.14),
189
+ 0 1px 14px 0 rgba(0, 0, 0, 0.12);
190
+ transform: scale(0.95);
191
+ }
192
+
193
+ /* Disabled state */
194
+ .fab-button::ng-deep button:disabled {
195
+ opacity: 0.5;
196
+ cursor: not-allowed;
197
+ box-shadow:
198
+ 0 2px 4px -1px rgba(0, 0, 0, 0.1),
199
+ 0 4px 8px 0 rgba(0, 0, 0, 0.08),
200
+ 0 1px 14px 0 rgba(0, 0, 0, 0.06);
201
+ }
202
+
203
+ /* Icon styling */
204
+ .fab-button::ng-deep button .btn__icon,
205
+ .fab-button::ng-deep button .btn__icon svg {
206
+ color: var(--color-on-accent) !important;
207
+ fill: var(--color-on-accent) !important;
208
+ }
209
+
210
+ /* Ensure icon is centered and sized properly */
211
+ .fab-button::ng-deep button .btn__icon {
212
+ display: flex !important;
213
+ align-items: center !important;
214
+ justify-content: center !important;
215
+ flex-shrink: 0 !important;
216
+ }
217
+
218
+ .fab-button::ng-deep button .btn__icon svg {
219
+ width: 24px !important;
220
+ height: 24px !important;
221
+ }
222
+ `]
223
+ })
224
+ export class DsMobileFabComponent implements AfterViewInit, OnDestroy {
225
+ private elementRef = inject(ElementRef);
226
+ private platform = inject(Platform);
227
+ private resizeObserver?: ResizeObserver;
228
+
229
+ /**
230
+ * Icon name from the design system icon library
231
+ * @default 'remixAddLine'
232
+ */
233
+ icon = input<string>('remixAddLine');
234
+
235
+ /**
236
+ * Position of the FAB on the screen
237
+ * @default 'bottom-right'
238
+ */
239
+ position = input<'bottom-right' | 'bottom-left' | 'bottom-center'>('bottom-right');
240
+
241
+ /**
242
+ * Size of the FAB button
243
+ * Note: FAB is always 56px circular, but this affects the icon size
244
+ * @default 'md'
245
+ */
246
+ size = input<'sm' | 'md' | 'lg'>('md');
247
+
248
+ /**
249
+ * ARIA label for accessibility
250
+ * @required - Always provide a descriptive label
251
+ */
252
+ ariaLabel = input.required<string>();
253
+
254
+ /**
255
+ * Whether the FAB is disabled
256
+ * @default false
257
+ */
258
+ disabled = input<boolean>(false);
259
+
260
+ /**
261
+ * Emitted when the FAB is clicked
262
+ */
263
+ clicked = output<void>();
264
+
265
+ ngAfterViewInit(): void {
266
+ // Only calculate position on mobile (not desktop)
267
+ if (!this.platform.is('desktop')) {
268
+ this.calculatePosition();
269
+ this.setupResizeObserver();
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Calculate the FAB position dynamically based on actual tab bar height
275
+ */
276
+ private calculatePosition(): void {
277
+ const tabBar = document.querySelector('ion-tab-bar[slot="bottom"]');
278
+ if (tabBar) {
279
+ const rect = tabBar.getBoundingClientRect();
280
+ const actualHeight = rect.height;
281
+ const gap = 20;
282
+ const bottom = actualHeight + gap;
283
+
284
+ const host = this.elementRef.nativeElement as HTMLElement;
285
+ host.style.setProperty('--fab-calculated-bottom', `${bottom}px`);
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Setup ResizeObserver to recalculate position when tab bar size changes
291
+ * (e.g., when device rotates or safe area changes)
292
+ */
293
+ private setupResizeObserver(): void {
294
+ const tabBar = document.querySelector('ion-tab-bar[slot="bottom"]');
295
+ if (tabBar && 'ResizeObserver' in window) {
296
+ this.resizeObserver = new ResizeObserver(() => {
297
+ this.calculatePosition();
298
+ });
299
+ this.resizeObserver.observe(tabBar);
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Handle button click
305
+ */
306
+ handleClick(): void {
307
+ if (!this.disabled()) {
308
+ this.clicked.emit();
309
+ }
310
+ }
311
+
312
+ ngOnDestroy(): void {
313
+ this.resizeObserver?.disconnect();
314
+ }
315
+ }
@@ -0,0 +1 @@
1
+ export { DsMobileFabComponent } from './ds-mobile-fab';
@@ -0,0 +1,121 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { DsMobileConfirmationSheetComponent } from '../bottom-sheet/ds-mobile-confirmation-sheet';
4
+ import { DsIconComponent } from '@propbinder/design-system';
5
+ import { NewFacilityData } from './ds-mobile-facility-creation-modal';
6
+
7
+ /**
8
+ * DsMobileFacilityCreationConfirmationWrapperComponent
9
+ *
10
+ * Wrapper component that uses the generic confirmation sheet
11
+ * specifically for facility creation confirmations.
12
+ *
13
+ * This component displays a summary of the created facility.
14
+ */
15
+ @Component({
16
+ selector: 'ds-mobile-facility-creation-confirmation-wrapper',
17
+ standalone: true,
18
+ imports: [
19
+ CommonModule,
20
+ DsMobileConfirmationSheetComponent,
21
+ DsIconComponent
22
+ ],
23
+ template: `
24
+ <ds-mobile-confirmation-sheet
25
+ [title]="'Facilitet oprettet'"
26
+ [message]="'Din nye facilitet er nu oprettet og klar til booking.'"
27
+ [buttonText]="'Luk'"
28
+ [illustrationVariant]="'confirmation'">
29
+ <ng-template #summary>
30
+ <div class="facility-summary">
31
+ <div class="summary-item">
32
+ <div class="summary-details">
33
+ <h3 class="summary-title">{{ facilityData.title }}</h3>
34
+ <p class="summary-description">{{ facilityData.description }}</p>
35
+
36
+ <div class="summary-info-list">
37
+ <div class="info-row">
38
+ <ds-icon name="remixGroupLine" size="16px" color="tertiary" />
39
+ <span class="info-label">{{ facilityData.whoCanBook }}</span>
40
+ </div>
41
+ <div class="info-row">
42
+ <ds-icon name="remixCalendarLine" size="16px" color="tertiary" />
43
+ <span class="info-label">{{ facilityData.whenCanBook }}</span>
44
+ </div>
45
+ <div class="info-row">
46
+ <ds-icon name="remixPriceTag3Line" size="16px" color="tertiary" />
47
+ <span class="info-label">{{ facilityData.price }}</span>
48
+ </div>
49
+ <div class="info-row">
50
+ <ds-icon name="remixKeyLine" size="16px" color="tertiary" />
51
+ <span class="info-label">{{ facilityData.accessRequirements }}</span>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </ng-template>
58
+ </ds-mobile-confirmation-sheet>
59
+ `,
60
+ styles: [`
61
+ .facility-summary {
62
+ width: 100%;
63
+ background: var(--color-background-neutral-secondary, #f5f5f5);
64
+ border-radius: 16px;
65
+ padding: 16px;
66
+ }
67
+
68
+ .summary-item {
69
+ display: flex;
70
+ gap: 12px;
71
+ align-items: flex-start;
72
+ }
73
+
74
+ .summary-details {
75
+ flex: 1;
76
+ display: flex;
77
+ flex-direction: column;
78
+ gap: 12px;
79
+ }
80
+
81
+ .summary-title {
82
+ font-family: 'Brockmann', sans-serif;
83
+ font-size: var(--font-size-base, 16px);
84
+ font-weight: 600;
85
+ color: var(--text-color-default-primary, #202227);
86
+ margin: 0;
87
+ }
88
+
89
+ .summary-description {
90
+ font-family: 'Brockmann', sans-serif;
91
+ font-size: var(--font-size-sm, 14px);
92
+ font-weight: 400;
93
+ line-height: 1.5;
94
+ color: var(--text-color-default-secondary, #545b66);
95
+ margin: 0;
96
+ }
97
+
98
+ .summary-info-list {
99
+ display: flex;
100
+ flex-direction: column;
101
+ gap: 8px;
102
+ margin-top: 4px;
103
+ }
104
+
105
+ .info-row {
106
+ display: flex;
107
+ align-items: center;
108
+ gap: 8px;
109
+ }
110
+
111
+ .info-label {
112
+ font-family: 'Brockmann', sans-serif;
113
+ font-size: var(--font-size-sm, 14px);
114
+ font-weight: 400;
115
+ color: var(--text-color-default-secondary, #545b66);
116
+ }
117
+ `]
118
+ })
119
+ export class DsMobileFacilityCreationConfirmationWrapperComponent {
120
+ @Input() facilityData!: NewFacilityData;
121
+ }