@propbinder/mobile-design 0.2.50 → 0.2.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/propbinder-mobile-design.mjs +26206 -0
- package/fesm2022/propbinder-mobile-design.mjs.map +1 -0
- package/index.d.ts +8193 -0
- package/package.json +39 -3
- package/ng-package.json +0 -24
- package/src/animations/page-transitions.ts +0 -165
- package/src/components/action-list-item/ds-mobile-action-list-item.ts +0 -102
- package/src/components/action-list-item/index.ts +0 -2
- package/src/components/app-icon/ds-app-icon.ts +0 -133
- package/src/components/app-icon/index.ts +0 -2
- package/src/components/attachment-preview/ds-mobile-attachment-preview.css +0 -139
- package/src/components/attachment-preview/ds-mobile-attachment-preview.ts +0 -164
- package/src/components/attachment-preview/index.ts +0 -1
- package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +0 -142
- package/src/components/avatar-with-badge/index.ts +0 -2
- package/src/components/booking-modal/ds-mobile-booking-confirmation-wrapper.ts +0 -71
- package/src/components/booking-modal/ds-mobile-booking-modal.service.ts +0 -121
- package/src/components/booking-modal/ds-mobile-booking-modal.ts +0 -598
- package/src/components/booking-modal/ds-mobile-booking-summary.ts +0 -161
- package/src/components/booking-modal/index.ts +0 -4
- package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +0 -266
- package/src/components/bottom-sheet/ds-mobile-bottom-sheet-header.ts +0 -146
- package/src/components/bottom-sheet/ds-mobile-bottom-sheet-wrapper.ts +0 -156
- package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +0 -101
- package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +0 -169
- package/src/components/bottom-sheet/ds-mobile-confirmation-sheet.ts +0 -211
- package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +0 -578
- package/src/components/bottom-sheet/ds-mobile-profile-actions-sheet.ts +0 -614
- package/src/components/bottom-sheet/index.ts +0 -8
- package/src/components/bottom-sheet/modal-shadow-fix.ts +0 -42
- package/src/components/card-inline/ds-mobile-card-inline.ts +0 -301
- package/src/components/card-inline/index.ts +0 -2
- package/src/components/card-inline-banner/ds-mobile-card-inline-banner.ts +0 -118
- package/src/components/card-inline-banner/index.ts +0 -1
- package/src/components/card-inline-contact/ds-mobile-card-inline-contact.ts +0 -120
- package/src/components/card-inline-contact/index.ts +0 -1
- package/src/components/card-inline-file/ds-mobile-card-inline-file.ts +0 -141
- package/src/components/card-inline-file/index.ts +0 -1
- package/src/components/chat-modal/ds-mobile-chat-modal.css +0 -159
- package/src/components/chat-modal/ds-mobile-chat-modal.service.ts +0 -105
- package/src/components/chat-modal/ds-mobile-chat-modal.ts +0 -918
- package/src/components/chat-modal/index.ts +0 -8
- package/src/components/comment/ds-mobile-comment.ts +0 -568
- package/src/components/comment/index.ts +0 -2
- package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +0 -182
- package/src/components/contact-list-item/index.ts +0 -2
- package/src/components/content/ds-mobile-content.ts +0 -139
- package/src/components/content/index.ts +0 -2
- package/src/components/dropdown/ds-mobile-dropdown.css +0 -199
- package/src/components/dropdown/ds-mobile-dropdown.ts +0 -340
- package/src/components/dropdown/index.ts +0 -2
- package/src/components/ds-mobile-tabs.css +0 -407
- package/src/components/ds-mobile-tabs.ts +0 -216
- package/src/components/empty-state/ds-mobile-empty-state.ts +0 -120
- package/src/components/empty-state/index.ts +0 -2
- package/src/components/fab/ds-mobile-fab.ts +0 -315
- package/src/components/fab/index.ts +0 -1
- package/src/components/facility-creation-modal/ds-mobile-facility-creation-confirmation-wrapper.ts +0 -121
- package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.css +0 -189
- package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.service.ts +0 -135
- package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.ts +0 -656
- package/src/components/facility-creation-modal/index.ts +0 -9
- package/src/components/facility-creation-modal/sheets/ds-mobile-access-sheet.ts +0 -105
- package/src/components/facility-creation-modal/sheets/ds-mobile-price-sheet.ts +0 -188
- package/src/components/facility-creation-modal/sheets/ds-mobile-when-can-book-sheet.ts +0 -460
- package/src/components/facility-creation-modal/sheets/ds-mobile-who-can-book-sheet.ts +0 -134
- package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.service.ts +0 -69
- package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.ts +0 -379
- package/src/components/facility-detail-modal/index.ts +0 -2
- package/src/components/file-attachment/ds-mobile-file-attachment.ts +0 -164
- package/src/components/file-attachment/index.ts +0 -2
- package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.css +0 -214
- package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +0 -84
- package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +0 -424
- package/src/components/handbook-detail-modal/index.ts +0 -3
- package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +0 -175
- package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +0 -533
- package/src/components/handbook-folder/index.ts +0 -4
- package/src/components/header-content/ds-mobile-header-content.ts +0 -222
- package/src/components/header-content/index.ts +0 -2
- package/src/components/illustration/ds-mobile-illustration.ts +0 -124
- package/src/components/illustration/index.ts +0 -2
- package/src/components/index.ts +0 -124
- package/src/components/inline-photo/ds-mobile-inline-photo.ts +0 -361
- package/src/components/inline-photo/index.ts +0 -1
- package/src/components/inline-tabs/ds-mobile-inline-tabs.ts +0 -132
- package/src/components/inline-tabs/index.ts +0 -2
- package/src/components/interactive-list-item-booking/ds-mobile-interactive-list-item-booking.ts +0 -350
- package/src/components/interactive-list-item-booking/index.ts +0 -1
- package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +0 -321
- package/src/components/interactive-list-item-inquiry/index.ts +0 -2
- package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +0 -237
- package/src/components/interactive-list-item-message/index.ts +0 -2
- package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +0 -549
- package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +0 -124
- package/src/components/interactive-list-item-post/index.ts +0 -13
- package/src/components/lightbox/ds-mobile-lightbox-footer.ts +0 -315
- package/src/components/lightbox/ds-mobile-lightbox-header.ts +0 -202
- package/src/components/lightbox/ds-mobile-lightbox-image.ts +0 -484
- package/src/components/lightbox/ds-mobile-lightbox-pdf.css +0 -377
- package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +0 -374
- package/src/components/lightbox/ds-mobile-lightbox.css +0 -587
- package/src/components/lightbox/ds-mobile-lightbox.service.ts +0 -296
- package/src/components/lightbox/ds-mobile-lightbox.ts +0 -529
- package/src/components/lightbox/index.ts +0 -22
- package/src/components/list-item/ds-mobile-list-item.ts +0 -603
- package/src/components/list-item/index.ts +0 -2
- package/src/components/list-item-static/ds-mobile-list-item-static.ts +0 -133
- package/src/components/list-item-static/index.ts +0 -2
- package/src/components/loader-overlay/ds-mobile-loader-overlay.css +0 -49
- package/src/components/loader-overlay/ds-mobile-loader-overlay.ts +0 -77
- package/src/components/loader-overlay/index.ts +0 -1
- package/src/components/logo/ds-logo.ts +0 -95
- package/src/components/logo/index.ts +0 -2
- package/src/components/message-bubble/ds-mobile-message-bubble.ts +0 -633
- package/src/components/message-bubble/index.ts +0 -7
- package/src/components/message-composer/ds-mobile-message-composer.ts +0 -1146
- package/src/components/message-composer/index.ts +0 -7
- package/src/components/modal/ds-mobile-modal.css +0 -163
- package/src/components/modal/ds-mobile-modal.service.ts +0 -329
- package/src/components/modal/index.ts +0 -8
- package/src/components/modal-base/ds-mobile-modal-base.css +0 -378
- package/src/components/modal-base/ds-mobile-modal-base.ts +0 -261
- package/src/components/modal-base/index.ts +0 -2
- package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.css +0 -112
- package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.service.ts +0 -93
- package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.ts +0 -442
- package/src/components/new-inquiry-modal/index.ts +0 -4
- package/src/components/offline-banner/ds-mobile-offline-banner.ts +0 -135
- package/src/components/offline-banner/index.ts +0 -1
- package/src/components/page-details/ds-mobile-page-details.css +0 -83
- package/src/components/page-details/ds-mobile-page-details.ts +0 -282
- package/src/components/page-details/index.ts +0 -2
- package/src/components/page-main/ds-mobile-page-main.css +0 -68
- package/src/components/page-main/ds-mobile-page-main.ts +0 -421
- package/src/components/page-main/index.ts +0 -2
- package/src/components/post-composer/ds-mobile-post-composer.ts +0 -140
- package/src/components/post-composer/index.ts +0 -2
- package/src/components/post-detail-modal/ds-mobile-post-detail-modal.css +0 -390
- package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +0 -108
- package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +0 -722
- package/src/components/post-detail-modal/index.ts +0 -9
- package/src/components/property-banner/ds-mobile-property-banner.ts +0 -95
- package/src/components/property-banner/index.ts +0 -2
- package/src/components/section/ds-mobile-section.ts +0 -263
- package/src/components/section/index.ts +0 -2
- package/src/components/shared/directives/index.ts +0 -2
- package/src/components/shared/directives/long-press.directive.ts +0 -212
- package/src/components/shared/index.ts +0 -3
- package/src/components/shared/mobile-modal-base.ts +0 -457
- package/src/components/shared/mobile-page-base.ts +0 -204
- package/src/components/swiper/ds-mobile-swiper-with-nav.ts +0 -160
- package/src/components/swiper/ds-mobile-swiper.ts +0 -327
- package/src/components/swiper/index.ts +0 -3
- package/src/components/system-message-banner/ds-mobile-system-message-banner.ts +0 -129
- package/src/components/system-message-banner/index.ts +0 -2
- package/src/components/tab-bar/ds-mobile-tab-bar.css +0 -533
- package/src/components/tab-bar/ds-mobile-tab-bar.ts +0 -735
- package/src/components/tab-bar/index.ts +0 -2
- package/src/components/tabs/ds-mobile-tabs.css +0 -25
- package/src/components/tabs/ds-mobile-tabs.ts +0 -89
- package/src/components/tabs/index.ts +0 -2
- package/src/components/text-input/ds-text-input.ts +0 -287
- package/src/components/text-input/index.ts +0 -2
- package/src/examples/booking.page.ts +0 -434
- package/src/examples/community.page.ts +0 -776
- package/src/examples/handbook.page.ts +0 -324
- package/src/examples/home.page.ts +0 -347
- package/src/examples/index.ts +0 -12
- package/src/examples/inquiries.example.ts +0 -273
- package/src/examples/inquiry-detail.example.css +0 -189
- package/src/examples/inquiry-detail.example.ts +0 -415
- package/src/examples/mobile-tabs-example.component.ts +0 -208
- package/src/examples/post-create.page.ts +0 -311
- package/src/examples/post-detail.page.ts +0 -296
- package/src/examples/sign-in.page.ts +0 -291
- package/src/examples/whitelabel-demo-modal.component.ts +0 -1094
- package/src/examples/whitelabel-demo-modal.service.ts +0 -77
- package/src/models/index.ts +0 -7
- package/src/models/post.model.ts +0 -41
- package/src/pages/community.page.ts +0 -769
- package/src/pages/handbook.page.ts +0 -388
- package/src/pages/home.page.ts +0 -303
- package/src/pages/index.ts +0 -11
- package/src/pages/inquiries.example.ts +0 -273
- package/src/pages/inquiry-detail.example.css +0 -189
- package/src/pages/inquiry-detail.example.ts +0 -415
- package/src/pages/mobile-tabs-example.component.ts +0 -179
- package/src/pages/post-create.page.ts +0 -311
- package/src/pages/post-detail.page.ts +0 -296
- package/src/pages/sign-in.page.ts +0 -291
- package/src/pages/whitelabel-demo-modal.component.ts +0 -1094
- package/src/pages/whitelabel-demo-modal.service.ts +0 -77
- package/src/public-api.ts +0 -6
- package/src/services/base-modal.service.ts +0 -101
- package/src/services/index.ts +0 -11
- package/src/services/posts.service.ts +0 -542
- package/src/services/tracking-permission.service.ts +0 -88
- package/src/services/user.service.ts +0 -60
- package/src/services/whitelabel.service.ts +0 -675
- package/tsconfig.lib.json +0 -17
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -13
- /package/{src/assets → assets}/fonts/Brockmann-Bold.otf +0 -0
- /package/{src/assets → assets}/fonts/Brockmann-BoldItalic.otf +0 -0
- /package/{src/assets → assets}/fonts/Brockmann-Medium.otf +0 -0
- /package/{src/assets → assets}/fonts/Brockmann-MediumItalic.otf +0 -0
- /package/{src/assets → assets}/fonts/Brockmann-Regular.otf +0 -0
- /package/{src/assets → assets}/fonts/Brockmann-RegularItalic.otf +0 -0
- /package/{src/assets → assets}/fonts/Brockmann-SemiBold.otf +0 -0
- /package/{src/assets → assets}/fonts/Brockmann-SemiBoldItalic.otf +0 -0
- /package/{src/assets → assets}/fonts/Brockmann_desktop_license.pdf +0 -0
- /package/{src/assets → assets}/fonts/brockmann-medium-webfont.woff2 +0 -0
- /package/{src/assets → assets}/fonts/brockmann-mediumitalic-webfont.woff2 +0 -0
- /package/{src/assets → assets}/fonts/brockmann-regular-webfont.woff2 +0 -0
- /package/{src/assets → assets}/fonts/brockmann-regularitalic-webfont.woff2 +0 -0
- /package/{src/assets → assets}/fonts/brockmann-semibold-webfont.woff2 +0 -0
- /package/{src/assets → assets}/fonts/brockmann-semibolditalic-webfont.woff2 +0 -0
- /package/{src/styles → styles}/ionic.css +0 -0
- /package/{src/components/shared → styles}/mobile-common.css +0 -0
- /package/{src/components/shared → styles}/mobile-page-base.css +0 -0
|
@@ -1,614 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Component,
|
|
3
|
-
Input,
|
|
4
|
-
signal,
|
|
5
|
-
computed,
|
|
6
|
-
ViewChild,
|
|
7
|
-
ElementRef,
|
|
8
|
-
afterNextRender,
|
|
9
|
-
Injector,
|
|
10
|
-
OnInit,
|
|
11
|
-
OnChanges,
|
|
12
|
-
SimpleChanges,
|
|
13
|
-
} from '@angular/core';
|
|
14
|
-
import { CommonModule } from '@angular/common';
|
|
15
|
-
import { ModalController } from '@ionic/angular/standalone';
|
|
16
|
-
import { DsIconComponent, DsIconButtonComponent } from '@propbinder/design-system';
|
|
17
|
-
import { DsMobileActionListItemComponent } from '../action-list-item/ds-mobile-action-list-item';
|
|
18
|
-
import { ActionResult, ActionItem, ActionGroup } from './ds-mobile-actions-bottom-sheet';
|
|
19
|
-
import { DsMobileBottomSheetWrapperComponent } from './ds-mobile-bottom-sheet-wrapper';
|
|
20
|
-
import { DsMobileBottomSheetHeaderComponent } from './ds-mobile-bottom-sheet-header';
|
|
21
|
-
|
|
22
|
-
export interface Language {
|
|
23
|
-
code: string;
|
|
24
|
-
nativeName: string;
|
|
25
|
-
englishName: string;
|
|
26
|
-
flagIcon: string; // Path to flag SVG or icon name
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* DsMobileProfileActionsSheetComponent
|
|
31
|
-
*
|
|
32
|
-
* Bottom sheet for profile actions with navigable language selection.
|
|
33
|
-
* Features a smooth slide-in navigation pattern for sub-menus.
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```typescript
|
|
37
|
-
* const sheet = await this.modalController.create({
|
|
38
|
-
* component: DsMobileProfileActionsSheetComponent,
|
|
39
|
-
* componentProps: {
|
|
40
|
-
* actionGroups: [...],
|
|
41
|
-
* currentLanguage: 'da',
|
|
42
|
-
* availableLanguages: [...]
|
|
43
|
-
* },
|
|
44
|
-
* breakpoints: [0, 1],
|
|
45
|
-
* initialBreakpoint: 1,
|
|
46
|
-
* handle: true,
|
|
47
|
-
* cssClass: ['ds-bottom-sheet', 'auto-height']
|
|
48
|
-
* });
|
|
49
|
-
*
|
|
50
|
-
* const result = await sheet.onWillDismiss();
|
|
51
|
-
* if (result.data?.action) {
|
|
52
|
-
* // Handle the action (e.g., 'language:da', 'profile', 'logout')
|
|
53
|
-
* }
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
@Component({
|
|
57
|
-
selector: 'ds-mobile-profile-actions-sheet',
|
|
58
|
-
standalone: true,
|
|
59
|
-
imports: [CommonModule, DsIconComponent, DsMobileActionListItemComponent, DsMobileBottomSheetWrapperComponent, DsMobileBottomSheetHeaderComponent],
|
|
60
|
-
template: `
|
|
61
|
-
<ds-mobile-bottom-sheet-wrapper>
|
|
62
|
-
<div class="profile-sheet-content" #sheetWrapper>
|
|
63
|
-
<!-- View Container with CSS Animation -->
|
|
64
|
-
<div class="view-container" #viewContainer
|
|
65
|
-
[class.show-language]="currentView() === 'language'"
|
|
66
|
-
[class.is-animating]="isAnimating()"
|
|
67
|
-
[style.height.px]="isAnimating() ? containerHeight() : null">
|
|
68
|
-
<!-- Main Actions View -->
|
|
69
|
-
<div class="view main-view" [class.active]="currentView() === 'main'">
|
|
70
|
-
<div class="actions-list">
|
|
71
|
-
@for (group of actionGroups; track $index; let isLast = $last) {
|
|
72
|
-
<!-- Action Group -->
|
|
73
|
-
<div class="action-group">
|
|
74
|
-
@for (actionItem of group.actions; track actionItem.action; let isLastInGroup = $last) {
|
|
75
|
-
<ds-mobile-action-list-item
|
|
76
|
-
[title]="actionItem.title"
|
|
77
|
-
[showDivider]="!isLastInGroup"
|
|
78
|
-
[class.destructive]="actionItem.destructive"
|
|
79
|
-
(itemClick)="handleActionClick(actionItem)"
|
|
80
|
-
>
|
|
81
|
-
<ds-icon action-icon [name]="actionItem.icon" size="20px" [class.destructive-icon]="actionItem.destructive" />
|
|
82
|
-
|
|
83
|
-
@if (actionItem.showChevron || actionItem.subtitle || actionItem.flagIcon) {
|
|
84
|
-
<div content-trailing class="trailing-content">
|
|
85
|
-
@if (actionItem.flagIcon) {
|
|
86
|
-
<img [src]="actionItem.flagIcon" [alt]="actionItem.title + ' flag'" class="subtitle-flag" />
|
|
87
|
-
} @if (actionItem.subtitle) {
|
|
88
|
-
<span class="subtitle">{{ actionItem.subtitle }}</span>
|
|
89
|
-
} @if (actionItem.showChevron) {
|
|
90
|
-
<ds-icon name="remixArrowRightSLine" size="20px" class="chevron-icon" />
|
|
91
|
-
}
|
|
92
|
-
</div>
|
|
93
|
-
}
|
|
94
|
-
</ds-mobile-action-list-item>
|
|
95
|
-
}
|
|
96
|
-
</div>
|
|
97
|
-
|
|
98
|
-
<!-- Full-width divider between groups -->
|
|
99
|
-
@if (!isLast) {
|
|
100
|
-
<div class="action-group-divider"></div>
|
|
101
|
-
} }
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
|
-
<!-- Language Selection View -->
|
|
106
|
-
<div class="view language-view" [class.active]="currentView() === 'language'">
|
|
107
|
-
<!-- Header with back and done buttons -->
|
|
108
|
-
<ds-mobile-bottom-sheet-header
|
|
109
|
-
title="Sprog"
|
|
110
|
-
leftButtonLabel="Tilbage"
|
|
111
|
-
rightButtonLabel="Færdig"
|
|
112
|
-
[rightButtonDisabled]="!hasLanguageChanged()"
|
|
113
|
-
(leftButtonClick)="navigateBack()"
|
|
114
|
-
(rightButtonClick)="confirmLanguageSelection()">
|
|
115
|
-
</ds-mobile-bottom-sheet-header>
|
|
116
|
-
|
|
117
|
-
<!-- Language Options -->
|
|
118
|
-
<div class="language-list">
|
|
119
|
-
@for (language of availableLanguages; track language.code; let isLast = $last) {
|
|
120
|
-
<ds-mobile-action-list-item [title]="language.nativeName" [showDivider]="!isLast" (itemClick)="selectLanguage(language.code)">
|
|
121
|
-
<!-- Country Flag -->
|
|
122
|
-
<img action-icon [src]="language.flagIcon" [alt]="language.englishName + ' flag'" class="language-flag" />
|
|
123
|
-
|
|
124
|
-
<!-- Radio Indicator in trailing slot -->
|
|
125
|
-
<div content-trailing class="radio-wrapper">
|
|
126
|
-
<div class="radio-indicator" [class.radio-checked]="language.code === selectedLanguage()">
|
|
127
|
-
<div class="radio-inner"></div>
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
</ds-mobile-action-list-item>
|
|
131
|
-
}
|
|
132
|
-
</div>
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
</ds-mobile-bottom-sheet-wrapper>
|
|
137
|
-
`,
|
|
138
|
-
styles: [
|
|
139
|
-
`
|
|
140
|
-
:host {
|
|
141
|
-
display: block;
|
|
142
|
-
height: auto;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
.profile-sheet-content {
|
|
146
|
-
overflow: hidden;
|
|
147
|
-
width: 100%;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/* View Container - holds both views side by side */
|
|
151
|
-
.view-container {
|
|
152
|
-
display: grid;
|
|
153
|
-
grid-template-columns: 50% 50%;
|
|
154
|
-
width: 200%;
|
|
155
|
-
transform: translateX(0);
|
|
156
|
-
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), height 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.15s ease-in-out;
|
|
157
|
-
overflow: hidden;
|
|
158
|
-
/* Height will be set dynamically via inline style */
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
.view-container.show-language {
|
|
162
|
-
transform: translateX(-50%);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/* Individual Views */
|
|
166
|
-
.view {
|
|
167
|
-
width: 100%;
|
|
168
|
-
/* Remove any min-height constraints */
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.view-container:not(.is-animating) .view:not(.active) {
|
|
172
|
-
height: 0 !important;
|
|
173
|
-
overflow: hidden !important;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/* Main View */
|
|
177
|
-
.main-view {
|
|
178
|
-
padding-top: 16px;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
.actions-list {
|
|
182
|
-
display: flex;
|
|
183
|
-
flex-direction: column;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.action-group {
|
|
187
|
-
display: flex;
|
|
188
|
-
flex-direction: column;
|
|
189
|
-
padding: 0 16px;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/* Language View */
|
|
193
|
-
.language-view {
|
|
194
|
-
display: flex;
|
|
195
|
-
flex-direction: column;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/* Language list styles */
|
|
199
|
-
.language-list {
|
|
200
|
-
padding: 8px 16px;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
.language-flag {
|
|
204
|
-
width: 24px;
|
|
205
|
-
height: 24px;
|
|
206
|
-
object-fit: cover;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/* Radio wrapper to ensure proper positioning */
|
|
210
|
-
.radio-wrapper {
|
|
211
|
-
display: flex;
|
|
212
|
-
align-items: center;
|
|
213
|
-
justify-content: center;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/* Radio Button Indicator (Custom styled to match DS radio) */
|
|
217
|
-
.radio-indicator {
|
|
218
|
-
width: 20px;
|
|
219
|
-
height: 20px;
|
|
220
|
-
border: 2px solid var(--color-border-default, #d1d5db);
|
|
221
|
-
border-radius: 50%;
|
|
222
|
-
display: flex;
|
|
223
|
-
align-items: center;
|
|
224
|
-
justify-content: center;
|
|
225
|
-
transition: all 0.2s ease;
|
|
226
|
-
flex-shrink: 0;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.radio-indicator.radio-checked {
|
|
230
|
-
border-color: var(--color-accent, #7c3aed);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
.radio-inner {
|
|
234
|
-
width: 10px;
|
|
235
|
-
height: 10px;
|
|
236
|
-
border-radius: 50%;
|
|
237
|
-
background: transparent;
|
|
238
|
-
transition: background 0.2s ease;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
.radio-checked .radio-inner {
|
|
242
|
-
background: var(--color-accent, #7c3aed);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/* Trailing Content (Subtitle + Chevron) */
|
|
246
|
-
.trailing-content {
|
|
247
|
-
display: flex;
|
|
248
|
-
align-items: center;
|
|
249
|
-
gap: 8px;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
.subtitle-flag {
|
|
253
|
-
width: 16px;
|
|
254
|
-
height: 16px;
|
|
255
|
-
object-fit: cover;
|
|
256
|
-
border-radius: 2px;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.subtitle {
|
|
260
|
-
font-size: 15px;
|
|
261
|
-
color: var(--color-text-subtle, #6b7280);
|
|
262
|
-
line-height: 20px;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
.chevron-icon {
|
|
266
|
-
color: var(--color-text-secondary, #737373);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
.check-icon {
|
|
270
|
-
color: var(--color-primary-base, #7c3aed);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/* Override default background for action items */
|
|
274
|
-
::ng-deep ds-mobile-action-list-item ds-mobile-list-item {
|
|
275
|
-
--color-background-primary: transparent;
|
|
276
|
-
--color-background-neutral-primary-hover: var(--color-background-neutral-secondary, #f5f5f5);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
::ng-deep ds-mobile-action-list-item ds-mobile-list-item .list-item-inner::before {
|
|
280
|
-
z-index: 0 !important;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
::ng-deep ds-mobile-action-list-item ds-mobile-list-item .content-leading,
|
|
284
|
-
::ng-deep ds-mobile-action-list-item ds-mobile-list-item .content-main,
|
|
285
|
-
::ng-deep ds-mobile-action-list-item ds-mobile-list-item .content-trailing {
|
|
286
|
-
position: relative;
|
|
287
|
-
z-index: 1;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/* Destructive action styling */
|
|
291
|
-
ds-mobile-action-list-item.destructive {
|
|
292
|
-
--text-color-default-primary: var(--color-error-base, #ef4444);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
.destructive-icon {
|
|
296
|
-
color: var(--color-error-base, #ef4444);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/* Full-width divider between action groups */
|
|
300
|
-
.action-group-divider {
|
|
301
|
-
height: 1px;
|
|
302
|
-
background: var(--color-border-subtle, #e5e5e5);
|
|
303
|
-
margin: 8px 0;
|
|
304
|
-
}
|
|
305
|
-
`,
|
|
306
|
-
],
|
|
307
|
-
})
|
|
308
|
-
export class DsMobileProfileActionsSheetComponent implements OnInit, OnChanges {
|
|
309
|
-
/**
|
|
310
|
-
* Action groups to display in main view
|
|
311
|
-
*/
|
|
312
|
-
@Input() actionGroups: ActionGroup[] = [];
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Currently selected language code
|
|
316
|
-
*/
|
|
317
|
-
@Input() currentLanguage: string = 'da';
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Initial language (for tracking changes)
|
|
321
|
-
*/
|
|
322
|
-
private initialLanguage: string = '';
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Currently selected language in the view (before confirmation)
|
|
326
|
-
*/
|
|
327
|
-
selectedLanguage = signal<string>('');
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* Check if language has changed
|
|
331
|
-
*/
|
|
332
|
-
hasLanguageChanged = computed(() => {
|
|
333
|
-
return this.selectedLanguage() !== this.initialLanguage && this.selectedLanguage() !== '';
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Available languages for selection
|
|
338
|
-
*/
|
|
339
|
-
@Input() availableLanguages: Language[] = [
|
|
340
|
-
{
|
|
341
|
-
code: 'da',
|
|
342
|
-
nativeName: 'Dansk',
|
|
343
|
-
englishName: 'Danish',
|
|
344
|
-
flagIcon: '/Assets/country-flags/denmark.svg',
|
|
345
|
-
},
|
|
346
|
-
{
|
|
347
|
-
code: 'en',
|
|
348
|
-
nativeName: 'English',
|
|
349
|
-
englishName: 'English',
|
|
350
|
-
flagIcon: '/Assets/country-flags/united kingdom.svg',
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
code: 'sv',
|
|
354
|
-
nativeName: 'Svenska',
|
|
355
|
-
englishName: 'Swedish',
|
|
356
|
-
flagIcon: '/Assets/country-flags/sweden.svg',
|
|
357
|
-
},
|
|
358
|
-
{
|
|
359
|
-
code: 'no',
|
|
360
|
-
nativeName: 'Norsk',
|
|
361
|
-
englishName: 'Norwegian',
|
|
362
|
-
flagIcon: '/Assets/country-flags/norway.svg',
|
|
363
|
-
},
|
|
364
|
-
{
|
|
365
|
-
code: 'de',
|
|
366
|
-
nativeName: 'Deutsch',
|
|
367
|
-
englishName: 'German',
|
|
368
|
-
flagIcon: '/Assets/country-flags/germany.svg',
|
|
369
|
-
},
|
|
370
|
-
];
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Current view state
|
|
374
|
-
*/
|
|
375
|
-
currentView = signal<'main' | 'language'>('main');
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Reference to the view container for height calculations
|
|
379
|
-
*/
|
|
380
|
-
@ViewChild('viewContainer', { read: ElementRef })
|
|
381
|
-
viewContainer?: ElementRef<HTMLDivElement>;
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Reference to the profile actions sheet wrapper
|
|
385
|
-
*/
|
|
386
|
-
@ViewChild('sheetWrapper', { read: ElementRef })
|
|
387
|
-
sheetWrapper?: ElementRef<HTMLDivElement>;
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Current container height (for dynamic transitions)
|
|
391
|
-
*/
|
|
392
|
-
containerHeight = signal<number | null>(null);
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Is animating between views
|
|
396
|
-
*/
|
|
397
|
-
isAnimating = signal<boolean>(false);
|
|
398
|
-
|
|
399
|
-
constructor(private modalController: ModalController, private injector: Injector) {
|
|
400
|
-
// Set initial height after render
|
|
401
|
-
afterNextRender(
|
|
402
|
-
() => {
|
|
403
|
-
this.updateHeight();
|
|
404
|
-
},
|
|
405
|
-
{ injector: this.injector }
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
ngOnChanges(changes: SimpleChanges): void {
|
|
410
|
-
if (changes['currentLanguage']) {
|
|
411
|
-
const val = changes['currentLanguage'].currentValue;
|
|
412
|
-
if (val) {
|
|
413
|
-
this.selectedLanguage.set(val);
|
|
414
|
-
this.initialLanguage = val;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
ngOnInit(): void {
|
|
420
|
-
// Try to get language from localStorage as fallback
|
|
421
|
-
const storedLangCode = this.getLanguageFromStorage();
|
|
422
|
-
|
|
423
|
-
if (storedLangCode) {
|
|
424
|
-
this.selectedLanguage.set(storedLangCode);
|
|
425
|
-
this.initialLanguage = storedLangCode;
|
|
426
|
-
} else if (!this.selectedLanguage()) {
|
|
427
|
-
// Fallback to input if storage is empty
|
|
428
|
-
this.selectedLanguage.set(this.currentLanguage);
|
|
429
|
-
this.initialLanguage = this.currentLanguage;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* Try to resolve short language code from localStorage ('selectedLanguage' key)
|
|
435
|
-
*/
|
|
436
|
-
private getLanguageFromStorage(): string | null {
|
|
437
|
-
try {
|
|
438
|
-
const stored = localStorage.getItem('selectedLanguage'); // e.g. "da-DK", "sv-SE"
|
|
439
|
-
if (!stored) return null;
|
|
440
|
-
|
|
441
|
-
// Find the code from availableLanguages that matches this locale/string
|
|
442
|
-
// We check if any language code is part of the stored string (e.g. 'da' in 'da-DK')
|
|
443
|
-
const match = this.availableLanguages.find(lang =>
|
|
444
|
-
lang.code === stored || stored.startsWith(lang.code + '-')
|
|
445
|
-
);
|
|
446
|
-
|
|
447
|
-
return match ? match.code : null;
|
|
448
|
-
} catch (e) {
|
|
449
|
-
return null;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Handle action item click
|
|
455
|
-
*/
|
|
456
|
-
handleActionClick(actionItem: ActionItem): void {
|
|
457
|
-
// If it's the language action, navigate to language view
|
|
458
|
-
if (actionItem.action === 'language') {
|
|
459
|
-
this.animateViewTransition('language');
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// Otherwise, dismiss with the action
|
|
464
|
-
this.selectAction(actionItem.action);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* Navigate back to main view
|
|
469
|
-
*/
|
|
470
|
-
navigateBack(): void {
|
|
471
|
-
if (this.currentView() === 'language') {
|
|
472
|
-
this.animateViewTransition('main');
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/**
|
|
477
|
-
* Confirm language selection and dismiss
|
|
478
|
-
*/
|
|
479
|
-
confirmLanguageSelection(): void {
|
|
480
|
-
if (this.hasLanguageChanged()) {
|
|
481
|
-
this.modalController.dismiss({ action: `language:${this.selectedLanguage()}` } as ActionResult, 'select');
|
|
482
|
-
} else {
|
|
483
|
-
// If no change, just go back
|
|
484
|
-
this.navigateBack();
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Handle language selection (update selection, don't dismiss)
|
|
490
|
-
*/
|
|
491
|
-
selectLanguage(languageCode: string): void {
|
|
492
|
-
this.selectedLanguage.set(languageCode);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/**
|
|
496
|
-
* Get current language flag icon
|
|
497
|
-
*/
|
|
498
|
-
getCurrentLanguageFlag(): string {
|
|
499
|
-
const language = this.availableLanguages.find((lang) => lang.code === this.currentLanguage);
|
|
500
|
-
return language?.flagIcon || '';
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Update container height based on active view
|
|
505
|
-
*/
|
|
506
|
-
private updateHeight(): void {
|
|
507
|
-
if (!this.viewContainer || !this.sheetWrapper) return;
|
|
508
|
-
|
|
509
|
-
const container = this.viewContainer.nativeElement;
|
|
510
|
-
const activeView = this.currentView() === 'main' ? container.querySelector('.main-view') : container.querySelector('.language-view');
|
|
511
|
-
|
|
512
|
-
if (activeView instanceof HTMLElement) {
|
|
513
|
-
const height = activeView.scrollHeight;
|
|
514
|
-
this.containerHeight.set(height);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
/**
|
|
519
|
-
* Animate view transition with height change
|
|
520
|
-
*/
|
|
521
|
-
private async animateViewTransition(toView: 'main' | 'language'): Promise<void> {
|
|
522
|
-
if (!this.viewContainer || !this.sheetWrapper || this.isAnimating()) return;
|
|
523
|
-
|
|
524
|
-
this.isAnimating.set(true);
|
|
525
|
-
|
|
526
|
-
const container = this.viewContainer.nativeElement;
|
|
527
|
-
|
|
528
|
-
// Step 1: Fade out current view (150ms)
|
|
529
|
-
container.style.opacity = '0';
|
|
530
|
-
|
|
531
|
-
await this.delay(150);
|
|
532
|
-
|
|
533
|
-
// Step 2: Measure target view height
|
|
534
|
-
// We need to temporarily position it to measure accurately
|
|
535
|
-
const mainView = container.querySelector('.main-view') as HTMLElement;
|
|
536
|
-
const langView = container.querySelector('.language-view') as HTMLElement;
|
|
537
|
-
const targetView = toView === 'main' ? mainView : langView;
|
|
538
|
-
|
|
539
|
-
// Temporarily make both views absolute positioned at same location to measure
|
|
540
|
-
const containerStyle = window.getComputedStyle(container);
|
|
541
|
-
const currentHeight = container.offsetHeight;
|
|
542
|
-
|
|
543
|
-
// Save current state
|
|
544
|
-
const savedTransition = container.style.transition;
|
|
545
|
-
const savedTransform = container.style.transform;
|
|
546
|
-
|
|
547
|
-
// Disable transitions and position target view for measurement
|
|
548
|
-
container.style.transition = 'none';
|
|
549
|
-
container.style.height = `${currentHeight}px`;
|
|
550
|
-
|
|
551
|
-
// Position target view to measure it
|
|
552
|
-
if (mainView && langView) {
|
|
553
|
-
mainView.style.position = 'absolute';
|
|
554
|
-
mainView.style.left = '0';
|
|
555
|
-
mainView.style.top = '0';
|
|
556
|
-
mainView.style.width = '50%';
|
|
557
|
-
mainView.style.visibility = toView === 'main' ? 'visible' : 'hidden';
|
|
558
|
-
|
|
559
|
-
langView.style.position = 'absolute';
|
|
560
|
-
langView.style.left = '0';
|
|
561
|
-
langView.style.top = '0';
|
|
562
|
-
langView.style.width = '50%';
|
|
563
|
-
langView.style.visibility = toView === 'language' ? 'visible' : 'hidden';
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// Force reflow and measure
|
|
567
|
-
container.offsetHeight;
|
|
568
|
-
const newHeight = targetView ? targetView.scrollHeight : currentHeight;
|
|
569
|
-
|
|
570
|
-
// Restore grid layout
|
|
571
|
-
if (mainView && langView) {
|
|
572
|
-
mainView.style.position = '';
|
|
573
|
-
mainView.style.left = '';
|
|
574
|
-
mainView.style.top = '';
|
|
575
|
-
mainView.style.width = '';
|
|
576
|
-
mainView.style.visibility = '';
|
|
577
|
-
|
|
578
|
-
langView.style.position = '';
|
|
579
|
-
langView.style.left = '';
|
|
580
|
-
langView.style.top = '';
|
|
581
|
-
langView.style.width = '';
|
|
582
|
-
langView.style.visibility = '';
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
// Wait a frame
|
|
586
|
-
await this.delay(10);
|
|
587
|
-
|
|
588
|
-
// Step 3: Re-enable transitions, switch view, and set new height
|
|
589
|
-
container.style.transition = savedTransition || '';
|
|
590
|
-
this.currentView.set(toView);
|
|
591
|
-
this.containerHeight.set(newHeight);
|
|
592
|
-
|
|
593
|
-
// Step 4: Wait for height animation (300ms) then fade in
|
|
594
|
-
await this.delay(250);
|
|
595
|
-
container.style.opacity = '1';
|
|
596
|
-
|
|
597
|
-
await this.delay(150);
|
|
598
|
-
this.isAnimating.set(false);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
/**
|
|
602
|
-
* Helper to create delay promise
|
|
603
|
-
*/
|
|
604
|
-
private delay(ms: number): Promise<void> {
|
|
605
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
/**
|
|
609
|
-
* Handle regular action selection
|
|
610
|
-
*/
|
|
611
|
-
selectAction(action: string): void {
|
|
612
|
-
this.modalController.dismiss({ action } as ActionResult, 'select');
|
|
613
|
-
}
|
|
614
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export * from './ds-mobile-actions-bottom-sheet';
|
|
2
|
-
export * from './ds-mobile-bottom-sheet.service';
|
|
3
|
-
export * from './ds-mobile-bottom-sheet-wrapper';
|
|
4
|
-
export * from './ds-mobile-bottom-sheet-header';
|
|
5
|
-
export * from './ds-mobile-confirmation-sheet';
|
|
6
|
-
export * from './ds-mobile-post-create-bottom-sheet';
|
|
7
|
-
export { DsMobileProfileActionsSheetComponent } from './ds-mobile-profile-actions-sheet';
|
|
8
|
-
export type { Language } from './ds-mobile-profile-actions-sheet';
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Disable pointer events for Ionic's internal modal shadow layer.
|
|
3
|
-
*
|
|
4
|
-
* The .modal-shadow element is rendered inside ion-modal's Shadow DOM and can
|
|
5
|
-
* intercept backdrop taps even when visually hidden.
|
|
6
|
-
*/
|
|
7
|
-
export function disableModalShadowPointerEvents(modal: HTMLIonModalElement): void {
|
|
8
|
-
const applyFix = () => {
|
|
9
|
-
const modalShadow = modal.shadowRoot?.querySelector<HTMLElement>('.modal-shadow');
|
|
10
|
-
if (!modalShadow) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
modalShadow.style.setProperty('pointer-events', 'none', 'important');
|
|
15
|
-
modalShadow.style.setProperty('box-shadow', 'none', 'important');
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
applyFix();
|
|
19
|
-
|
|
20
|
-
if (!modal.shadowRoot) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const observer = new MutationObserver(() => {
|
|
25
|
-
applyFix();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
observer.observe(modal.shadowRoot, {
|
|
29
|
-
childList: true,
|
|
30
|
-
subtree: true,
|
|
31
|
-
attributes: true,
|
|
32
|
-
attributeFilter: ['class', 'style'],
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
modal.addEventListener(
|
|
36
|
-
'ionModalDidDismiss',
|
|
37
|
-
() => {
|
|
38
|
-
observer.disconnect();
|
|
39
|
-
},
|
|
40
|
-
{ once: true }
|
|
41
|
-
);
|
|
42
|
-
}
|