@propbinder/mobile-design 0.2.36 → 0.2.40
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 +817 -446
- package/fesm2022/propbinder-mobile-design.mjs.map +1 -1
- package/index.d.ts +119 -18
- package/package.json +1 -1
|
@@ -5,16 +5,17 @@ import { CommonModule, isPlatformBrowser } from '@angular/common';
|
|
|
5
5
|
import * as i1$4 from '@angular/router';
|
|
6
6
|
import { Router, NavigationEnd } from '@angular/router';
|
|
7
7
|
import * as i1 from '@ionic/angular/standalone';
|
|
8
|
-
import { ModalController, IonHeader, IonToolbar, IonTitle, IonButtons, IonContent, Platform, IonRefresher, IonRefresherContent, IonPopover, IonTabBar, IonTabButton, IonLabel, IonTabs, IonTab, IonSpinner, IonInfiniteScroll, IonInfiniteScrollContent } from '@ionic/angular/standalone';
|
|
8
|
+
import { ModalController, IonHeader, IonToolbar, IonTitle, IonButtons, IonContent, Platform, IonRefresher, IonRefresherContent, IonPopover, IonTabBar, IonTabButton, IonLabel, IonTabs, IonTab, IonSpinner, IonPicker, IonPickerColumn, IonPickerColumnOption, IonInfiniteScroll, IonInfiniteScrollContent } from '@ionic/angular/standalone';
|
|
9
9
|
import { ImpactStyle, Haptics } from '@capacitor/haptics';
|
|
10
|
-
import { DsIconButtonComponent, DsIconComponent, DsButtonComponent, DsAvatarComponent, DsShapeIndicatorComponent, DsTextareaComponent, DsCheckboxComponent, DsInputTimeComponent, DsLabelComponent, DsInputComponent, DsBadgeComponent } from '@propbinder/design-system';
|
|
10
|
+
import { DsIconButtonComponent, DsIconComponent, DsButtonComponent, DsAvatarComponent, DsShapeIndicatorComponent, DsTextareaComponent, DsDatepickerComponent, DsCheckboxComponent, DsInputTimeComponent, DsLabelComponent, DsInputComponent, DsBadgeComponent } from '@propbinder/design-system';
|
|
11
11
|
import { StatusBar, Style } from '@capacitor/status-bar';
|
|
12
12
|
import { Network } from '@capacitor/network';
|
|
13
13
|
import { Keyboard } from '@capacitor/keyboard';
|
|
14
14
|
import * as i1$1 from '@angular/platform-browser';
|
|
15
15
|
import * as i1$3 from '@angular/forms';
|
|
16
16
|
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
17
|
-
import {
|
|
17
|
+
import { Capacitor } from '@capacitor/core';
|
|
18
|
+
import { FilePicker } from '@capawesome/capacitor-file-picker';
|
|
18
19
|
import { Subject } from 'rxjs';
|
|
19
20
|
import { createAnimation } from '@ionic/core';
|
|
20
21
|
import { filter } from 'rxjs/operators';
|
|
@@ -23,7 +24,7 @@ import { Pagination } from 'swiper/modules';
|
|
|
23
24
|
import { Share } from '@capacitor/share';
|
|
24
25
|
import { Filesystem, Directory } from '@capacitor/filesystem';
|
|
25
26
|
import { Browser } from '@capacitor/browser';
|
|
26
|
-
import {
|
|
27
|
+
import { AppTrackingTransparency } from 'capacitor-plugin-app-tracking-transparency';
|
|
27
28
|
|
|
28
29
|
const DEFAULT_CONFIG = {
|
|
29
30
|
logoUrl: '/Assets/logos/propbinder-logomark.svg',
|
|
@@ -2498,17 +2499,18 @@ class DsMobilePostCreateBottomSheetComponent {
|
|
|
2498
2499
|
this.applySafeAreaToToolbar();
|
|
2499
2500
|
try {
|
|
2500
2501
|
console.log('Requesting photo from library...');
|
|
2501
|
-
const
|
|
2502
|
-
|
|
2503
|
-
allowEditing: false,
|
|
2504
|
-
resultType: CameraResultType.Uri,
|
|
2505
|
-
source: CameraSource.Photos, // Only show photo library, not camera
|
|
2502
|
+
const result = await FilePicker.pickImages({
|
|
2503
|
+
limit: 1,
|
|
2506
2504
|
});
|
|
2505
|
+
const image = result.files?.[0];
|
|
2507
2506
|
console.log('Photo selected successfully:', image);
|
|
2508
2507
|
// Add the image path to the array
|
|
2509
|
-
if (image
|
|
2510
|
-
|
|
2511
|
-
|
|
2508
|
+
if (image) {
|
|
2509
|
+
const imageSrc = image.path ? Capacitor.convertFileSrc(image.path) : (image.blob ? URL.createObjectURL(image.blob) : '');
|
|
2510
|
+
if (imageSrc) {
|
|
2511
|
+
this.selectedImages.update(images => [...images, imageSrc]);
|
|
2512
|
+
console.log('Image added to preview:', imageSrc);
|
|
2513
|
+
}
|
|
2512
2514
|
}
|
|
2513
2515
|
// Re-apply safe area padding immediately after returning
|
|
2514
2516
|
// Since we're using fixed values, this won't cause flickering
|
|
@@ -5726,6 +5728,7 @@ class DsMobileSectionComponent {
|
|
|
5726
5728
|
<ds-icon name="remixArrowRightSLine" size="16px" />
|
|
5727
5729
|
</a>
|
|
5728
5730
|
}
|
|
5731
|
+
<ng-content select="[header-action]" />
|
|
5729
5732
|
</header>
|
|
5730
5733
|
}
|
|
5731
5734
|
|
|
@@ -5757,6 +5760,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5757
5760
|
<ds-icon name="remixArrowRightSLine" size="16px" />
|
|
5758
5761
|
</a>
|
|
5759
5762
|
}
|
|
5763
|
+
<ng-content select="[header-action]" />
|
|
5760
5764
|
</header>
|
|
5761
5765
|
}
|
|
5762
5766
|
|
|
@@ -6862,9 +6866,15 @@ class DsMobileDropdownComponent {
|
|
|
6862
6866
|
});
|
|
6863
6867
|
}
|
|
6864
6868
|
/**
|
|
6865
|
-
* Content projection for custom item template
|
|
6869
|
+
* Content projection for custom item template (per-item renderer)
|
|
6866
6870
|
*/
|
|
6867
6871
|
customItemTemplate;
|
|
6872
|
+
/**
|
|
6873
|
+
* Content projection for fully custom popover content.
|
|
6874
|
+
* When provided, the item list is bypassed entirely and this template
|
|
6875
|
+
* is rendered directly inside the popover — use for pickers, forms, etc.
|
|
6876
|
+
*/
|
|
6877
|
+
customContent;
|
|
6868
6878
|
/**
|
|
6869
6879
|
* Optional trigger element ID for Ionic Popover positioning
|
|
6870
6880
|
*/
|
|
@@ -6875,9 +6885,10 @@ class DsMobileDropdownComponent {
|
|
|
6875
6885
|
*/
|
|
6876
6886
|
keepFocusOn = input(...(ngDevMode ? [undefined, { debugName: "keepFocusOn" }] : []));
|
|
6877
6887
|
/**
|
|
6878
|
-
* Array of dropdown items to display
|
|
6888
|
+
* Array of dropdown items to display.
|
|
6889
|
+
* Not required when using the #customContent slot.
|
|
6879
6890
|
*/
|
|
6880
|
-
items = input
|
|
6891
|
+
items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
6881
6892
|
/**
|
|
6882
6893
|
* Whether the dropdown is open
|
|
6883
6894
|
*/
|
|
@@ -6906,6 +6917,12 @@ class DsMobileDropdownComponent {
|
|
|
6906
6917
|
* ARIA label for the dropdown menu
|
|
6907
6918
|
*/
|
|
6908
6919
|
ariaLabel = input('Dropdown menu', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
6920
|
+
/**
|
|
6921
|
+
* Maximum width of the popover.
|
|
6922
|
+
* Defaults to '192px' (standard dropdown width).
|
|
6923
|
+
* Override when using #customContent that requires more space (e.g. '280px' for a picker).
|
|
6924
|
+
*/
|
|
6925
|
+
maxWidth = input('192px', ...(ngDevMode ? [{ debugName: "maxWidth" }] : []));
|
|
6909
6926
|
/**
|
|
6910
6927
|
* Emits when an item is selected
|
|
6911
6928
|
*/
|
|
@@ -6967,7 +6984,7 @@ class DsMobileDropdownComponent {
|
|
|
6967
6984
|
this.itemSelected.emit(item);
|
|
6968
6985
|
}
|
|
6969
6986
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6970
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileDropdownComponent, isStandalone: true, selector: "ds-mobile-dropdown", inputs: { trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, keepFocusOn: { classPropertyName: "keepFocusOn", publicName: "keepFocusOn", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired:
|
|
6987
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileDropdownComponent, isStandalone: true, selector: "ds-mobile-dropdown", inputs: { trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, keepFocusOn: { classPropertyName: "keepFocusOn", publicName: "keepFocusOn", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelected: "itemSelected", closed: "closed" }, queries: [{ propertyName: "customItemTemplate", first: true, predicate: ["itemTemplate"], descendants: true }, { propertyName: "customContent", first: true, predicate: ["customContent"], descendants: true }], ngImport: i0, template: `
|
|
6971
6988
|
<ion-popover
|
|
6972
6989
|
[isOpen]="isOpen()"
|
|
6973
6990
|
[trigger]="trigger()"
|
|
@@ -6981,71 +6998,77 @@ class DsMobileDropdownComponent {
|
|
|
6981
6998
|
(didDismiss)="closed.emit()"
|
|
6982
6999
|
[style.--offset-y]="offsetY()"
|
|
6983
7000
|
[style.--offset-x]="offsetX()"
|
|
6984
|
-
[style.--max-width]="
|
|
7001
|
+
[style.--max-width]="maxWidth()"
|
|
6985
7002
|
[style.--background]="'transparent'"
|
|
6986
7003
|
[style.--box-shadow]="'none'"
|
|
6987
7004
|
[style.--backdrop-opacity]="'0'">
|
|
6988
7005
|
|
|
6989
7006
|
<ng-template>
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7007
|
+
@if (customContent) {
|
|
7008
|
+
<!-- Fully custom popover content (e.g. picker, form) -->
|
|
7009
|
+
<ng-container *ngTemplateOutlet="customContent" />
|
|
7010
|
+
} @else {
|
|
7011
|
+
<!-- Standard item list -->
|
|
7012
|
+
<div
|
|
7013
|
+
[class]="dropdownClasses()"
|
|
7014
|
+
[style.max-height.px]="maxHeight()"
|
|
7015
|
+
(mousedown)="$event.stopPropagation()"
|
|
7016
|
+
(click)="$event.stopPropagation()"
|
|
7017
|
+
role="menu"
|
|
7018
|
+
[attr.aria-label]="ariaLabel()">
|
|
7019
|
+
|
|
7020
|
+
@if (customItemTemplate) {
|
|
7021
|
+
<!-- Custom template for each item -->
|
|
7022
|
+
@for (item of items(); track item.id) {
|
|
7023
|
+
<div
|
|
7024
|
+
[class]="getItemClass(item)"
|
|
7025
|
+
[attr.data-disabled]="item.disabled ? '' : null"
|
|
7026
|
+
[attr.aria-disabled]="item.disabled"
|
|
7027
|
+
(mousedown)="handleItemClick(item, $event)"
|
|
7028
|
+
role="menuitem">
|
|
7029
|
+
<ng-container
|
|
7030
|
+
*ngTemplateOutlet="customItemTemplate; context: { $implicit: item }" />
|
|
7031
|
+
</div>
|
|
7032
|
+
}
|
|
7033
|
+
} @else {
|
|
7034
|
+
<!-- Default three-slot template: leading - main - trailing -->
|
|
7035
|
+
@for (item of items(); track item.id) {
|
|
7036
|
+
<div
|
|
7037
|
+
[class]="getItemClass(item)"
|
|
7038
|
+
[attr.data-disabled]="item.disabled ? '' : null"
|
|
7039
|
+
[attr.aria-disabled]="item.disabled"
|
|
7040
|
+
(mousedown)="handleItemClick(item, $event)"
|
|
7041
|
+
role="menuitem">
|
|
7042
|
+
|
|
7043
|
+
<!-- Leading slot -->
|
|
7044
|
+
@if (item.leadingIcon) {
|
|
7045
|
+
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--leading">
|
|
7046
|
+
<ds-icon [name]="item.leadingIcon" size="16px" />
|
|
7047
|
+
</div>
|
|
7048
|
+
}
|
|
7049
|
+
|
|
7050
|
+
<!-- Main slot -->
|
|
7051
|
+
@if (item.label) {
|
|
7052
|
+
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--main">
|
|
7053
|
+
<span class="ds-mobile-dropdown__label">{{ item.label }}</span>
|
|
7054
|
+
</div>
|
|
7055
|
+
}
|
|
7056
|
+
|
|
7057
|
+
<!-- Trailing slot -->
|
|
7058
|
+
@if (item.trailingIcon) {
|
|
7059
|
+
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--trailing">
|
|
7060
|
+
<ds-icon [name]="item.trailingIcon" size="20px" />
|
|
7061
|
+
</div>
|
|
7062
|
+
}
|
|
7063
|
+
</div>
|
|
7064
|
+
}
|
|
7010
7065
|
}
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
<div
|
|
7015
|
-
[class]="getItemClass(item)"
|
|
7016
|
-
[attr.data-disabled]="item.disabled ? '' : null"
|
|
7017
|
-
[attr.aria-disabled]="item.disabled"
|
|
7018
|
-
(mousedown)="handleItemClick(item, $event)"
|
|
7019
|
-
role="menuitem">
|
|
7020
|
-
|
|
7021
|
-
<!-- Leading slot -->
|
|
7022
|
-
@if (item.leadingIcon) {
|
|
7023
|
-
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--leading">
|
|
7024
|
-
<ds-icon [name]="item.leadingIcon" size="16px" />
|
|
7025
|
-
</div>
|
|
7026
|
-
}
|
|
7027
|
-
|
|
7028
|
-
<!-- Main slot -->
|
|
7029
|
-
@if (item.label) {
|
|
7030
|
-
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--main">
|
|
7031
|
-
<span class="ds-mobile-dropdown__label">{{ item.label }}</span>
|
|
7032
|
-
</div>
|
|
7033
|
-
}
|
|
7034
|
-
|
|
7035
|
-
<!-- Trailing slot -->
|
|
7036
|
-
@if (item.trailingIcon) {
|
|
7037
|
-
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--trailing">
|
|
7038
|
-
<ds-icon [name]="item.trailingIcon" size="20px" />
|
|
7039
|
-
</div>
|
|
7040
|
-
}
|
|
7041
|
-
</div>
|
|
7066
|
+
|
|
7067
|
+
@if (items().length === 0 && emptyMessage()) {
|
|
7068
|
+
<div class="ds-mobile-dropdown__empty">{{ emptyMessage() }}</div>
|
|
7042
7069
|
}
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
@if (items().length === 0 && emptyMessage()) {
|
|
7046
|
-
<div class="ds-mobile-dropdown__empty">{{ emptyMessage() }}</div>
|
|
7047
|
-
}
|
|
7048
|
-
</div>
|
|
7070
|
+
</div>
|
|
7071
|
+
}
|
|
7049
7072
|
</ng-template>
|
|
7050
7073
|
</ion-popover>
|
|
7051
7074
|
`, isInline: true, styles: ["ion-popover{--background: transparent;--box-shadow: none;--backdrop-opacity: 0;--max-width: 192px}ion-popover::part(content){background:#ffffff80!important;backdrop-filter:blur(12px)!important;-webkit-backdrop-filter:blur(12px)!important;box-shadow:0 2px 8px #00000014,0 4px 16px #0000001f!important;border:1px solid rgba(255,255,255,1)!important;border-radius:16px!important;padding:4px!important;outline:none!important;max-width:192px!important}ion-popover::part(backdrop){background:transparent!important}.ds-mobile-dropdown{position:relative;width:100%;background:transparent!important;border:none!important;box-shadow:none!important;overflow-y:auto;animation:slideIn var(--spring-duration-medium) var(--spring-curve-bouncy);padding:0}.ds-mobile-dropdown__item{display:flex;align-items:center;gap:12px;padding:4px 12px;background:none;width:100%;text-align:left;cursor:pointer;transition:background .15s ease;min-height:40px;justify-content:flex-start;border-radius:14px}.ds-mobile-dropdown__item:last-child{border-bottom:none}.ds-mobile-dropdown__item:hover:not(.ds-mobile-dropdown__item--disabled){background:#0000000a}.ds-mobile-dropdown__item:active:not(.ds-mobile-dropdown__item--disabled){background:#00000014;transition:background 0s}.ds-mobile-dropdown__item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ds-mobile-dropdown__slot{display:flex;align-items:center}.ds-mobile-dropdown__slot--leading{flex-shrink:0;justify-content:center}.ds-mobile-dropdown__slot--main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;text-align:left;align-items:flex-start}.ds-mobile-dropdown__slot--trailing{flex-shrink:0;margin-left:auto}.ds-mobile-dropdown__label{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;line-height:20px;color:var(--color-text-primary, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:left}.ds-mobile-dropdown__empty{padding:24px 16px;text-align:center;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373)}@keyframes slideIn{0%{opacity:0;transform:translateY(8px) scale(.75)}to{opacity:1;transform:translateY(0) scale(1)}}.ds-mobile-dropdown--above{animation:slideUp var(--spring-duration-medium) var(--spring-curve-bouncy)}@keyframes slideOut{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(8px) scale(.75)}}@keyframes slideDown{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(-8px) scale(.75)}}@keyframes slideUp{0%{opacity:0;transform:translateY(-8px) scale(.75)}to{opacity:1;transform:translateY(0) scale(1)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: IonPopover, selector: "ion-popover" }] });
|
|
@@ -7066,78 +7089,87 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
7066
7089
|
(didDismiss)="closed.emit()"
|
|
7067
7090
|
[style.--offset-y]="offsetY()"
|
|
7068
7091
|
[style.--offset-x]="offsetX()"
|
|
7069
|
-
[style.--max-width]="
|
|
7092
|
+
[style.--max-width]="maxWidth()"
|
|
7070
7093
|
[style.--background]="'transparent'"
|
|
7071
7094
|
[style.--box-shadow]="'none'"
|
|
7072
7095
|
[style.--backdrop-opacity]="'0'">
|
|
7073
7096
|
|
|
7074
7097
|
<ng-template>
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7098
|
+
@if (customContent) {
|
|
7099
|
+
<!-- Fully custom popover content (e.g. picker, form) -->
|
|
7100
|
+
<ng-container *ngTemplateOutlet="customContent" />
|
|
7101
|
+
} @else {
|
|
7102
|
+
<!-- Standard item list -->
|
|
7103
|
+
<div
|
|
7104
|
+
[class]="dropdownClasses()"
|
|
7105
|
+
[style.max-height.px]="maxHeight()"
|
|
7106
|
+
(mousedown)="$event.stopPropagation()"
|
|
7107
|
+
(click)="$event.stopPropagation()"
|
|
7108
|
+
role="menu"
|
|
7109
|
+
[attr.aria-label]="ariaLabel()">
|
|
7110
|
+
|
|
7111
|
+
@if (customItemTemplate) {
|
|
7112
|
+
<!-- Custom template for each item -->
|
|
7113
|
+
@for (item of items(); track item.id) {
|
|
7114
|
+
<div
|
|
7115
|
+
[class]="getItemClass(item)"
|
|
7116
|
+
[attr.data-disabled]="item.disabled ? '' : null"
|
|
7117
|
+
[attr.aria-disabled]="item.disabled"
|
|
7118
|
+
(mousedown)="handleItemClick(item, $event)"
|
|
7119
|
+
role="menuitem">
|
|
7120
|
+
<ng-container
|
|
7121
|
+
*ngTemplateOutlet="customItemTemplate; context: { $implicit: item }" />
|
|
7122
|
+
</div>
|
|
7123
|
+
}
|
|
7124
|
+
} @else {
|
|
7125
|
+
<!-- Default three-slot template: leading - main - trailing -->
|
|
7126
|
+
@for (item of items(); track item.id) {
|
|
7127
|
+
<div
|
|
7128
|
+
[class]="getItemClass(item)"
|
|
7129
|
+
[attr.data-disabled]="item.disabled ? '' : null"
|
|
7130
|
+
[attr.aria-disabled]="item.disabled"
|
|
7131
|
+
(mousedown)="handleItemClick(item, $event)"
|
|
7132
|
+
role="menuitem">
|
|
7133
|
+
|
|
7134
|
+
<!-- Leading slot -->
|
|
7135
|
+
@if (item.leadingIcon) {
|
|
7136
|
+
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--leading">
|
|
7137
|
+
<ds-icon [name]="item.leadingIcon" size="16px" />
|
|
7138
|
+
</div>
|
|
7139
|
+
}
|
|
7140
|
+
|
|
7141
|
+
<!-- Main slot -->
|
|
7142
|
+
@if (item.label) {
|
|
7143
|
+
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--main">
|
|
7144
|
+
<span class="ds-mobile-dropdown__label">{{ item.label }}</span>
|
|
7145
|
+
</div>
|
|
7146
|
+
}
|
|
7147
|
+
|
|
7148
|
+
<!-- Trailing slot -->
|
|
7149
|
+
@if (item.trailingIcon) {
|
|
7150
|
+
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--trailing">
|
|
7151
|
+
<ds-icon [name]="item.trailingIcon" size="20px" />
|
|
7152
|
+
</div>
|
|
7153
|
+
}
|
|
7154
|
+
</div>
|
|
7155
|
+
}
|
|
7095
7156
|
}
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
<div
|
|
7100
|
-
[class]="getItemClass(item)"
|
|
7101
|
-
[attr.data-disabled]="item.disabled ? '' : null"
|
|
7102
|
-
[attr.aria-disabled]="item.disabled"
|
|
7103
|
-
(mousedown)="handleItemClick(item, $event)"
|
|
7104
|
-
role="menuitem">
|
|
7105
|
-
|
|
7106
|
-
<!-- Leading slot -->
|
|
7107
|
-
@if (item.leadingIcon) {
|
|
7108
|
-
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--leading">
|
|
7109
|
-
<ds-icon [name]="item.leadingIcon" size="16px" />
|
|
7110
|
-
</div>
|
|
7111
|
-
}
|
|
7112
|
-
|
|
7113
|
-
<!-- Main slot -->
|
|
7114
|
-
@if (item.label) {
|
|
7115
|
-
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--main">
|
|
7116
|
-
<span class="ds-mobile-dropdown__label">{{ item.label }}</span>
|
|
7117
|
-
</div>
|
|
7118
|
-
}
|
|
7119
|
-
|
|
7120
|
-
<!-- Trailing slot -->
|
|
7121
|
-
@if (item.trailingIcon) {
|
|
7122
|
-
<div class="ds-mobile-dropdown__slot ds-mobile-dropdown__slot--trailing">
|
|
7123
|
-
<ds-icon [name]="item.trailingIcon" size="20px" />
|
|
7124
|
-
</div>
|
|
7125
|
-
}
|
|
7126
|
-
</div>
|
|
7157
|
+
|
|
7158
|
+
@if (items().length === 0 && emptyMessage()) {
|
|
7159
|
+
<div class="ds-mobile-dropdown__empty">{{ emptyMessage() }}</div>
|
|
7127
7160
|
}
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
@if (items().length === 0 && emptyMessage()) {
|
|
7131
|
-
<div class="ds-mobile-dropdown__empty">{{ emptyMessage() }}</div>
|
|
7132
|
-
}
|
|
7133
|
-
</div>
|
|
7161
|
+
</div>
|
|
7162
|
+
}
|
|
7134
7163
|
</ng-template>
|
|
7135
7164
|
</ion-popover>
|
|
7136
7165
|
`, styles: ["ion-popover{--background: transparent;--box-shadow: none;--backdrop-opacity: 0;--max-width: 192px}ion-popover::part(content){background:#ffffff80!important;backdrop-filter:blur(12px)!important;-webkit-backdrop-filter:blur(12px)!important;box-shadow:0 2px 8px #00000014,0 4px 16px #0000001f!important;border:1px solid rgba(255,255,255,1)!important;border-radius:16px!important;padding:4px!important;outline:none!important;max-width:192px!important}ion-popover::part(backdrop){background:transparent!important}.ds-mobile-dropdown{position:relative;width:100%;background:transparent!important;border:none!important;box-shadow:none!important;overflow-y:auto;animation:slideIn var(--spring-duration-medium) var(--spring-curve-bouncy);padding:0}.ds-mobile-dropdown__item{display:flex;align-items:center;gap:12px;padding:4px 12px;background:none;width:100%;text-align:left;cursor:pointer;transition:background .15s ease;min-height:40px;justify-content:flex-start;border-radius:14px}.ds-mobile-dropdown__item:last-child{border-bottom:none}.ds-mobile-dropdown__item:hover:not(.ds-mobile-dropdown__item--disabled){background:#0000000a}.ds-mobile-dropdown__item:active:not(.ds-mobile-dropdown__item--disabled){background:#00000014;transition:background 0s}.ds-mobile-dropdown__item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ds-mobile-dropdown__slot{display:flex;align-items:center}.ds-mobile-dropdown__slot--leading{flex-shrink:0;justify-content:center}.ds-mobile-dropdown__slot--main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;text-align:left;align-items:flex-start}.ds-mobile-dropdown__slot--trailing{flex-shrink:0;margin-left:auto}.ds-mobile-dropdown__label{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;line-height:20px;color:var(--color-text-primary, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:left}.ds-mobile-dropdown__empty{padding:24px 16px;text-align:center;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373)}@keyframes slideIn{0%{opacity:0;transform:translateY(8px) scale(.75)}to{opacity:1;transform:translateY(0) scale(1)}}.ds-mobile-dropdown--above{animation:slideUp var(--spring-duration-medium) var(--spring-curve-bouncy)}@keyframes slideOut{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(8px) scale(.75)}}@keyframes slideDown{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(-8px) scale(.75)}}@keyframes slideUp{0%{opacity:0;transform:translateY(-8px) scale(.75)}to{opacity:1;transform:translateY(0) scale(1)}}\n"] }]
|
|
7137
7166
|
}], ctorParameters: () => [], propDecorators: { customItemTemplate: [{
|
|
7138
7167
|
type: ContentChild,
|
|
7139
7168
|
args: ['itemTemplate']
|
|
7140
|
-
}],
|
|
7169
|
+
}], customContent: [{
|
|
7170
|
+
type: ContentChild,
|
|
7171
|
+
args: ['customContent']
|
|
7172
|
+
}], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], keepFocusOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepFocusOn", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
7141
7173
|
|
|
7142
7174
|
/**
|
|
7143
7175
|
* DsMobileMessageComposerComponent
|
|
@@ -7164,6 +7196,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
7164
7196
|
* ```
|
|
7165
7197
|
*/
|
|
7166
7198
|
class DsMobileMessageComposerComponent {
|
|
7199
|
+
cdr;
|
|
7200
|
+
constructor(cdr) {
|
|
7201
|
+
this.cdr = cdr;
|
|
7202
|
+
}
|
|
7167
7203
|
/**
|
|
7168
7204
|
* Avatar initials
|
|
7169
7205
|
*/
|
|
@@ -7258,41 +7294,40 @@ class DsMobileMessageComposerComponent {
|
|
|
7258
7294
|
const users = this.mentionUsers();
|
|
7259
7295
|
if (!query)
|
|
7260
7296
|
return users;
|
|
7261
|
-
return users.filter(user => user.name.toLowerCase().includes(query));
|
|
7297
|
+
return users.filter((user) => user.name.toLowerCase().includes(query));
|
|
7262
7298
|
}, ...(ngDevMode ? [{ debugName: "filteredUsers" }] : []));
|
|
7263
7299
|
/**
|
|
7264
7300
|
* Convert filtered users to dropdown items
|
|
7265
7301
|
*/
|
|
7266
7302
|
mentionDropdownItems = computed(() => {
|
|
7267
|
-
return this.filteredUsers().map(user => ({
|
|
7303
|
+
return this.filteredUsers().map((user) => ({
|
|
7268
7304
|
id: user.name,
|
|
7269
7305
|
label: user.name,
|
|
7270
7306
|
data: {
|
|
7271
7307
|
name: user.name,
|
|
7272
7308
|
initials: user.initials,
|
|
7273
|
-
role: user.role
|
|
7274
|
-
}
|
|
7309
|
+
role: user.role,
|
|
7310
|
+
},
|
|
7275
7311
|
}));
|
|
7276
7312
|
}, ...(ngDevMode ? [{ debugName: "mentionDropdownItems" }] : []));
|
|
7277
7313
|
/**
|
|
7278
7314
|
* Attachment menu items
|
|
7315
|
+
* Static list to prevent change detection loops
|
|
7279
7316
|
*/
|
|
7280
|
-
attachmentMenuItems =
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
];
|
|
7295
|
-
}, ...(ngDevMode ? [{ debugName: "attachmentMenuItems" }] : []));
|
|
7317
|
+
attachmentMenuItems = [
|
|
7318
|
+
{
|
|
7319
|
+
id: 'photo',
|
|
7320
|
+
leadingIcon: 'remixImageLine',
|
|
7321
|
+
label: 'Photo',
|
|
7322
|
+
action: () => this.handleAddPhoto(),
|
|
7323
|
+
},
|
|
7324
|
+
{
|
|
7325
|
+
id: 'file',
|
|
7326
|
+
leadingIcon: 'remixFile3Line',
|
|
7327
|
+
label: 'File',
|
|
7328
|
+
action: () => this.handleAddFile(),
|
|
7329
|
+
},
|
|
7330
|
+
];
|
|
7296
7331
|
/**
|
|
7297
7332
|
* Emits when a message is sent
|
|
7298
7333
|
*/
|
|
@@ -7328,6 +7363,8 @@ class DsMobileMessageComposerComponent {
|
|
|
7328
7363
|
}
|
|
7329
7364
|
// Set up keyboard listeners
|
|
7330
7365
|
this.setupKeyboardListeners();
|
|
7366
|
+
// Explicitly trigger change detection to avoid NG0100 with ViewChild bindings
|
|
7367
|
+
this.cdr.detectChanges();
|
|
7331
7368
|
}
|
|
7332
7369
|
ngOnDestroy() {
|
|
7333
7370
|
// Clean up keyboard listeners
|
|
@@ -7339,22 +7376,22 @@ class DsMobileMessageComposerComponent {
|
|
|
7339
7376
|
setupKeyboardListeners() {
|
|
7340
7377
|
Keyboard.addListener('keyboardWillShow', (info) => {
|
|
7341
7378
|
document.documentElement.style.setProperty('--keyboard-height', `${info.keyboardHeight}px`);
|
|
7342
|
-
}).catch(
|
|
7379
|
+
}).catch(() => { });
|
|
7343
7380
|
Keyboard.addListener('keyboardWillHide', () => {
|
|
7344
7381
|
document.documentElement.style.setProperty('--keyboard-height', '0px');
|
|
7345
|
-
}).catch(
|
|
7382
|
+
}).catch(() => { });
|
|
7346
7383
|
}
|
|
7347
7384
|
/**
|
|
7348
7385
|
* Clean up keyboard event listeners
|
|
7349
7386
|
*/
|
|
7350
7387
|
cleanupKeyboardListeners() {
|
|
7351
|
-
Keyboard.removeAllListeners().catch(
|
|
7388
|
+
Keyboard.removeAllListeners().catch(() => { });
|
|
7352
7389
|
}
|
|
7353
7390
|
/**
|
|
7354
7391
|
* Show the keyboard when user interacts with input
|
|
7355
7392
|
*/
|
|
7356
7393
|
showKeyboard() {
|
|
7357
|
-
Keyboard.show().catch(
|
|
7394
|
+
Keyboard.show().catch(() => { });
|
|
7358
7395
|
}
|
|
7359
7396
|
/**
|
|
7360
7397
|
* Handle keyboard shortcuts (Shift+Enter to send)
|
|
@@ -7527,7 +7564,7 @@ class DsMobileMessageComposerComponent {
|
|
|
7527
7564
|
event.preventDefault();
|
|
7528
7565
|
event.stopPropagation();
|
|
7529
7566
|
}
|
|
7530
|
-
this.isAttachmentMenuOpen.update(open => !open);
|
|
7567
|
+
this.isAttachmentMenuOpen.update((open) => !open);
|
|
7531
7568
|
}
|
|
7532
7569
|
/**
|
|
7533
7570
|
* Close attachment menu
|
|
@@ -7541,7 +7578,7 @@ class DsMobileMessageComposerComponent {
|
|
|
7541
7578
|
}
|
|
7542
7579
|
/**
|
|
7543
7580
|
* Handle add photo button click from menu
|
|
7544
|
-
* Uses
|
|
7581
|
+
* Uses Capawesome File Picker API to open photo library directly
|
|
7545
7582
|
* Allows multiple photo selection
|
|
7546
7583
|
*/
|
|
7547
7584
|
async handleAddPhoto(event) {
|
|
@@ -7553,38 +7590,35 @@ class DsMobileMessageComposerComponent {
|
|
|
7553
7590
|
return;
|
|
7554
7591
|
}
|
|
7555
7592
|
try {
|
|
7556
|
-
console.log('[MessageComposer] Opening photo library');
|
|
7593
|
+
//console.log('[MessageComposer] Opening photo library');
|
|
7557
7594
|
// Calculate remaining slots
|
|
7558
7595
|
const remainingSlots = 6 - this.attachments().length;
|
|
7559
7596
|
// Open photo library with multiple selection using pickImages
|
|
7560
|
-
const result = await
|
|
7561
|
-
quality: 90,
|
|
7597
|
+
const result = await FilePicker.pickImages({
|
|
7562
7598
|
limit: remainingSlots, // Limit to remaining slots
|
|
7563
7599
|
});
|
|
7564
|
-
if (result.
|
|
7565
|
-
console.log(`[MessageComposer] ${result.
|
|
7600
|
+
if (result.files && result.files.length > 0) {
|
|
7601
|
+
//console.log(`[MessageComposer] ${result.files.length} photo(s) selected`);
|
|
7566
7602
|
// Process each selected photo
|
|
7567
|
-
for (const photo of result.
|
|
7603
|
+
for (const photo of result.files) {
|
|
7568
7604
|
const attachmentId = `photo-${Date.now()}-${Math.random()}`;
|
|
7569
7605
|
// Add attachment with loading state
|
|
7570
7606
|
const loadingAttachment = {
|
|
7571
7607
|
id: attachmentId,
|
|
7572
|
-
src: photo.
|
|
7608
|
+
src: photo.path ? Capacitor.convertFileSrc(photo.path) : (photo.blob ? URL.createObjectURL(photo.blob) : ''),
|
|
7573
7609
|
type: 'image',
|
|
7574
|
-
name:
|
|
7575
|
-
size:
|
|
7576
|
-
isLoading: true
|
|
7610
|
+
name: photo.name,
|
|
7611
|
+
size: this.formatFileSize(photo.size ?? 0),
|
|
7612
|
+
isLoading: true,
|
|
7577
7613
|
};
|
|
7578
|
-
this.attachments.update(attachments => [...attachments, loadingAttachment]);
|
|
7614
|
+
this.attachments.update((attachments) => [...attachments, loadingAttachment]);
|
|
7579
7615
|
// Simulate processing time (in real app, this would be actual image processing)
|
|
7580
7616
|
// TODO: Reduce to 300ms or remove in production
|
|
7581
7617
|
setTimeout(() => {
|
|
7582
|
-
this.attachments.update(attachments => attachments.map(a => a.id === attachmentId
|
|
7583
|
-
? { ...a, isLoading: false }
|
|
7584
|
-
: a));
|
|
7618
|
+
this.attachments.update((attachments) => attachments.map((a) => (a.id === attachmentId ? { ...a, isLoading: false } : a)));
|
|
7585
7619
|
}, 1500); // 1.5s for testing - shows loading overlay clearly
|
|
7586
7620
|
}
|
|
7587
|
-
console.log('[MessageComposer] All photos added successfully');
|
|
7621
|
+
//console.log('[MessageComposer] All photos added successfully');
|
|
7588
7622
|
// Notify parent that attachments changed so it can scroll
|
|
7589
7623
|
this.attachmentsChanged.emit();
|
|
7590
7624
|
// ResizeObserver in MobileModalBase automatically handles layout adjustments
|
|
@@ -7592,7 +7626,7 @@ class DsMobileMessageComposerComponent {
|
|
|
7592
7626
|
}
|
|
7593
7627
|
catch (error) {
|
|
7594
7628
|
if (error.message && !error.message.includes('cancel')) {
|
|
7595
|
-
console.error('[MessageComposer] Error adding photo:', error);
|
|
7629
|
+
//console.error('[MessageComposer] Error adding photo:', error);
|
|
7596
7630
|
}
|
|
7597
7631
|
// User cancelled - that's fine
|
|
7598
7632
|
}
|
|
@@ -7653,7 +7687,7 @@ class DsMobileMessageComposerComponent {
|
|
|
7653
7687
|
const k = 1024;
|
|
7654
7688
|
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
7655
7689
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
7656
|
-
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
|
|
7690
|
+
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
|
|
7657
7691
|
}
|
|
7658
7692
|
/**
|
|
7659
7693
|
* Handle file selection from file input
|
|
@@ -7668,7 +7702,7 @@ class DsMobileMessageComposerComponent {
|
|
|
7668
7702
|
// Process each selected file (up to 6 total)
|
|
7669
7703
|
const remainingSlots = 6 - this.attachments().length;
|
|
7670
7704
|
const filesToProcess = Array.from(files).slice(0, remainingSlots);
|
|
7671
|
-
filesToProcess.forEach(file => {
|
|
7705
|
+
filesToProcess.forEach((file) => {
|
|
7672
7706
|
const fileType = this.detectFileType(file);
|
|
7673
7707
|
const attachmentId = `file-${Date.now()}-${Math.random()}`;
|
|
7674
7708
|
// Add attachment with loading state immediately
|
|
@@ -7678,9 +7712,9 @@ class DsMobileMessageComposerComponent {
|
|
|
7678
7712
|
type: fileType,
|
|
7679
7713
|
name: file.name,
|
|
7680
7714
|
size: this.formatFileSize(file.size),
|
|
7681
|
-
isLoading: true
|
|
7715
|
+
isLoading: true,
|
|
7682
7716
|
};
|
|
7683
|
-
this.attachments.update(attachments => [...attachments, loadingAttachment]);
|
|
7717
|
+
this.attachments.update((attachments) => [...attachments, loadingAttachment]);
|
|
7684
7718
|
// Create a data URL for preview
|
|
7685
7719
|
const reader = new FileReader();
|
|
7686
7720
|
reader.onload = (e) => {
|
|
@@ -7690,9 +7724,7 @@ class DsMobileMessageComposerComponent {
|
|
|
7690
7724
|
// TODO: Remove setTimeout in production (use actual FileReader timing)
|
|
7691
7725
|
setTimeout(() => {
|
|
7692
7726
|
// Update attachment with actual data and remove loading state
|
|
7693
|
-
this.attachments.update(attachments => attachments.map(a => a.id === attachmentId
|
|
7694
|
-
? { ...a, src: result, isLoading: false }
|
|
7695
|
-
: a));
|
|
7727
|
+
this.attachments.update((attachments) => attachments.map((a) => (a.id === attachmentId ? { ...a, src: result, isLoading: false } : a)));
|
|
7696
7728
|
// Notify parent that attachments changed so it can scroll
|
|
7697
7729
|
setTimeout(() => {
|
|
7698
7730
|
this.attachmentsChanged.emit();
|
|
@@ -7711,12 +7743,12 @@ class DsMobileMessageComposerComponent {
|
|
|
7711
7743
|
* Keeps keyboard open by maintaining focus
|
|
7712
7744
|
*/
|
|
7713
7745
|
removeAttachment(attachmentId) {
|
|
7714
|
-
this.attachments.update(attachments => attachments.filter(a => a.id !== attachmentId));
|
|
7746
|
+
this.attachments.update((attachments) => attachments.filter((a) => a.id !== attachmentId));
|
|
7715
7747
|
// Immediately refocus input to prevent keyboard from closing
|
|
7716
7748
|
setTimeout(() => {
|
|
7717
7749
|
if (this.messageInputRef?.nativeElement) {
|
|
7718
7750
|
this.messageInputRef.nativeElement.focus();
|
|
7719
|
-
Keyboard.show().catch(e => console.log('Keyboard.show() not available:', e));
|
|
7751
|
+
Keyboard.show().catch((e) => console.log('Keyboard.show() not available:', e));
|
|
7720
7752
|
}
|
|
7721
7753
|
}, 0);
|
|
7722
7754
|
// Notify parent that attachments changed so it can scroll
|
|
@@ -7736,13 +7768,11 @@ class DsMobileMessageComposerComponent {
|
|
|
7736
7768
|
const isReply = !!this.replyingTo();
|
|
7737
7769
|
// Emit message sent event
|
|
7738
7770
|
this.messageSent.emit({
|
|
7739
|
-
content: isReply && this.replyingTo()
|
|
7740
|
-
? `@${this.replyingTo().authorName} ${text}`
|
|
7741
|
-
: text,
|
|
7771
|
+
content: isReply && this.replyingTo() ? `@${this.replyingTo().authorName} ${text}` : text,
|
|
7742
7772
|
isReply,
|
|
7743
7773
|
replyTo: this.replyingTo()?.authorName,
|
|
7744
7774
|
isEdit,
|
|
7745
|
-
attachments: hasAttachments ? [...this.attachments()] : undefined
|
|
7775
|
+
attachments: hasAttachments ? [...this.attachments()] : undefined,
|
|
7746
7776
|
});
|
|
7747
7777
|
// Keep keyboard open by explicitly showing it before clearing
|
|
7748
7778
|
// This prevents the keyboard from starting to close during the clear operation
|
|
@@ -7757,7 +7787,7 @@ class DsMobileMessageComposerComponent {
|
|
|
7757
7787
|
this.messageInputRef.nativeElement.focus();
|
|
7758
7788
|
}
|
|
7759
7789
|
}
|
|
7760
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileMessageComposerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7790
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileMessageComposerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
7761
7791
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileMessageComposerComponent, isStandalone: true, selector: "ds-mobile-message-composer", inputs: { avatarInitials: { classPropertyName: "avatarInitials", publicName: "avatarInitials", isSignal: true, isRequired: false, transformFunction: null }, avatarType: { classPropertyName: "avatarType", publicName: "avatarType", isSignal: true, isRequired: false, transformFunction: null }, avatarSrc: { classPropertyName: "avatarSrc", publicName: "avatarSrc", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, sendButtonLabel: { classPropertyName: "sendButtonLabel", publicName: "sendButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, attachmentButtonLabel: { classPropertyName: "attachmentButtonLabel", publicName: "attachmentButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, showAttachmentButton: { classPropertyName: "showAttachmentButton", publicName: "showAttachmentButton", isSignal: true, isRequired: false, transformFunction: null }, editIndicatorText: { classPropertyName: "editIndicatorText", publicName: "editIndicatorText", isSignal: true, isRequired: false, transformFunction: null }, replyIndicatorText: { classPropertyName: "replyIndicatorText", publicName: "replyIndicatorText", isSignal: true, isRequired: false, transformFunction: null }, enableMentions: { classPropertyName: "enableMentions", publicName: "enableMentions", isSignal: true, isRequired: false, transformFunction: null }, mentionUsers: { classPropertyName: "mentionUsers", publicName: "mentionUsers", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { messageSent: "messageSent", editCancelled: "editCancelled", replyCancelled: "replyCancelled", mentionSelected: "mentionSelected", attachmentClicked: "attachmentClicked", attachmentsChanged: "attachmentsChanged" }, viewQueries: [{ propertyName: "messageInputRef", first: true, predicate: ["messageInputEl"], descendants: true }, { propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: `
|
|
7762
7792
|
<div class="message-composer">
|
|
7763
7793
|
<!-- Edit indicator (optional) -->
|
|
@@ -7772,7 +7802,7 @@ class DsMobileMessageComposerComponent {
|
|
|
7772
7802
|
</button>
|
|
7773
7803
|
</div>
|
|
7774
7804
|
}
|
|
7775
|
-
|
|
7805
|
+
|
|
7776
7806
|
<!-- Reply indicator (optional) -->
|
|
7777
7807
|
@if (replyingTo() && !editingMessage()) {
|
|
7778
7808
|
<div class="reply-indicator">
|
|
@@ -7787,21 +7817,18 @@ class DsMobileMessageComposerComponent {
|
|
|
7787
7817
|
</button>
|
|
7788
7818
|
</div>
|
|
7789
7819
|
}
|
|
7790
|
-
|
|
7820
|
+
|
|
7791
7821
|
<!-- Attachment Previews (if any) -->
|
|
7792
7822
|
@if (attachments().length > 0) {
|
|
7793
7823
|
<div class="attachment-previews-section">
|
|
7794
7824
|
<div class="attachment-previews">
|
|
7795
7825
|
@for (attachment of attachments(); track attachment.id) {
|
|
7796
|
-
<ds-mobile-attachment-preview
|
|
7797
|
-
[attachment]="attachment"
|
|
7798
|
-
(remove)="removeAttachment($event)"
|
|
7799
|
-
/>
|
|
7826
|
+
<ds-mobile-attachment-preview [attachment]="attachment" (remove)="removeAttachment($event)" />
|
|
7800
7827
|
}
|
|
7801
7828
|
</div>
|
|
7802
7829
|
</div>
|
|
7803
7830
|
}
|
|
7804
|
-
|
|
7831
|
+
|
|
7805
7832
|
<div class="composer-content">
|
|
7806
7833
|
<!-- Attachment button replacing avatar (left side) -->
|
|
7807
7834
|
@if (showAttachmentButton()) {
|
|
@@ -7812,34 +7839,30 @@ class DsMobileMessageComposerComponent {
|
|
|
7812
7839
|
icon="remixAddLine"
|
|
7813
7840
|
variant="secondary"
|
|
7814
7841
|
size="lg"
|
|
7815
|
-
(
|
|
7816
|
-
(mousedown)="toggleAttachmentMenu($event)"
|
|
7842
|
+
(clicked)="toggleAttachmentMenu($event)"
|
|
7817
7843
|
[attr.aria-label]="attachmentButtonLabel()"
|
|
7818
|
-
[attr.aria-expanded]="isAttachmentMenuOpen()"
|
|
7844
|
+
[attr.aria-expanded]="isAttachmentMenuOpen()"
|
|
7845
|
+
>
|
|
7819
7846
|
</ds-icon-button>
|
|
7820
|
-
|
|
7847
|
+
|
|
7821
7848
|
<!-- Attachment menu using dropdown -->
|
|
7822
7849
|
<ds-mobile-dropdown
|
|
7823
|
-
[items]="attachmentMenuItems
|
|
7850
|
+
[items]="attachmentMenuItems"
|
|
7824
7851
|
[isOpen]="isAttachmentMenuOpen()"
|
|
7825
7852
|
[trigger]="'attachment-trigger'"
|
|
7826
7853
|
[keepFocusOn]="messageInputRef"
|
|
7827
7854
|
position="above"
|
|
7828
7855
|
align="start"
|
|
7829
7856
|
(itemSelected)="handleAttachmentMenuSelect($event)"
|
|
7830
|
-
(closed)="closeAttachmentMenu()"
|
|
7857
|
+
(closed)="closeAttachmentMenu()"
|
|
7858
|
+
>
|
|
7831
7859
|
</ds-mobile-dropdown>
|
|
7832
7860
|
</div>
|
|
7833
7861
|
} @else {
|
|
7834
7862
|
<!-- Avatar (only shown when attachment button is hidden) -->
|
|
7835
|
-
<ds-avatar
|
|
7836
|
-
[initials]="avatarInitials()"
|
|
7837
|
-
[type]="avatarType()"
|
|
7838
|
-
[src]="avatarSrc()"
|
|
7839
|
-
size="lg"
|
|
7840
|
-
/>
|
|
7863
|
+
<ds-avatar [initials]="avatarInitials()" [type]="avatarType()" [src]="avatarSrc()" size="lg" />
|
|
7841
7864
|
}
|
|
7842
|
-
|
|
7865
|
+
|
|
7843
7866
|
<div class="composer-input-wrapper">
|
|
7844
7867
|
<textarea
|
|
7845
7868
|
#messageInputEl
|
|
@@ -7852,8 +7875,9 @@ class DsMobileMessageComposerComponent {
|
|
|
7852
7875
|
(focus)="showKeyboard()"
|
|
7853
7876
|
(click)="showKeyboard()"
|
|
7854
7877
|
rows="1"
|
|
7855
|
-
>
|
|
7856
|
-
|
|
7878
|
+
>
|
|
7879
|
+
</textarea>
|
|
7880
|
+
|
|
7857
7881
|
<!-- Mention menu using dropdown (only render if mentions are enabled) -->
|
|
7858
7882
|
@if (enableMentions()) {
|
|
7859
7883
|
<ds-mobile-dropdown
|
|
@@ -7864,12 +7888,10 @@ class DsMobileMessageComposerComponent {
|
|
|
7864
7888
|
align="start"
|
|
7865
7889
|
[maxHeight]="200"
|
|
7866
7890
|
(itemSelected)="handleMentionSelect($event)"
|
|
7867
|
-
(closed)="closeMentionMenu()"
|
|
7891
|
+
(closed)="closeMentionMenu()"
|
|
7892
|
+
>
|
|
7868
7893
|
<ng-template #itemTemplate let-item>
|
|
7869
|
-
<ds-avatar
|
|
7870
|
-
[initials]="item.data.initials"
|
|
7871
|
-
[type]="'initials'"
|
|
7872
|
-
size="sm" />
|
|
7894
|
+
<ds-avatar [initials]="item.data.initials" [type]="'initials'" size="sm" />
|
|
7873
7895
|
<div class="mention-user-info">
|
|
7874
7896
|
<span class="mention-user-name">{{ item.data.name }}</span>
|
|
7875
7897
|
<span class="mention-user-role">{{ item.data.role }}</span>
|
|
@@ -7877,7 +7899,7 @@ class DsMobileMessageComposerComponent {
|
|
|
7877
7899
|
</ng-template>
|
|
7878
7900
|
</ds-mobile-dropdown>
|
|
7879
7901
|
}
|
|
7880
|
-
|
|
7902
|
+
|
|
7881
7903
|
<!-- Send button (absolute positioned in top right, always rendered) -->
|
|
7882
7904
|
<ds-icon-button
|
|
7883
7905
|
icon="remixCheckLine"
|
|
@@ -7886,11 +7908,12 @@ class DsMobileMessageComposerComponent {
|
|
|
7886
7908
|
(clicked)="sendMessage()"
|
|
7887
7909
|
[attr.aria-label]="sendButtonLabel()"
|
|
7888
7910
|
[class.send-button-inline]="true"
|
|
7889
|
-
[class.show]="messageText().trim().length > 0 || attachments().length > 0"
|
|
7911
|
+
[class.show]="messageText().trim().length > 0 || attachments().length > 0"
|
|
7912
|
+
>
|
|
7890
7913
|
</ds-icon-button>
|
|
7891
7914
|
</div>
|
|
7892
7915
|
</div>
|
|
7893
|
-
|
|
7916
|
+
|
|
7894
7917
|
<!-- Hidden file input -->
|
|
7895
7918
|
<input
|
|
7896
7919
|
#fileInput
|
|
@@ -7902,19 +7925,11 @@ class DsMobileMessageComposerComponent {
|
|
|
7902
7925
|
(change)="handleFileSelect($event)"
|
|
7903
7926
|
/>
|
|
7904
7927
|
</div>
|
|
7905
|
-
`, isInline: true, styles: [":host{display:block}.message-composer{background:var(--color-background-neutral-primary, #ffffff);border-top:1px solid var(--border-color-default);border-bottom-left-radius:0;border-bottom-right-radius:0;padding:12px 16px;width:100%;display:flex;flex-direction:column;gap:8px}.edit-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-brand-subtle, #f0edfe);border-radius:8px;animation:slideDown .2s ease-out}.edit-indicator-content{display:flex;align-items:center;gap:8px;color:var(--color-accent, #
|
|
7928
|
+
`, isInline: true, styles: [":host{display:block}.message-composer{background:var(--color-background-neutral-primary, #ffffff);border-top:1px solid var(--border-color-default);border-bottom-left-radius:0;border-bottom-right-radius:0;padding:12px 16px;width:100%;display:flex;flex-direction:column;gap:8px}.edit-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-brand-subtle, #f0edfe);border-radius:8px;animation:slideDown .2s ease-out}.edit-indicator-content{display:flex;align-items:center;gap:8px;color:var(--color-accent, #6b5ff5);flex:1;min-width:0}.edit-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:18px;color:var(--color-accent, #6b5ff5)}.cancel-edit{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-accent, #6b5ff5);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-edit:active{background:var(--color-brand-subtle, #e0dbfe)}.reply-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:8px;animation:slideDown .2s ease-out}.reply-indicator-content{display:flex;align-items:center;gap:4px;color:var(--color-text-secondary, #737373);flex:1;min-width:0}.reply-to-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.reply-author{color:var(--color-accent, #6b5ff5);font-weight:600}.cancel-reply{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-text-secondary, #737373);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-reply:active{background:var(--color-background-neutral-secondary, #f5f5f5)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.attachment-previews-section{padding:0 0 8px;animation:slideDown .2s ease-out}.attachment-previews{display:flex;flex-wrap:wrap;gap:8px}.composer-content{display:flex;align-items:center;gap:12px;width:100%;position:relative}.composer-leading-button{flex-shrink:0}.composer-leading-button::ng-deep button{width:40px!important;height:40px!important;min-width:40px!important;min-height:40px!important;padding:0!important;border-radius:50%!important;transition:transform .3s ease}.composer-leading-button--open::ng-deep button{transform:rotate(45deg)}.composer-input-wrapper{flex:1;display:flex;align-items:flex-start;gap:8px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:24px;padding:12px 16px;min-height:44px;position:relative}.mention-user-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.mention-user-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:20px;color:var(--color-text-primary, #1a1a1a)}.mention-user-role{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373)}.composer-input{flex:1;border:none;background:transparent;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:20px;color:var(--color-text-primary, #1a1a1a);outline:none;resize:none;min-height:20px;max-height:120px;overflow-y:auto;padding:0;margin:0}.composer-input::placeholder{color:var(--color-text-tertiary, #a0a0a0);font-size:var(--font-size-sm)}.send-button-inline{position:absolute;top:6px;right:6px;z-index:10;flex-shrink:0;opacity:0;transform:translate(20px) scale(.8);pointer-events:none;transition:opacity .15s ease-in,transform .15s ease-in}.send-button-inline.show{opacity:1;transform:translate(0) scale(1);pointer-events:auto;animation:slideInFromRight var(--spring-bouncy)}.send-button-inline::ng-deep button{width:32px!important;height:32px!important;min-width:32px!important;min-height:32px!important;padding:0!important;border-radius:50%!important}@keyframes slideInFromRight{0%{opacity:0;transform:translate(20px) scale(.8)}to{opacity:1;transform:translate(0) scale(1)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileAttachmentPreviewComponent, selector: "ds-mobile-attachment-preview", inputs: ["attachment"], outputs: ["remove"] }, { kind: "component", type: DsMobileDropdownComponent, selector: "ds-mobile-dropdown", inputs: ["trigger", "keepFocusOn", "items", "isOpen", "position", "align", "maxHeight", "emptyMessage", "ariaLabel", "maxWidth"], outputs: ["itemSelected", "closed"] }] });
|
|
7906
7929
|
}
|
|
7907
7930
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileMessageComposerComponent, decorators: [{
|
|
7908
7931
|
type: Component,
|
|
7909
|
-
args: [{ selector: 'ds-mobile-message-composer', standalone: true, imports: [
|
|
7910
|
-
CommonModule,
|
|
7911
|
-
FormsModule,
|
|
7912
|
-
DsAvatarComponent,
|
|
7913
|
-
DsIconButtonComponent,
|
|
7914
|
-
DsIconComponent,
|
|
7915
|
-
DsMobileAttachmentPreviewComponent,
|
|
7916
|
-
DsMobileDropdownComponent
|
|
7917
|
-
], template: `
|
|
7932
|
+
args: [{ selector: 'ds-mobile-message-composer', standalone: true, imports: [CommonModule, FormsModule, DsAvatarComponent, DsIconButtonComponent, DsIconComponent, DsMobileAttachmentPreviewComponent, DsMobileDropdownComponent], template: `
|
|
7918
7933
|
<div class="message-composer">
|
|
7919
7934
|
<!-- Edit indicator (optional) -->
|
|
7920
7935
|
@if (editingMessage()) {
|
|
@@ -7928,7 +7943,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
7928
7943
|
</button>
|
|
7929
7944
|
</div>
|
|
7930
7945
|
}
|
|
7931
|
-
|
|
7946
|
+
|
|
7932
7947
|
<!-- Reply indicator (optional) -->
|
|
7933
7948
|
@if (replyingTo() && !editingMessage()) {
|
|
7934
7949
|
<div class="reply-indicator">
|
|
@@ -7943,21 +7958,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
7943
7958
|
</button>
|
|
7944
7959
|
</div>
|
|
7945
7960
|
}
|
|
7946
|
-
|
|
7961
|
+
|
|
7947
7962
|
<!-- Attachment Previews (if any) -->
|
|
7948
7963
|
@if (attachments().length > 0) {
|
|
7949
7964
|
<div class="attachment-previews-section">
|
|
7950
7965
|
<div class="attachment-previews">
|
|
7951
7966
|
@for (attachment of attachments(); track attachment.id) {
|
|
7952
|
-
<ds-mobile-attachment-preview
|
|
7953
|
-
[attachment]="attachment"
|
|
7954
|
-
(remove)="removeAttachment($event)"
|
|
7955
|
-
/>
|
|
7967
|
+
<ds-mobile-attachment-preview [attachment]="attachment" (remove)="removeAttachment($event)" />
|
|
7956
7968
|
}
|
|
7957
7969
|
</div>
|
|
7958
7970
|
</div>
|
|
7959
7971
|
}
|
|
7960
|
-
|
|
7972
|
+
|
|
7961
7973
|
<div class="composer-content">
|
|
7962
7974
|
<!-- Attachment button replacing avatar (left side) -->
|
|
7963
7975
|
@if (showAttachmentButton()) {
|
|
@@ -7968,34 +7980,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
7968
7980
|
icon="remixAddLine"
|
|
7969
7981
|
variant="secondary"
|
|
7970
7982
|
size="lg"
|
|
7971
|
-
(
|
|
7972
|
-
(mousedown)="toggleAttachmentMenu($event)"
|
|
7983
|
+
(clicked)="toggleAttachmentMenu($event)"
|
|
7973
7984
|
[attr.aria-label]="attachmentButtonLabel()"
|
|
7974
|
-
[attr.aria-expanded]="isAttachmentMenuOpen()"
|
|
7985
|
+
[attr.aria-expanded]="isAttachmentMenuOpen()"
|
|
7986
|
+
>
|
|
7975
7987
|
</ds-icon-button>
|
|
7976
|
-
|
|
7988
|
+
|
|
7977
7989
|
<!-- Attachment menu using dropdown -->
|
|
7978
7990
|
<ds-mobile-dropdown
|
|
7979
|
-
[items]="attachmentMenuItems
|
|
7991
|
+
[items]="attachmentMenuItems"
|
|
7980
7992
|
[isOpen]="isAttachmentMenuOpen()"
|
|
7981
7993
|
[trigger]="'attachment-trigger'"
|
|
7982
7994
|
[keepFocusOn]="messageInputRef"
|
|
7983
7995
|
position="above"
|
|
7984
7996
|
align="start"
|
|
7985
7997
|
(itemSelected)="handleAttachmentMenuSelect($event)"
|
|
7986
|
-
(closed)="closeAttachmentMenu()"
|
|
7998
|
+
(closed)="closeAttachmentMenu()"
|
|
7999
|
+
>
|
|
7987
8000
|
</ds-mobile-dropdown>
|
|
7988
8001
|
</div>
|
|
7989
8002
|
} @else {
|
|
7990
8003
|
<!-- Avatar (only shown when attachment button is hidden) -->
|
|
7991
|
-
<ds-avatar
|
|
7992
|
-
[initials]="avatarInitials()"
|
|
7993
|
-
[type]="avatarType()"
|
|
7994
|
-
[src]="avatarSrc()"
|
|
7995
|
-
size="lg"
|
|
7996
|
-
/>
|
|
8004
|
+
<ds-avatar [initials]="avatarInitials()" [type]="avatarType()" [src]="avatarSrc()" size="lg" />
|
|
7997
8005
|
}
|
|
7998
|
-
|
|
8006
|
+
|
|
7999
8007
|
<div class="composer-input-wrapper">
|
|
8000
8008
|
<textarea
|
|
8001
8009
|
#messageInputEl
|
|
@@ -8008,8 +8016,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
8008
8016
|
(focus)="showKeyboard()"
|
|
8009
8017
|
(click)="showKeyboard()"
|
|
8010
8018
|
rows="1"
|
|
8011
|
-
>
|
|
8012
|
-
|
|
8019
|
+
>
|
|
8020
|
+
</textarea>
|
|
8021
|
+
|
|
8013
8022
|
<!-- Mention menu using dropdown (only render if mentions are enabled) -->
|
|
8014
8023
|
@if (enableMentions()) {
|
|
8015
8024
|
<ds-mobile-dropdown
|
|
@@ -8020,12 +8029,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
8020
8029
|
align="start"
|
|
8021
8030
|
[maxHeight]="200"
|
|
8022
8031
|
(itemSelected)="handleMentionSelect($event)"
|
|
8023
|
-
(closed)="closeMentionMenu()"
|
|
8032
|
+
(closed)="closeMentionMenu()"
|
|
8033
|
+
>
|
|
8024
8034
|
<ng-template #itemTemplate let-item>
|
|
8025
|
-
<ds-avatar
|
|
8026
|
-
[initials]="item.data.initials"
|
|
8027
|
-
[type]="'initials'"
|
|
8028
|
-
size="sm" />
|
|
8035
|
+
<ds-avatar [initials]="item.data.initials" [type]="'initials'" size="sm" />
|
|
8029
8036
|
<div class="mention-user-info">
|
|
8030
8037
|
<span class="mention-user-name">{{ item.data.name }}</span>
|
|
8031
8038
|
<span class="mention-user-role">{{ item.data.role }}</span>
|
|
@@ -8033,7 +8040,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
8033
8040
|
</ng-template>
|
|
8034
8041
|
</ds-mobile-dropdown>
|
|
8035
8042
|
}
|
|
8036
|
-
|
|
8043
|
+
|
|
8037
8044
|
<!-- Send button (absolute positioned in top right, always rendered) -->
|
|
8038
8045
|
<ds-icon-button
|
|
8039
8046
|
icon="remixCheckLine"
|
|
@@ -8042,11 +8049,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
8042
8049
|
(clicked)="sendMessage()"
|
|
8043
8050
|
[attr.aria-label]="sendButtonLabel()"
|
|
8044
8051
|
[class.send-button-inline]="true"
|
|
8045
|
-
[class.show]="messageText().trim().length > 0 || attachments().length > 0"
|
|
8052
|
+
[class.show]="messageText().trim().length > 0 || attachments().length > 0"
|
|
8053
|
+
>
|
|
8046
8054
|
</ds-icon-button>
|
|
8047
8055
|
</div>
|
|
8048
8056
|
</div>
|
|
8049
|
-
|
|
8057
|
+
|
|
8050
8058
|
<!-- Hidden file input -->
|
|
8051
8059
|
<input
|
|
8052
8060
|
#fileInput
|
|
@@ -8058,8 +8066,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
8058
8066
|
(change)="handleFileSelect($event)"
|
|
8059
8067
|
/>
|
|
8060
8068
|
</div>
|
|
8061
|
-
`, styles: [":host{display:block}.message-composer{background:var(--color-background-neutral-primary, #ffffff);border-top:1px solid var(--border-color-default);border-bottom-left-radius:0;border-bottom-right-radius:0;padding:12px 16px;width:100%;display:flex;flex-direction:column;gap:8px}.edit-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-brand-subtle, #f0edfe);border-radius:8px;animation:slideDown .2s ease-out}.edit-indicator-content{display:flex;align-items:center;gap:8px;color:var(--color-accent, #
|
|
8062
|
-
}], propDecorators: { avatarInitials: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarInitials", required: false }] }], avatarType: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarType", required: false }] }], avatarSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarSrc", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], sendButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sendButtonLabel", required: false }] }], attachmentButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachmentButtonLabel", required: false }] }], showAttachmentButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAttachmentButton", required: false }] }], editIndicatorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "editIndicatorText", required: false }] }], replyIndicatorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "replyIndicatorText", required: false }] }], enableMentions: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableMentions", required: false }] }], mentionUsers: [{ type: i0.Input, args: [{ isSignal: true, alias: "mentionUsers", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], messageInputRef: [{
|
|
8069
|
+
`, styles: [":host{display:block}.message-composer{background:var(--color-background-neutral-primary, #ffffff);border-top:1px solid var(--border-color-default);border-bottom-left-radius:0;border-bottom-right-radius:0;padding:12px 16px;width:100%;display:flex;flex-direction:column;gap:8px}.edit-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-brand-subtle, #f0edfe);border-radius:8px;animation:slideDown .2s ease-out}.edit-indicator-content{display:flex;align-items:center;gap:8px;color:var(--color-accent, #6b5ff5);flex:1;min-width:0}.edit-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:18px;color:var(--color-accent, #6b5ff5)}.cancel-edit{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-accent, #6b5ff5);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-edit:active{background:var(--color-brand-subtle, #e0dbfe)}.reply-indicator{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:8px;animation:slideDown .2s ease-out}.reply-indicator-content{display:flex;align-items:center;gap:4px;color:var(--color-text-secondary, #737373);flex:1;min-width:0}.reply-to-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.reply-author{color:var(--color-accent, #6b5ff5);font-weight:600}.cancel-reply{background:none;border:none;padding:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-text-secondary, #737373);border-radius:4px;transition:background .2s ease;flex-shrink:0}.cancel-reply:active{background:var(--color-background-neutral-secondary, #f5f5f5)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.attachment-previews-section{padding:0 0 8px;animation:slideDown .2s ease-out}.attachment-previews{display:flex;flex-wrap:wrap;gap:8px}.composer-content{display:flex;align-items:center;gap:12px;width:100%;position:relative}.composer-leading-button{flex-shrink:0}.composer-leading-button::ng-deep button{width:40px!important;height:40px!important;min-width:40px!important;min-height:40px!important;padding:0!important;border-radius:50%!important;transition:transform .3s ease}.composer-leading-button--open::ng-deep button{transform:rotate(45deg)}.composer-input-wrapper{flex:1;display:flex;align-items:flex-start;gap:8px;background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:24px;padding:12px 16px;min-height:44px;position:relative}.mention-user-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.mention-user-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:20px;color:var(--color-text-primary, #1a1a1a)}.mention-user-role{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:18px;color:var(--color-text-secondary, #737373)}.composer-input{flex:1;border:none;background:transparent;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);line-height:20px;color:var(--color-text-primary, #1a1a1a);outline:none;resize:none;min-height:20px;max-height:120px;overflow-y:auto;padding:0;margin:0}.composer-input::placeholder{color:var(--color-text-tertiary, #a0a0a0);font-size:var(--font-size-sm)}.send-button-inline{position:absolute;top:6px;right:6px;z-index:10;flex-shrink:0;opacity:0;transform:translate(20px) scale(.8);pointer-events:none;transition:opacity .15s ease-in,transform .15s ease-in}.send-button-inline.show{opacity:1;transform:translate(0) scale(1);pointer-events:auto;animation:slideInFromRight var(--spring-bouncy)}.send-button-inline::ng-deep button{width:32px!important;height:32px!important;min-width:32px!important;min-height:32px!important;padding:0!important;border-radius:50%!important}@keyframes slideInFromRight{0%{opacity:0;transform:translate(20px) scale(.8)}to{opacity:1;transform:translate(0) scale(1)}}\n"] }]
|
|
8070
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { avatarInitials: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarInitials", required: false }] }], avatarType: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarType", required: false }] }], avatarSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarSrc", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], sendButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sendButtonLabel", required: false }] }], attachmentButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachmentButtonLabel", required: false }] }], showAttachmentButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAttachmentButton", required: false }] }], editIndicatorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "editIndicatorText", required: false }] }], replyIndicatorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "replyIndicatorText", required: false }] }], enableMentions: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableMentions", required: false }] }], mentionUsers: [{ type: i0.Input, args: [{ isSignal: true, alias: "mentionUsers", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], messageInputRef: [{
|
|
8063
8071
|
type: ViewChild,
|
|
8064
8072
|
args: ['messageInputEl']
|
|
8065
8073
|
}], fileInput: [{
|
|
@@ -10389,7 +10397,7 @@ class DsMobileTabBarComponent {
|
|
|
10389
10397
|
<ds-avatar [size]="'md'" [type]="avatarType" [initials]="avatarInitials" [src]="avatarSrc" [iconName]="avatarIconName" (click)="handleAvatarClick()" />
|
|
10390
10398
|
</div>
|
|
10391
10399
|
</ion-tab-bar>
|
|
10392
|
-
`, isInline: true, styles: [":host{--ds-tab-bar-height: 64px}@media (min-width: 768px){:host{display:block;--ds-tab-bar-height: 64px}}@media (max-width: 767px){:host{display:contents}}ion-tabs.ds-tabs-wrapper{height:100%;background:var(--color-header-surface)}ion-tab-button:before,ion-tab-button:after{content:none!important;display:none!important}ion-tab-button[title]:before,ion-tab-button[title]:after{display:none!important}ion-tab-button::part(native):before,ion-tab-button::part(native):after{display:none!important}.ds-tab-bar{--background: var(--color-background-neutral-primary);transition:transform .2s ease-in-out}ion-tab-bar[slot=bottom]{border-top:1px solid var(--border-color-default);padding-top:8px;padding-bottom:max(8px,calc(var(--ion-safe-area-bottom, 0px) - 16px));padding-left:12px;padding-right:12px}@media (max-width: 767px){ion-tab-bar[slot=bottom]{position:fixed;bottom:0;left:0;right:0;z-index:100}}@media (max-width: 767px){:host-context(ion-tabs:has(ds-mobile-page-details)) .ds-tab-bar{transform:translateY(100%);transition:transform .3s ease}}.ds-tab-bar__logo,.ds-tab-bar__actions{display:none}.ds-tab-bar__tabs{display:flex;width:100%;justify-content:space-around;align-items:center}@media (min-width: 769px){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)}}@media (display-mode: standalone){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)!important}}@media (min-width: 768px){:host[slot=top]{order:-1!important}:host ion-tab-bar{position:relative!important;bottom:auto!important;top:0!important}ion-tab-bar[slot=top]{--background: var(--color-header-surface);position:relative!important;display:flex!important;align-items:center;padding:12px 24px;height:64px;max-width:none;bottom:auto!important;top:0!important}ion-tab-bar[slot=bottom]{position:relative!important;bottom:auto!important}ion-tabs>div:not([slot]){order:1!important}.ds-tab-bar__logo{display:flex;position:absolute;left:24px;align-items:center;color:var(--header-content-color, white)}.ds-tab-bar__actions{display:flex;position:absolute;right:24px;align-items:center;gap:12px}.ds-tab-bar__tabs{display:flex;gap:8px;align-items:center;max-width:640px;width:100%;margin:0 auto;justify-content:center;padding-left:var(--content-padding-md);padding-right:var(--content-padding-md)}.logomark{height:28px;width:auto;flex-shrink:0}}@media (min-width: 992px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg);justify-content:center}}@media (min-width: 1440px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-tab-button{--color: var(--text-color-default-tertiary);--color-selected: var(--color-accent);display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:visible;pointer-events:auto}ion-tab-button[title]:before{content:attr(title);position:absolute;opacity:0;pointer-events:none}.tab-icon-ripple{position:absolute;left:50%;top:50%;width:40px;height:40px;border-radius:50%;background:var(--color-accent);transform:translate(-50%,-50%) scale(0);opacity:0;pointer-events:none;transition:all .6s cubic-bezier(.36,1.2,.04,1.4);z-index:0}.tab-selected .tab-icon-ripple{transform:translate(-50%,-50%) scale(2);opacity:.05;animation:ripple-fade .6s cubic-bezier(.36,.5,.04,1.8) forwards}@keyframes ripple-fade{0%{opacity:0;transform:translate(-50%,-50%) scale(0)}30%{opacity:.1}to{opacity:0;transform:translate(-50%,-50%) scale(2)}}ion-tab-button::part(native){overflow:visible}ion-tab-button ion-ripple-effect{color:var(--color-accent);border-radius:1000px}ion-tab-button ion-label{font-size:
|
|
10400
|
+
`, isInline: true, styles: [":host{--ds-tab-bar-height: 64px}@media (min-width: 768px){:host{display:block;--ds-tab-bar-height: 64px}}@media (max-width: 767px){:host{display:contents}}ion-tabs.ds-tabs-wrapper{height:100%;background:var(--color-header-surface)}ion-tab-button:before,ion-tab-button:after{content:none!important;display:none!important}ion-tab-button[title]:before,ion-tab-button[title]:after{display:none!important}ion-tab-button::part(native):before,ion-tab-button::part(native):after{display:none!important}.ds-tab-bar{--background: var(--color-background-neutral-primary);transition:transform .2s ease-in-out}ion-tab-bar[slot=bottom]{border-top:1px solid var(--border-color-default);padding-top:8px;padding-bottom:max(8px,calc(var(--ion-safe-area-bottom, 0px) - 16px));padding-left:12px;padding-right:12px}@media (max-width: 767px){ion-tab-bar[slot=bottom]{position:fixed;bottom:0;left:0;right:0;z-index:100}}@media (max-width: 767px){:host-context(ion-tabs:has(ds-mobile-page-details)) .ds-tab-bar{transform:translateY(100%);transition:transform .3s ease}}.ds-tab-bar__logo,.ds-tab-bar__actions{display:none}.ds-tab-bar__tabs{display:flex;width:100%;justify-content:space-around;align-items:center}@media (min-width: 769px){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)}}@media (display-mode: standalone){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)!important}}@media (min-width: 768px){:host[slot=top]{order:-1!important}:host ion-tab-bar{position:relative!important;bottom:auto!important;top:0!important}ion-tab-bar[slot=top]{--background: var(--color-header-surface);position:relative!important;display:flex!important;align-items:center;padding:12px 24px;height:64px;max-width:none;bottom:auto!important;top:0!important}ion-tab-bar[slot=bottom]{position:relative!important;bottom:auto!important}ion-tabs>div:not([slot]){order:1!important}.ds-tab-bar__logo{display:flex;position:absolute;left:24px;align-items:center;color:var(--header-content-color, white)}.ds-tab-bar__actions{display:flex;position:absolute;right:24px;align-items:center;gap:12px}.ds-tab-bar__tabs{display:flex;gap:8px;align-items:center;max-width:640px;width:100%;margin:0 auto;justify-content:center;padding-left:var(--content-padding-md);padding-right:var(--content-padding-md)}.logomark{height:28px;width:auto;flex-shrink:0}}@media (min-width: 992px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg);justify-content:center}}@media (min-width: 1440px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-tab-button{--color: var(--text-color-default-tertiary);--color-selected: var(--color-accent);display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:visible;pointer-events:auto}ion-tab-button[title]:before{content:attr(title);position:absolute;opacity:0;pointer-events:none}.tab-icon-ripple{position:absolute;left:50%;top:50%;width:40px;height:40px;border-radius:50%;background:var(--color-accent);transform:translate(-50%,-50%) scale(0);opacity:0;pointer-events:none;transition:all .6s cubic-bezier(.36,1.2,.04,1.4);z-index:0}.tab-selected .tab-icon-ripple{transform:translate(-50%,-50%) scale(2);opacity:.05;animation:ripple-fade .6s cubic-bezier(.36,.5,.04,1.8) forwards}@keyframes ripple-fade{0%{opacity:0;transform:translate(-50%,-50%) scale(0)}30%{opacity:.1}to{opacity:0;transform:translate(-50%,-50%) scale(2)}}ion-tab-button::part(native){overflow:visible}ion-tab-button ion-ripple-effect{color:var(--color-accent);border-radius:1000px}ion-tab-button ion-label{font-size:11px;font-weight:500;letter-spacing:-.5px;margin-top:0}.tab-icon-wrapper{position:relative;width:24px;height:24px;display:flex;align-items:center;justify-content:center;z-index:1;margin-bottom:4px}.tab-icon-inactive,.tab-icon-active{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);transition:all .8s cubic-bezier(.36,1,.04,1)}.tab-icon-inactive{opacity:1;transform:translate(-50%,-50%) scale(1)}.tab-icon-active{opacity:0;transform:translate(-50%,calc(-50% - 12px)) scale(.5)}.tab-selected .tab-icon-inactive{opacity:0;transform:translate(-50%,-50%) scale(.5)}.tab-selected .tab-icon-active{opacity:1;transform:translate(-50%,-50%) scale(1)}@media (min-width: 768px){.ds-tab-button{flex-direction:row;height:40px;padding:0 16px!important;border-radius:40px;transition:all .2s ease;width:-moz-fit-content;width:fit-content;min-width:-moz-fit-content;min-width:fit-content;flex:0 0 auto;--color: rgba(var(--color-header-content-rgb, 255, 255, 255), .7);--color-selected: var(--color-header-content, white);color:rgba(var(--color-header-content-rgb, 255, 255, 255),.7);background:transparent;position:relative;overflow:hidden}.tab-icon-wrapper,.tab-icon-ripple{width:20px;height:20px}.ds-tab-button::part(native){border-radius:40px}.ds-tab-button:hover:not(.tab-selected){--color: var(--color-header-content, white);--color-selected: var(--color-header-content, white);color:var(--color-header-content, white);background:rgba(var(--color-header-content-rgb, 255, 255, 255),.1)}.ds-tab-button:hover:not(.tab-selected) ion-label{color:var(--color-header-content, white)}.ds-tab-button:hover:not(.tab-selected) ds-icon{--icon-color: var(--color-header-content, white);color:var(--color-header-content, white)}.ds-tab-button:hover:not(.tab-selected) ds-icon svg{fill:var(--color-header-content, white)}.ds-tab-button.tab-selected,.ds-tab-button.tab-selected:hover{background:var(--color-header-accent);--color-selected: var(--color-on-header-accent, white);--color: var(--color-on-header-accent, white);color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected:hover ion-label{color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected:hover ds-icon{--icon-color: var(--color-on-header-accent, white);color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected:hover ds-icon svg{fill:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected:hover .tab-icon-active{opacity:1!important;visibility:visible!important}.ds-tab-button.tab-selected:hover .tab-icon-inactive{opacity:0!important}.ds-tab-button.tab-selected ion-label{color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected ds-icon{--icon-color: var(--color-on-header-accent, white);color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected ds-icon svg{fill:var(--color-on-header-accent, white)}.ds-tab-button .button-native{width:auto;padding:0}.ds-tab-button ion-label{font-size:var(--font-size-sm);font-weight:500;margin:0;color:inherit}.ds-tab-button .tab-icon-wrapper{margin-right:4px;margin-bottom:0}.ds-tab-button ion-ripple-effect{color:rgba(var(--header-content-color-rgb, 255, 255, 255),.3);border-radius:1000px;transform:scale(1.5)}}@media (min-width: 768px){.ds-tab-bar__actions ds-avatar{cursor:pointer;transition:transform .2s ease}.ds-tab-bar__actions ds-avatar:hover{transform:scale(1.05)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IonTabBar, selector: "ion-tab-bar", inputs: ["color", "mode", "selectedTab", "translucent"] }, { kind: "component", type: IonTabButton, selector: "ion-tab-button", inputs: ["disabled", "download", "href", "layout", "mode", "rel", "selected", "tab", "target"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }, { kind: "component", type: DsLogoComponent, selector: "ds-logo", inputs: ["variant", "size", "customHeight", "customWidth"] }] });
|
|
10393
10401
|
}
|
|
10394
10402
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileTabBarComponent, decorators: [{
|
|
10395
10403
|
type: Component,
|
|
@@ -10425,7 +10433,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10425
10433
|
<ds-avatar [size]="'md'" [type]="avatarType" [initials]="avatarInitials" [src]="avatarSrc" [iconName]="avatarIconName" (click)="handleAvatarClick()" />
|
|
10426
10434
|
</div>
|
|
10427
10435
|
</ion-tab-bar>
|
|
10428
|
-
`, styles: [":host{--ds-tab-bar-height: 64px}@media (min-width: 768px){:host{display:block;--ds-tab-bar-height: 64px}}@media (max-width: 767px){:host{display:contents}}ion-tabs.ds-tabs-wrapper{height:100%;background:var(--color-header-surface)}ion-tab-button:before,ion-tab-button:after{content:none!important;display:none!important}ion-tab-button[title]:before,ion-tab-button[title]:after{display:none!important}ion-tab-button::part(native):before,ion-tab-button::part(native):after{display:none!important}.ds-tab-bar{--background: var(--color-background-neutral-primary);transition:transform .2s ease-in-out}ion-tab-bar[slot=bottom]{border-top:1px solid var(--border-color-default);padding-top:8px;padding-bottom:max(8px,calc(var(--ion-safe-area-bottom, 0px) - 16px));padding-left:12px;padding-right:12px}@media (max-width: 767px){ion-tab-bar[slot=bottom]{position:fixed;bottom:0;left:0;right:0;z-index:100}}@media (max-width: 767px){:host-context(ion-tabs:has(ds-mobile-page-details)) .ds-tab-bar{transform:translateY(100%);transition:transform .3s ease}}.ds-tab-bar__logo,.ds-tab-bar__actions{display:none}.ds-tab-bar__tabs{display:flex;width:100%;justify-content:space-around;align-items:center}@media (min-width: 769px){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)}}@media (display-mode: standalone){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)!important}}@media (min-width: 768px){:host[slot=top]{order:-1!important}:host ion-tab-bar{position:relative!important;bottom:auto!important;top:0!important}ion-tab-bar[slot=top]{--background: var(--color-header-surface);position:relative!important;display:flex!important;align-items:center;padding:12px 24px;height:64px;max-width:none;bottom:auto!important;top:0!important}ion-tab-bar[slot=bottom]{position:relative!important;bottom:auto!important}ion-tabs>div:not([slot]){order:1!important}.ds-tab-bar__logo{display:flex;position:absolute;left:24px;align-items:center;color:var(--header-content-color, white)}.ds-tab-bar__actions{display:flex;position:absolute;right:24px;align-items:center;gap:12px}.ds-tab-bar__tabs{display:flex;gap:8px;align-items:center;max-width:640px;width:100%;margin:0 auto;justify-content:center;padding-left:var(--content-padding-md);padding-right:var(--content-padding-md)}.logomark{height:28px;width:auto;flex-shrink:0}}@media (min-width: 992px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg);justify-content:center}}@media (min-width: 1440px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-tab-button{--color: var(--text-color-default-tertiary);--color-selected: var(--color-accent);display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:visible;pointer-events:auto}ion-tab-button[title]:before{content:attr(title);position:absolute;opacity:0;pointer-events:none}.tab-icon-ripple{position:absolute;left:50%;top:50%;width:40px;height:40px;border-radius:50%;background:var(--color-accent);transform:translate(-50%,-50%) scale(0);opacity:0;pointer-events:none;transition:all .6s cubic-bezier(.36,1.2,.04,1.4);z-index:0}.tab-selected .tab-icon-ripple{transform:translate(-50%,-50%) scale(2);opacity:.05;animation:ripple-fade .6s cubic-bezier(.36,.5,.04,1.8) forwards}@keyframes ripple-fade{0%{opacity:0;transform:translate(-50%,-50%) scale(0)}30%{opacity:.1}to{opacity:0;transform:translate(-50%,-50%) scale(2)}}ion-tab-button::part(native){overflow:visible}ion-tab-button ion-ripple-effect{color:var(--color-accent);border-radius:1000px}ion-tab-button ion-label{font-size:
|
|
10436
|
+
`, styles: [":host{--ds-tab-bar-height: 64px}@media (min-width: 768px){:host{display:block;--ds-tab-bar-height: 64px}}@media (max-width: 767px){:host{display:contents}}ion-tabs.ds-tabs-wrapper{height:100%;background:var(--color-header-surface)}ion-tab-button:before,ion-tab-button:after{content:none!important;display:none!important}ion-tab-button[title]:before,ion-tab-button[title]:after{display:none!important}ion-tab-button::part(native):before,ion-tab-button::part(native):after{display:none!important}.ds-tab-bar{--background: var(--color-background-neutral-primary);transition:transform .2s ease-in-out}ion-tab-bar[slot=bottom]{border-top:1px solid var(--border-color-default);padding-top:8px;padding-bottom:max(8px,calc(var(--ion-safe-area-bottom, 0px) - 16px));padding-left:12px;padding-right:12px}@media (max-width: 767px){ion-tab-bar[slot=bottom]{position:fixed;bottom:0;left:0;right:0;z-index:100}}@media (max-width: 767px){:host-context(ion-tabs:has(ds-mobile-page-details)) .ds-tab-bar{transform:translateY(100%);transition:transform .3s ease}}.ds-tab-bar__logo,.ds-tab-bar__actions{display:none}.ds-tab-bar__tabs{display:flex;width:100%;justify-content:space-around;align-items:center}@media (min-width: 769px){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)}}@media (display-mode: standalone){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)!important}}@media (min-width: 768px){:host[slot=top]{order:-1!important}:host ion-tab-bar{position:relative!important;bottom:auto!important;top:0!important}ion-tab-bar[slot=top]{--background: var(--color-header-surface);position:relative!important;display:flex!important;align-items:center;padding:12px 24px;height:64px;max-width:none;bottom:auto!important;top:0!important}ion-tab-bar[slot=bottom]{position:relative!important;bottom:auto!important}ion-tabs>div:not([slot]){order:1!important}.ds-tab-bar__logo{display:flex;position:absolute;left:24px;align-items:center;color:var(--header-content-color, white)}.ds-tab-bar__actions{display:flex;position:absolute;right:24px;align-items:center;gap:12px}.ds-tab-bar__tabs{display:flex;gap:8px;align-items:center;max-width:640px;width:100%;margin:0 auto;justify-content:center;padding-left:var(--content-padding-md);padding-right:var(--content-padding-md)}.logomark{height:28px;width:auto;flex-shrink:0}}@media (min-width: 992px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg);justify-content:center}}@media (min-width: 1440px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-tab-button{--color: var(--text-color-default-tertiary);--color-selected: var(--color-accent);display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:visible;pointer-events:auto}ion-tab-button[title]:before{content:attr(title);position:absolute;opacity:0;pointer-events:none}.tab-icon-ripple{position:absolute;left:50%;top:50%;width:40px;height:40px;border-radius:50%;background:var(--color-accent);transform:translate(-50%,-50%) scale(0);opacity:0;pointer-events:none;transition:all .6s cubic-bezier(.36,1.2,.04,1.4);z-index:0}.tab-selected .tab-icon-ripple{transform:translate(-50%,-50%) scale(2);opacity:.05;animation:ripple-fade .6s cubic-bezier(.36,.5,.04,1.8) forwards}@keyframes ripple-fade{0%{opacity:0;transform:translate(-50%,-50%) scale(0)}30%{opacity:.1}to{opacity:0;transform:translate(-50%,-50%) scale(2)}}ion-tab-button::part(native){overflow:visible}ion-tab-button ion-ripple-effect{color:var(--color-accent);border-radius:1000px}ion-tab-button ion-label{font-size:11px;font-weight:500;letter-spacing:-.5px;margin-top:0}.tab-icon-wrapper{position:relative;width:24px;height:24px;display:flex;align-items:center;justify-content:center;z-index:1;margin-bottom:4px}.tab-icon-inactive,.tab-icon-active{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);transition:all .8s cubic-bezier(.36,1,.04,1)}.tab-icon-inactive{opacity:1;transform:translate(-50%,-50%) scale(1)}.tab-icon-active{opacity:0;transform:translate(-50%,calc(-50% - 12px)) scale(.5)}.tab-selected .tab-icon-inactive{opacity:0;transform:translate(-50%,-50%) scale(.5)}.tab-selected .tab-icon-active{opacity:1;transform:translate(-50%,-50%) scale(1)}@media (min-width: 768px){.ds-tab-button{flex-direction:row;height:40px;padding:0 16px!important;border-radius:40px;transition:all .2s ease;width:-moz-fit-content;width:fit-content;min-width:-moz-fit-content;min-width:fit-content;flex:0 0 auto;--color: rgba(var(--color-header-content-rgb, 255, 255, 255), .7);--color-selected: var(--color-header-content, white);color:rgba(var(--color-header-content-rgb, 255, 255, 255),.7);background:transparent;position:relative;overflow:hidden}.tab-icon-wrapper,.tab-icon-ripple{width:20px;height:20px}.ds-tab-button::part(native){border-radius:40px}.ds-tab-button:hover:not(.tab-selected){--color: var(--color-header-content, white);--color-selected: var(--color-header-content, white);color:var(--color-header-content, white);background:rgba(var(--color-header-content-rgb, 255, 255, 255),.1)}.ds-tab-button:hover:not(.tab-selected) ion-label{color:var(--color-header-content, white)}.ds-tab-button:hover:not(.tab-selected) ds-icon{--icon-color: var(--color-header-content, white);color:var(--color-header-content, white)}.ds-tab-button:hover:not(.tab-selected) ds-icon svg{fill:var(--color-header-content, white)}.ds-tab-button.tab-selected,.ds-tab-button.tab-selected:hover{background:var(--color-header-accent);--color-selected: var(--color-on-header-accent, white);--color: var(--color-on-header-accent, white);color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected:hover ion-label{color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected:hover ds-icon{--icon-color: var(--color-on-header-accent, white);color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected:hover ds-icon svg{fill:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected:hover .tab-icon-active{opacity:1!important;visibility:visible!important}.ds-tab-button.tab-selected:hover .tab-icon-inactive{opacity:0!important}.ds-tab-button.tab-selected ion-label{color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected ds-icon{--icon-color: var(--color-on-header-accent, white);color:var(--color-on-header-accent, white)}.ds-tab-button.tab-selected ds-icon svg{fill:var(--color-on-header-accent, white)}.ds-tab-button .button-native{width:auto;padding:0}.ds-tab-button ion-label{font-size:var(--font-size-sm);font-weight:500;margin:0;color:inherit}.ds-tab-button .tab-icon-wrapper{margin-right:4px;margin-bottom:0}.ds-tab-button ion-ripple-effect{color:rgba(var(--header-content-color-rgb, 255, 255, 255),.3);border-radius:1000px;transform:scale(1.5)}}@media (min-width: 768px){.ds-tab-bar__actions ds-avatar{cursor:pointer;transition:transform .2s ease}.ds-tab-bar__actions ds-avatar:hover{transform:scale(1.05)}}\n"] }]
|
|
10429
10437
|
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { tabs: [{
|
|
10430
10438
|
type: Input
|
|
10431
10439
|
}], avatarType: [{
|
|
@@ -10720,6 +10728,12 @@ class DsMobileSwiperComponent {
|
|
|
10720
10728
|
slideNext() {
|
|
10721
10729
|
this.swiperInstance?.slideNext();
|
|
10722
10730
|
}
|
|
10731
|
+
/**
|
|
10732
|
+
* Navigate to a specific slide by index
|
|
10733
|
+
*/
|
|
10734
|
+
slideTo(index, speed = 300) {
|
|
10735
|
+
this.swiperInstance?.slideTo(index, speed);
|
|
10736
|
+
}
|
|
10723
10737
|
/**
|
|
10724
10738
|
* Check if at the beginning
|
|
10725
10739
|
*/
|
|
@@ -16007,18 +16021,17 @@ class DsMobileNewInquiryModalComponent {
|
|
|
16007
16021
|
return;
|
|
16008
16022
|
}
|
|
16009
16023
|
try {
|
|
16010
|
-
const
|
|
16011
|
-
|
|
16012
|
-
allowEditing: false,
|
|
16013
|
-
resultType: CameraResultType.Uri,
|
|
16014
|
-
source: CameraSource.Photos, // Only show photo library
|
|
16024
|
+
const result = await FilePicker.pickImages({
|
|
16025
|
+
limit: 1,
|
|
16015
16026
|
});
|
|
16016
|
-
|
|
16027
|
+
const image = result.files?.[0];
|
|
16028
|
+
if (image) {
|
|
16017
16029
|
const newAttachment = {
|
|
16018
16030
|
id: `photo-${Date.now()}`,
|
|
16019
|
-
src: image.
|
|
16031
|
+
src: image.path ? Capacitor.convertFileSrc(image.path) : (image.blob ? URL.createObjectURL(image.blob) : ''),
|
|
16020
16032
|
type: 'image',
|
|
16021
|
-
name: `Photo ${this.attachments().length + 1}`,
|
|
16033
|
+
name: image.name || `Photo ${this.attachments().length + 1}`,
|
|
16034
|
+
size: this.formatFileSize(image.size ?? 0),
|
|
16022
16035
|
};
|
|
16023
16036
|
this.attachments.update((attachments) => [...attachments, newAttachment]);
|
|
16024
16037
|
}
|
|
@@ -16412,6 +16425,11 @@ class DsMobileBookingModalComponent {
|
|
|
16412
16425
|
modalController;
|
|
16413
16426
|
facilityId;
|
|
16414
16427
|
facilityTitle;
|
|
16428
|
+
/**
|
|
16429
|
+
* Number of days ahead available for booking selection.
|
|
16430
|
+
* Defaults to 60 (2 months). Override via componentProps when opening the modal.
|
|
16431
|
+
*/
|
|
16432
|
+
daysAhead = 60;
|
|
16415
16433
|
swiperComponent;
|
|
16416
16434
|
// Signals for reactive state management
|
|
16417
16435
|
dateOptions = signal([], ...(ngDevMode ? [{ debugName: "dateOptions" }] : []));
|
|
@@ -16442,22 +16460,50 @@ class DsMobileBookingModalComponent {
|
|
|
16442
16460
|
}
|
|
16443
16461
|
}, 150);
|
|
16444
16462
|
}
|
|
16463
|
+
/**
|
|
16464
|
+
* Returns true if the given date should be disabled in both the swiper and the datepicker.
|
|
16465
|
+
* Weekends are disabled. Index-based mock disabling (i===3, i===7) is swiper-only and
|
|
16466
|
+
* not representable as a date rule, so it is intentionally excluded here.
|
|
16467
|
+
*/
|
|
16468
|
+
isDateUnavailable(date) {
|
|
16469
|
+
return date.getDay() === 0 || date.getDay() === 6;
|
|
16470
|
+
}
|
|
16471
|
+
/**
|
|
16472
|
+
* Computed signal that returns a fresh disabled-date function whenever dateOptions()
|
|
16473
|
+
* changes. Returning a new function reference causes the datepicker's own isDateDisabled
|
|
16474
|
+
* input to update, which triggers its internal computed to re-run and re-render all
|
|
16475
|
+
* calendar cells with the correct disabled state.
|
|
16476
|
+
* The disabledSet is pre-built once per computation for O(1) per-cell lookups.
|
|
16477
|
+
*/
|
|
16478
|
+
dateDisabledFn = computed(() => {
|
|
16479
|
+
const disabledSet = new Set(this.dateOptions()
|
|
16480
|
+
.filter(opt => opt.state === 'disabled')
|
|
16481
|
+
.map(opt => opt.fullDate.toDateString()));
|
|
16482
|
+
return (date) => {
|
|
16483
|
+
const today = new Date();
|
|
16484
|
+
today.setHours(0, 0, 0, 0);
|
|
16485
|
+
const max = new Date(today);
|
|
16486
|
+
max.setDate(today.getDate() + this.daysAhead - 1);
|
|
16487
|
+
const d = new Date(date);
|
|
16488
|
+
d.setHours(0, 0, 0, 0);
|
|
16489
|
+
if (d < today || d > max)
|
|
16490
|
+
return true;
|
|
16491
|
+
return disabledSet.has(date.toDateString());
|
|
16492
|
+
};
|
|
16493
|
+
}, ...(ngDevMode ? [{ debugName: "dateDisabledFn" }] : []));
|
|
16445
16494
|
/**
|
|
16446
16495
|
* Generate mock date and time data
|
|
16447
16496
|
*/
|
|
16448
16497
|
generateMockData() {
|
|
16449
|
-
// Generate 14 days starting from today
|
|
16450
16498
|
const dates = [];
|
|
16451
16499
|
const today = new Date();
|
|
16452
16500
|
const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
16453
16501
|
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
16454
16502
|
let firstAvailableDate = null;
|
|
16455
|
-
for (let i = 0; i <
|
|
16503
|
+
for (let i = 0; i < this.daysAhead; i++) {
|
|
16456
16504
|
const date = new Date(today);
|
|
16457
16505
|
date.setDate(today.getDate() + i);
|
|
16458
|
-
|
|
16459
|
-
const isWeekend = date.getDay() === 0 || date.getDay() === 6;
|
|
16460
|
-
const isDisabled = isWeekend || (i === 3) || (i === 7); // Example: disable some dates
|
|
16506
|
+
const isDisabled = this.isDateUnavailable(date) || (i === 3) || (i === 7);
|
|
16461
16507
|
const dateOption = {
|
|
16462
16508
|
id: `date-${i}`,
|
|
16463
16509
|
dayName: dayNames[date.getDay()],
|
|
@@ -16545,6 +16591,23 @@ class DsMobileBookingModalComponent {
|
|
|
16545
16591
|
this.timeSlots.set(updatedSlots);
|
|
16546
16592
|
this.selectedTimeSlot.set(selectedSlot);
|
|
16547
16593
|
}
|
|
16594
|
+
/**
|
|
16595
|
+
* Called when the datepicker overlay emits a date selection.
|
|
16596
|
+
* Finds the matching DateOption in the swiper, selects it, and auto-scrolls to it.
|
|
16597
|
+
*/
|
|
16598
|
+
jumpToDate(date) {
|
|
16599
|
+
if (!date)
|
|
16600
|
+
return;
|
|
16601
|
+
const options = this.dateOptions();
|
|
16602
|
+
const idx = options.findIndex(opt => opt.fullDate.toDateString() === date.toDateString());
|
|
16603
|
+
if (idx === -1)
|
|
16604
|
+
return;
|
|
16605
|
+
const option = options[idx];
|
|
16606
|
+
if (option.state === 'disabled')
|
|
16607
|
+
return;
|
|
16608
|
+
this.selectDate(option);
|
|
16609
|
+
this.swiperComponent?.slideTo(idx);
|
|
16610
|
+
}
|
|
16548
16611
|
/**
|
|
16549
16612
|
* Handle confirm button click
|
|
16550
16613
|
*/
|
|
@@ -16571,7 +16634,7 @@ class DsMobileBookingModalComponent {
|
|
|
16571
16634
|
await this.modalController.dismiss(null, 'cancel');
|
|
16572
16635
|
}
|
|
16573
16636
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingModalComponent, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Component });
|
|
16574
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileBookingModalComponent, isStandalone: true, selector: "ds-mobile-booking-modal", inputs: { facilityId: "facilityId", facilityTitle: "facilityTitle" }, viewQueries: [{ propertyName: "swiperComponent", first: true, predicate: DsMobileSwiperComponent, descendants: true }], ngImport: i0, template: `
|
|
16637
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileBookingModalComponent, isStandalone: true, selector: "ds-mobile-booking-modal", inputs: { facilityId: "facilityId", facilityTitle: "facilityTitle", daysAhead: "daysAhead" }, viewQueries: [{ propertyName: "swiperComponent", first: true, predicate: DsMobileSwiperComponent, descendants: true }], ngImport: i0, template: `
|
|
16575
16638
|
<ds-mobile-modal-base
|
|
16576
16639
|
headerTitle="Hvornår skal det være?"
|
|
16577
16640
|
[showCloseButton]="true"
|
|
@@ -16580,6 +16643,16 @@ class DsMobileBookingModalComponent {
|
|
|
16580
16643
|
|
|
16581
16644
|
<!-- Date Section -->
|
|
16582
16645
|
<ds-mobile-section headline="Vælg dato">
|
|
16646
|
+
<ds-datepicker
|
|
16647
|
+
header-action
|
|
16648
|
+
[isDateDisabled]="dateDisabledFn()"
|
|
16649
|
+
(dateChange)="jumpToDate($event)">
|
|
16650
|
+
<span class="calendar-link">
|
|
16651
|
+
Vælg fra kalender
|
|
16652
|
+
<ds-icon name="remixArrowRightSLine" size="16px" />
|
|
16653
|
+
</span>
|
|
16654
|
+
</ds-datepicker>
|
|
16655
|
+
|
|
16583
16656
|
<ds-mobile-swiper
|
|
16584
16657
|
class="date-swiper"
|
|
16585
16658
|
[slideWidth]="'auto'"
|
|
@@ -16633,7 +16706,7 @@ class DsMobileBookingModalComponent {
|
|
|
16633
16706
|
</ds-button>
|
|
16634
16707
|
</div>
|
|
16635
16708
|
</ds-mobile-modal-base>
|
|
16636
|
-
`, isInline: true, styles: [".date-item{display:flex;flex-direction:column;align-items:center;justify-content:center;width:80px;padding:12px 8px;border-radius:12px;border:1px solid var(--color-border, #e5e5e5);background:var(--color-surface-primary, #ffffff);cursor:pointer;transition:all .2s ease;-webkit-tap-highlight-color:transparent;gap:4px}.date-item .day-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;color:var(--text-color-default-secondary, #71727a);text-transform:uppercase}.date-item .date-number{font-family:Brockmann,sans-serif;font-size:var(--font-size-xl, 20px);font-weight:600;color:var(--text-color-default-primary, #202227)}.date-item .month-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;color:var(--text-color-default-secondary, #71727a);text-transform:capitalize}.date-item.selected{background:var(--color-accent, #5d5fef);border-color:var(--color-accent, #5d5fef)}.date-item.selected .day-name,.date-item.selected .date-number,.date-item.selected .month-name{color:#fff}.date-item.disabled{background:var(--color-background-neutral-secondary, #f5f5f5);border-color:var(--color-border, #e5e5e5);cursor:not-allowed;opacity:.6}.date-item.disabled .day-name,.date-item.disabled .date-number,.date-item.disabled .month-name{color:var(--text-color-default-tertiary, #9a9aa2)}.date-item:not(.disabled):not(.selected):hover{border-color:var(--color-accent, #5d5fef);background:var(--color-background-neutral-secondary, #f5f5f5)}.time-slots-list{display:flex;flex-direction:column;gap:8px}.time-slot-item{display:flex;align-items:center;justify-content:space-between;width:100%;padding:16px 20px;border-radius:12px;border:1px solid var(--color-border, #e5e5e5);background:var(--color-surface-primary, #ffffff);cursor:pointer;transition:all .2s ease;-webkit-tap-highlight-color:transparent}.time-slot-item span{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);font-weight:400;color:var(--text-color-default-primary, #202227)}.time-slot-item.selected{background:var(--color-accent, #5d5fef);border-color:var(--color-accent, #5d5fef)}.time-slot-item.selected span{color:#fff;font-weight:500}.time-slot-item.disabled{background:var(--color-background-neutral-secondary, #f5f5f5);border-color:var(--color-border, #e5e5e5);cursor:not-allowed;opacity:.6}.time-slot-item.disabled span{color:var(--text-color-default-tertiary, #9a9aa2)}.time-slot-item:not(.disabled):not(.selected):hover{border-color:var(--color-accent, #5d5fef);background:var(--color-background-neutral-secondary, #f5f5f5)}.booking-confirm-action{width:100%;padding:16px 20px;background:var(--color-surface-primary, #ffffff);border-top:1px solid var(--color-border, #e5e5e5);box-sizing:border-box}.booking-confirm-action ::ng-deep ds-button{display:block;width:100%}.booking-confirm-action ::ng-deep ds-button button{width:100%;border-radius:100px;height:48px}::ng-deep .date-swiper .swiper-slide{width:auto!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsMobileModalBaseComponent, selector: "ds-mobile-modal-base", inputs: ["showHeader"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileSwiperComponent, selector: "ds-mobile-swiper", inputs: ["slideWidth", "gap", "pagination", "autoHeight", "progressiveOpacity", "progressiveScale"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsButtonComponent, selector: "ds-button", inputs: ["variant", "size", "disabled", "loading", "pressed", "expanded", "leadingIcon", "trailingIcon", "ariaLabel", "iconOnly"], outputs: ["clicked", "focused", "blurred"] }] });
|
|
16709
|
+
`, isInline: true, styles: [".date-item{display:flex;flex-direction:column;align-items:center;justify-content:center;width:80px;padding:12px 8px;border-radius:12px;border:1px solid var(--color-border, #e5e5e5);background:var(--color-surface-primary, #ffffff);cursor:pointer;transition:all .2s ease;-webkit-tap-highlight-color:transparent;gap:4px}.date-item .day-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;color:var(--text-color-default-secondary, #71727a);text-transform:uppercase}.date-item .date-number{font-family:Brockmann,sans-serif;font-size:var(--font-size-xl, 20px);font-weight:600;color:var(--text-color-default-primary, #202227)}.date-item .month-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;color:var(--text-color-default-secondary, #71727a);text-transform:capitalize}.date-item.selected{background:var(--color-accent, #5d5fef);border-color:var(--color-accent, #5d5fef)}.date-item.selected .day-name,.date-item.selected .date-number,.date-item.selected .month-name{color:#fff}.date-item.disabled{background:var(--color-background-neutral-secondary, #f5f5f5);border-color:var(--color-border, #e5e5e5);cursor:not-allowed;opacity:.6}.date-item.disabled .day-name,.date-item.disabled .date-number,.date-item.disabled .month-name{color:var(--text-color-default-tertiary, #9a9aa2)}.date-item:not(.disabled):not(.selected):hover{border-color:var(--color-accent, #5d5fef);background:var(--color-background-neutral-secondary, #f5f5f5)}.time-slots-list{display:flex;flex-direction:column;gap:8px}.time-slot-item{display:flex;align-items:center;justify-content:space-between;width:100%;padding:16px 20px;border-radius:12px;border:1px solid var(--color-border, #e5e5e5);background:var(--color-surface-primary, #ffffff);cursor:pointer;transition:all .2s ease;-webkit-tap-highlight-color:transparent}.time-slot-item span{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);font-weight:400;color:var(--text-color-default-primary, #202227)}.time-slot-item.selected{background:var(--color-accent, #5d5fef);border-color:var(--color-accent, #5d5fef)}.time-slot-item.selected span{color:#fff;font-weight:500}.time-slot-item.disabled{background:var(--color-background-neutral-secondary, #f5f5f5);border-color:var(--color-border, #e5e5e5);cursor:not-allowed;opacity:.6}.time-slot-item.disabled span{color:var(--text-color-default-tertiary, #9a9aa2)}.time-slot-item:not(.disabled):not(.selected):hover{border-color:var(--color-accent, #5d5fef);background:var(--color-background-neutral-secondary, #f5f5f5)}.booking-confirm-action{width:100%;padding:16px 20px;background:var(--color-surface-primary, #ffffff);border-top:1px solid var(--color-border, #e5e5e5);box-sizing:border-box}.booking-confirm-action ::ng-deep ds-button{display:block;width:100%}.booking-confirm-action ::ng-deep ds-button button{width:100%;border-radius:100px;height:48px}::ng-deep .date-swiper .swiper-slide{width:auto!important}.calendar-link{display:flex;align-items:center;gap:2px;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;color:var(--color-accent, #5d5fef);cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none;line-height:1}::ng-deep .cdk-overlay-container{z-index:20001}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsMobileModalBaseComponent, selector: "ds-mobile-modal-base", inputs: ["showHeader"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileSwiperComponent, selector: "ds-mobile-swiper", inputs: ["slideWidth", "gap", "pagination", "autoHeight", "progressiveOpacity", "progressiveScale"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsButtonComponent, selector: "ds-button", inputs: ["variant", "size", "disabled", "loading", "pressed", "expanded", "leadingIcon", "trailingIcon", "ariaLabel", "iconOnly"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsDatepickerComponent, selector: "ds-datepicker", inputs: ["variant", "disabled", "placeholder", "ariaLabel", "ariaDescribedBy", "disableFutureDates", "disablePastDates", "isDateDisabled", "locale"], outputs: ["dateChange", "opened", "closed"] }] });
|
|
16637
16710
|
}
|
|
16638
16711
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingModalComponent, decorators: [{
|
|
16639
16712
|
type: Component,
|
|
@@ -16643,7 +16716,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
16643
16716
|
DsMobileSectionComponent,
|
|
16644
16717
|
DsMobileSwiperComponent,
|
|
16645
16718
|
DsIconComponent,
|
|
16646
|
-
DsButtonComponent
|
|
16719
|
+
DsButtonComponent,
|
|
16720
|
+
DsDatepickerComponent
|
|
16647
16721
|
], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: `
|
|
16648
16722
|
<ds-mobile-modal-base
|
|
16649
16723
|
headerTitle="Hvornår skal det være?"
|
|
@@ -16653,6 +16727,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
16653
16727
|
|
|
16654
16728
|
<!-- Date Section -->
|
|
16655
16729
|
<ds-mobile-section headline="Vælg dato">
|
|
16730
|
+
<ds-datepicker
|
|
16731
|
+
header-action
|
|
16732
|
+
[isDateDisabled]="dateDisabledFn()"
|
|
16733
|
+
(dateChange)="jumpToDate($event)">
|
|
16734
|
+
<span class="calendar-link">
|
|
16735
|
+
Vælg fra kalender
|
|
16736
|
+
<ds-icon name="remixArrowRightSLine" size="16px" />
|
|
16737
|
+
</span>
|
|
16738
|
+
</ds-datepicker>
|
|
16739
|
+
|
|
16656
16740
|
<ds-mobile-swiper
|
|
16657
16741
|
class="date-swiper"
|
|
16658
16742
|
[slideWidth]="'auto'"
|
|
@@ -16706,11 +16790,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
16706
16790
|
</ds-button>
|
|
16707
16791
|
</div>
|
|
16708
16792
|
</ds-mobile-modal-base>
|
|
16709
|
-
`, styles: [".date-item{display:flex;flex-direction:column;align-items:center;justify-content:center;width:80px;padding:12px 8px;border-radius:12px;border:1px solid var(--color-border, #e5e5e5);background:var(--color-surface-primary, #ffffff);cursor:pointer;transition:all .2s ease;-webkit-tap-highlight-color:transparent;gap:4px}.date-item .day-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;color:var(--text-color-default-secondary, #71727a);text-transform:uppercase}.date-item .date-number{font-family:Brockmann,sans-serif;font-size:var(--font-size-xl, 20px);font-weight:600;color:var(--text-color-default-primary, #202227)}.date-item .month-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;color:var(--text-color-default-secondary, #71727a);text-transform:capitalize}.date-item.selected{background:var(--color-accent, #5d5fef);border-color:var(--color-accent, #5d5fef)}.date-item.selected .day-name,.date-item.selected .date-number,.date-item.selected .month-name{color:#fff}.date-item.disabled{background:var(--color-background-neutral-secondary, #f5f5f5);border-color:var(--color-border, #e5e5e5);cursor:not-allowed;opacity:.6}.date-item.disabled .day-name,.date-item.disabled .date-number,.date-item.disabled .month-name{color:var(--text-color-default-tertiary, #9a9aa2)}.date-item:not(.disabled):not(.selected):hover{border-color:var(--color-accent, #5d5fef);background:var(--color-background-neutral-secondary, #f5f5f5)}.time-slots-list{display:flex;flex-direction:column;gap:8px}.time-slot-item{display:flex;align-items:center;justify-content:space-between;width:100%;padding:16px 20px;border-radius:12px;border:1px solid var(--color-border, #e5e5e5);background:var(--color-surface-primary, #ffffff);cursor:pointer;transition:all .2s ease;-webkit-tap-highlight-color:transparent}.time-slot-item span{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);font-weight:400;color:var(--text-color-default-primary, #202227)}.time-slot-item.selected{background:var(--color-accent, #5d5fef);border-color:var(--color-accent, #5d5fef)}.time-slot-item.selected span{color:#fff;font-weight:500}.time-slot-item.disabled{background:var(--color-background-neutral-secondary, #f5f5f5);border-color:var(--color-border, #e5e5e5);cursor:not-allowed;opacity:.6}.time-slot-item.disabled span{color:var(--text-color-default-tertiary, #9a9aa2)}.time-slot-item:not(.disabled):not(.selected):hover{border-color:var(--color-accent, #5d5fef);background:var(--color-background-neutral-secondary, #f5f5f5)}.booking-confirm-action{width:100%;padding:16px 20px;background:var(--color-surface-primary, #ffffff);border-top:1px solid var(--color-border, #e5e5e5);box-sizing:border-box}.booking-confirm-action ::ng-deep ds-button{display:block;width:100%}.booking-confirm-action ::ng-deep ds-button button{width:100%;border-radius:100px;height:48px}::ng-deep .date-swiper .swiper-slide{width:auto!important}\n"] }]
|
|
16793
|
+
`, styles: [".date-item{display:flex;flex-direction:column;align-items:center;justify-content:center;width:80px;padding:12px 8px;border-radius:12px;border:1px solid var(--color-border, #e5e5e5);background:var(--color-surface-primary, #ffffff);cursor:pointer;transition:all .2s ease;-webkit-tap-highlight-color:transparent;gap:4px}.date-item .day-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;color:var(--text-color-default-secondary, #71727a);text-transform:uppercase}.date-item .date-number{font-family:Brockmann,sans-serif;font-size:var(--font-size-xl, 20px);font-weight:600;color:var(--text-color-default-primary, #202227)}.date-item .month-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;color:var(--text-color-default-secondary, #71727a);text-transform:capitalize}.date-item.selected{background:var(--color-accent, #5d5fef);border-color:var(--color-accent, #5d5fef)}.date-item.selected .day-name,.date-item.selected .date-number,.date-item.selected .month-name{color:#fff}.date-item.disabled{background:var(--color-background-neutral-secondary, #f5f5f5);border-color:var(--color-border, #e5e5e5);cursor:not-allowed;opacity:.6}.date-item.disabled .day-name,.date-item.disabled .date-number,.date-item.disabled .month-name{color:var(--text-color-default-tertiary, #9a9aa2)}.date-item:not(.disabled):not(.selected):hover{border-color:var(--color-accent, #5d5fef);background:var(--color-background-neutral-secondary, #f5f5f5)}.time-slots-list{display:flex;flex-direction:column;gap:8px}.time-slot-item{display:flex;align-items:center;justify-content:space-between;width:100%;padding:16px 20px;border-radius:12px;border:1px solid var(--color-border, #e5e5e5);background:var(--color-surface-primary, #ffffff);cursor:pointer;transition:all .2s ease;-webkit-tap-highlight-color:transparent}.time-slot-item span{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);font-weight:400;color:var(--text-color-default-primary, #202227)}.time-slot-item.selected{background:var(--color-accent, #5d5fef);border-color:var(--color-accent, #5d5fef)}.time-slot-item.selected span{color:#fff;font-weight:500}.time-slot-item.disabled{background:var(--color-background-neutral-secondary, #f5f5f5);border-color:var(--color-border, #e5e5e5);cursor:not-allowed;opacity:.6}.time-slot-item.disabled span{color:var(--text-color-default-tertiary, #9a9aa2)}.time-slot-item:not(.disabled):not(.selected):hover{border-color:var(--color-accent, #5d5fef);background:var(--color-background-neutral-secondary, #f5f5f5)}.booking-confirm-action{width:100%;padding:16px 20px;background:var(--color-surface-primary, #ffffff);border-top:1px solid var(--color-border, #e5e5e5);box-sizing:border-box}.booking-confirm-action ::ng-deep ds-button{display:block;width:100%}.booking-confirm-action ::ng-deep ds-button button{width:100%;border-radius:100px;height:48px}::ng-deep .date-swiper .swiper-slide{width:auto!important}.calendar-link{display:flex;align-items:center;gap:2px;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;color:var(--color-accent, #5d5fef);cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none;line-height:1}::ng-deep .cdk-overlay-container{z-index:20001}\n"] }]
|
|
16710
16794
|
}], ctorParameters: () => [{ type: i1.ModalController }], propDecorators: { facilityId: [{
|
|
16711
16795
|
type: Input
|
|
16712
16796
|
}], facilityTitle: [{
|
|
16713
16797
|
type: Input
|
|
16798
|
+
}], daysAhead: [{
|
|
16799
|
+
type: Input
|
|
16714
16800
|
}], swiperComponent: [{
|
|
16715
16801
|
type: ViewChild,
|
|
16716
16802
|
args: [DsMobileSwiperComponent]
|
|
@@ -16960,12 +17046,14 @@ class DsMobileBookingModalService extends BaseModalService {
|
|
|
16960
17046
|
* @param facilityId The ID of the facility to book
|
|
16961
17047
|
* @param facilityTitle The display name of the facility
|
|
16962
17048
|
* @param facilityThumbnail Optional thumbnail image URL
|
|
17049
|
+
* @param daysAhead Number of days ahead available for selection (defaults to 14)
|
|
16963
17050
|
* @returns Promise that resolves when the booking flow is complete
|
|
16964
17051
|
*/
|
|
16965
|
-
async open(facilityId, facilityTitle, facilityThumbnail) {
|
|
17052
|
+
async open(facilityId, facilityTitle, facilityThumbnail, daysAhead) {
|
|
16966
17053
|
const modal = await this.createModal(DsMobileBookingModalComponent, {
|
|
16967
17054
|
facilityId,
|
|
16968
|
-
facilityTitle
|
|
17055
|
+
facilityTitle,
|
|
17056
|
+
...(daysAhead !== undefined && { daysAhead })
|
|
16969
17057
|
}, { keyboardClose: true });
|
|
16970
17058
|
await modal.present();
|
|
16971
17059
|
const result = await modal.onWillDismiss();
|
|
@@ -17272,18 +17360,17 @@ class DsMobileFacilityCreationModalComponent {
|
|
|
17272
17360
|
return;
|
|
17273
17361
|
}
|
|
17274
17362
|
try {
|
|
17275
|
-
const
|
|
17276
|
-
|
|
17277
|
-
allowEditing: false,
|
|
17278
|
-
resultType: CameraResultType.Uri,
|
|
17279
|
-
source: CameraSource.Photos, // Only show photo library
|
|
17363
|
+
const result = await FilePicker.pickImages({
|
|
17364
|
+
limit: 1,
|
|
17280
17365
|
});
|
|
17281
|
-
|
|
17366
|
+
const image = result.files?.[0];
|
|
17367
|
+
if (image) {
|
|
17282
17368
|
const newAttachment = {
|
|
17283
17369
|
id: `photo-${Date.now()}`,
|
|
17284
|
-
src: image.
|
|
17370
|
+
src: image.path ? Capacitor.convertFileSrc(image.path) : (image.blob ? URL.createObjectURL(image.blob) : ''),
|
|
17285
17371
|
type: 'image',
|
|
17286
|
-
name: `Photo ${this.attachments().length + 1}`,
|
|
17372
|
+
name: image.name || `Photo ${this.attachments().length + 1}`,
|
|
17373
|
+
size: this.formatFileSize(image.size ?? 0),
|
|
17287
17374
|
};
|
|
17288
17375
|
this.attachments.update((attachments) => [...attachments, newAttachment]);
|
|
17289
17376
|
}
|
|
@@ -17454,8 +17541,8 @@ class DsMobileFacilityCreationModalComponent {
|
|
|
17454
17541
|
|
|
17455
17542
|
<!-- List Items Section -->
|
|
17456
17543
|
<ds-mobile-section [contentGap]="'0'">
|
|
17457
|
-
<!-- Who can book -->
|
|
17458
|
-
<ds-mobile-list-item
|
|
17544
|
+
<!-- Who can book - hidden until Propbinder API supports this field -->
|
|
17545
|
+
<!-- <ds-mobile-list-item
|
|
17459
17546
|
[leadingSize]="'32px'"
|
|
17460
17547
|
[showDivider]="true"
|
|
17461
17548
|
[interactive]="true"
|
|
@@ -17468,7 +17555,7 @@ class DsMobileFacilityCreationModalComponent {
|
|
|
17468
17555
|
<div class="detail-value">{{ whoCanBook() }}</div>
|
|
17469
17556
|
</div>
|
|
17470
17557
|
<ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
|
|
17471
|
-
</ds-mobile-list-item>
|
|
17558
|
+
</ds-mobile-list-item> -->
|
|
17472
17559
|
|
|
17473
17560
|
<!-- When can it be booked -->
|
|
17474
17561
|
<ds-mobile-list-item
|
|
@@ -17489,7 +17576,7 @@ class DsMobileFacilityCreationModalComponent {
|
|
|
17489
17576
|
<!-- Price -->
|
|
17490
17577
|
<ds-mobile-list-item
|
|
17491
17578
|
[leadingSize]="'32px'"
|
|
17492
|
-
[showDivider]="
|
|
17579
|
+
[showDivider]="false"
|
|
17493
17580
|
[interactive]="true"
|
|
17494
17581
|
[showDesktopMoreButton]="false"
|
|
17495
17582
|
[align]="'center'"
|
|
@@ -17502,8 +17589,8 @@ class DsMobileFacilityCreationModalComponent {
|
|
|
17502
17589
|
<ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
|
|
17503
17590
|
</ds-mobile-list-item>
|
|
17504
17591
|
|
|
17505
|
-
<!-- Access requirements -->
|
|
17506
|
-
<ds-mobile-list-item
|
|
17592
|
+
<!-- Access requirements - hidden until Propbinder API supports this field -->
|
|
17593
|
+
<!-- <ds-mobile-list-item
|
|
17507
17594
|
[leadingSize]="'32px'"
|
|
17508
17595
|
[showDivider]="false"
|
|
17509
17596
|
[interactive]="true"
|
|
@@ -17516,7 +17603,7 @@ class DsMobileFacilityCreationModalComponent {
|
|
|
17516
17603
|
<div class="detail-value">{{ accessRequirements() }}</div>
|
|
17517
17604
|
</div>
|
|
17518
17605
|
<ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
|
|
17519
|
-
</ds-mobile-list-item>
|
|
17606
|
+
</ds-mobile-list-item> -->
|
|
17520
17607
|
</ds-mobile-section>
|
|
17521
17608
|
|
|
17522
17609
|
<!-- Fixed Bottom Container (Slides with keyboard) -->
|
|
@@ -17610,8 +17697,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
17610
17697
|
|
|
17611
17698
|
<!-- List Items Section -->
|
|
17612
17699
|
<ds-mobile-section [contentGap]="'0'">
|
|
17613
|
-
<!-- Who can book -->
|
|
17614
|
-
<ds-mobile-list-item
|
|
17700
|
+
<!-- Who can book - hidden until Propbinder API supports this field -->
|
|
17701
|
+
<!-- <ds-mobile-list-item
|
|
17615
17702
|
[leadingSize]="'32px'"
|
|
17616
17703
|
[showDivider]="true"
|
|
17617
17704
|
[interactive]="true"
|
|
@@ -17624,7 +17711,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
17624
17711
|
<div class="detail-value">{{ whoCanBook() }}</div>
|
|
17625
17712
|
</div>
|
|
17626
17713
|
<ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
|
|
17627
|
-
</ds-mobile-list-item>
|
|
17714
|
+
</ds-mobile-list-item> -->
|
|
17628
17715
|
|
|
17629
17716
|
<!-- When can it be booked -->
|
|
17630
17717
|
<ds-mobile-list-item
|
|
@@ -17645,7 +17732,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
17645
17732
|
<!-- Price -->
|
|
17646
17733
|
<ds-mobile-list-item
|
|
17647
17734
|
[leadingSize]="'32px'"
|
|
17648
|
-
[showDivider]="
|
|
17735
|
+
[showDivider]="false"
|
|
17649
17736
|
[interactive]="true"
|
|
17650
17737
|
[showDesktopMoreButton]="false"
|
|
17651
17738
|
[align]="'center'"
|
|
@@ -17658,8 +17745,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
17658
17745
|
<ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
|
|
17659
17746
|
</ds-mobile-list-item>
|
|
17660
17747
|
|
|
17661
|
-
<!-- Access requirements -->
|
|
17662
|
-
<ds-mobile-list-item
|
|
17748
|
+
<!-- Access requirements - hidden until Propbinder API supports this field -->
|
|
17749
|
+
<!-- <ds-mobile-list-item
|
|
17663
17750
|
[leadingSize]="'32px'"
|
|
17664
17751
|
[showDivider]="false"
|
|
17665
17752
|
[interactive]="true"
|
|
@@ -17672,7 +17759,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
17672
17759
|
<div class="detail-value">{{ accessRequirements() }}</div>
|
|
17673
17760
|
</div>
|
|
17674
17761
|
<ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
|
|
17675
|
-
</ds-mobile-list-item>
|
|
17762
|
+
</ds-mobile-list-item> -->
|
|
17676
17763
|
</ds-mobile-section>
|
|
17677
17764
|
|
|
17678
17765
|
<!-- Fixed Bottom Container (Slides with keyboard) -->
|
|
@@ -18091,24 +18178,59 @@ var dsMobileWhoCanBookSheet = /*#__PURE__*/Object.freeze({
|
|
|
18091
18178
|
* DsMobileWhenCanBookSheetComponent
|
|
18092
18179
|
*
|
|
18093
18180
|
* Bottom sheet for selecting when a facility can be booked (days, time range, duration).
|
|
18181
|
+
* "Vælg selv" opens a drum-roll IonPopover on mobile, or inline number inputs on desktop.
|
|
18094
18182
|
*/
|
|
18095
18183
|
class DsMobileWhenCanBookSheetComponent {
|
|
18096
18184
|
modalController;
|
|
18185
|
+
platformId = inject(PLATFORM_ID);
|
|
18186
|
+
// Platform
|
|
18187
|
+
isDesktop = signal(false, ...(ngDevMode ? [{ debugName: "isDesktop" }] : []));
|
|
18097
18188
|
// State
|
|
18098
|
-
selectedDays = signal(new Set(['Fre', 'Lør', 'Søn']), ...(ngDevMode ? [{ debugName: "selectedDays" }] : []));
|
|
18189
|
+
selectedDays = signal(new Set(['Fre', 'Lør', 'Søn']), ...(ngDevMode ? [{ debugName: "selectedDays" }] : []));
|
|
18099
18190
|
startTime = signal('09:00', ...(ngDevMode ? [{ debugName: "startTime" }] : []));
|
|
18100
18191
|
endTime = signal('17:30', ...(ngDevMode ? [{ debugName: "endTime" }] : []));
|
|
18101
18192
|
selectedDuration = signal('1 time', ...(ngDevMode ? [{ debugName: "selectedDuration" }] : []));
|
|
18193
|
+
/**
|
|
18194
|
+
* Maximum number of days available in the "Vælg selv" picker/inputs.
|
|
18195
|
+
* Defaults to 30 (one full month). Override via componentProps when opening the sheet.
|
|
18196
|
+
*/
|
|
18197
|
+
maxDays = input(30, ...(ngDevMode ? [{ debugName: "maxDays" }] : []));
|
|
18198
|
+
// Custom duration state
|
|
18199
|
+
pickerOpen = signal(false, ...(ngDevMode ? [{ debugName: "pickerOpen" }] : []));
|
|
18200
|
+
customDays = signal(0, ...(ngDevMode ? [{ debugName: "customDays" }] : []));
|
|
18201
|
+
customHours = signal(1, ...(ngDevMode ? [{ debugName: "customHours" }] : []));
|
|
18202
|
+
customMinutes = signal(0, ...(ngDevMode ? [{ debugName: "customMinutes" }] : []));
|
|
18203
|
+
customDurationLabel = computed(() => {
|
|
18204
|
+
const d = this.customDays();
|
|
18205
|
+
const h = this.customHours();
|
|
18206
|
+
const m = this.customMinutes();
|
|
18207
|
+
const parts = [];
|
|
18208
|
+
if (d > 0)
|
|
18209
|
+
parts.push(`${d} dage`);
|
|
18210
|
+
if (h > 0)
|
|
18211
|
+
parts.push(`${h}t`);
|
|
18212
|
+
if (m > 0)
|
|
18213
|
+
parts.push(`${m}min`);
|
|
18214
|
+
return parts.join(' ');
|
|
18215
|
+
}, ...(ngDevMode ? [{ debugName: "customDurationLabel" }] : []));
|
|
18216
|
+
showInlineInputs = computed(() => this.selectedDuration() === 'Vælg selv' && this.isDesktop(), ...(ngDevMode ? [{ debugName: "showInlineInputs" }] : []));
|
|
18102
18217
|
// Options
|
|
18103
18218
|
days = ['Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør', 'Søn'];
|
|
18104
18219
|
durations = [
|
|
18105
18220
|
{ value: '30 min', label: '30 min' },
|
|
18106
18221
|
{ value: '1 time', label: '1 time' },
|
|
18107
18222
|
{ value: '2 timer', label: '2 timer' },
|
|
18223
|
+
{ value: 'Hele dagen', label: 'Hele dagen' },
|
|
18108
18224
|
{ value: 'Vælg selv', label: 'Vælg selv' }
|
|
18109
18225
|
];
|
|
18226
|
+
daysOptions = computed(() => Array.from({ length: this.maxDays() + 1 }, (_, i) => i), ...(ngDevMode ? [{ debugName: "daysOptions" }] : []));
|
|
18227
|
+
hours = Array.from({ length: 24 }, (_, i) => i);
|
|
18228
|
+
minuteOptions = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];
|
|
18110
18229
|
// Validation
|
|
18111
18230
|
isValid = computed(() => {
|
|
18231
|
+
if (this.selectedDuration() === 'Vælg selv' && this.customDurationLabel() === '') {
|
|
18232
|
+
return false;
|
|
18233
|
+
}
|
|
18112
18234
|
return this.selectedDays().size > 0 &&
|
|
18113
18235
|
this.startTime() &&
|
|
18114
18236
|
this.endTime();
|
|
@@ -18116,6 +18238,50 @@ class DsMobileWhenCanBookSheetComponent {
|
|
|
18116
18238
|
constructor(modalController) {
|
|
18117
18239
|
this.modalController = modalController;
|
|
18118
18240
|
}
|
|
18241
|
+
ngOnInit() {
|
|
18242
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
18243
|
+
this.isDesktop.set(window.innerWidth >= 768);
|
|
18244
|
+
window.addEventListener('resize', () => {
|
|
18245
|
+
this.isDesktop.set(window.innerWidth >= 768);
|
|
18246
|
+
});
|
|
18247
|
+
}
|
|
18248
|
+
}
|
|
18249
|
+
/**
|
|
18250
|
+
* Handle duration chip selection.
|
|
18251
|
+
* On mobile, opening "Vælg selv" triggers the IonPopover via its trigger id.
|
|
18252
|
+
* On desktop, it shows the inline inputs.
|
|
18253
|
+
*/
|
|
18254
|
+
selectDuration(value) {
|
|
18255
|
+
this.selectedDuration.set(value);
|
|
18256
|
+
if (value === 'Vælg selv' && !this.isDesktop()) {
|
|
18257
|
+
this.pickerOpen.set(true);
|
|
18258
|
+
}
|
|
18259
|
+
}
|
|
18260
|
+
/**
|
|
18261
|
+
* Normalizes days/hours/minutes so values never overflow their units.
|
|
18262
|
+
* e.g. 0d 48t 0min → 2d 0t 0min; 0d 0t 75min → 0d 1t 15min.
|
|
18263
|
+
* Caps days at maxDays().
|
|
18264
|
+
*/
|
|
18265
|
+
normalize() {
|
|
18266
|
+
const totalMinutes = this.customDays() * 24 * 60
|
|
18267
|
+
+ this.customHours() * 60
|
|
18268
|
+
+ this.customMinutes();
|
|
18269
|
+
const maxTotalMinutes = this.maxDays() * 24 * 60 + 23 * 60 + 59;
|
|
18270
|
+
const clamped = Math.max(0, Math.min(totalMinutes, maxTotalMinutes));
|
|
18271
|
+
const d = Math.floor(clamped / (24 * 60));
|
|
18272
|
+
const h = Math.floor((clamped % (24 * 60)) / 60);
|
|
18273
|
+
const m = clamped % 60;
|
|
18274
|
+
this.customDays.set(d);
|
|
18275
|
+
this.customHours.set(h);
|
|
18276
|
+
this.customMinutes.set(m);
|
|
18277
|
+
}
|
|
18278
|
+
/**
|
|
18279
|
+
* Called when the mobile picker popover is dismissed — normalize and commit.
|
|
18280
|
+
*/
|
|
18281
|
+
onPickerDismiss() {
|
|
18282
|
+
this.normalize();
|
|
18283
|
+
this.pickerOpen.set(false);
|
|
18284
|
+
}
|
|
18119
18285
|
/**
|
|
18120
18286
|
* Toggle day selection
|
|
18121
18287
|
*/
|
|
@@ -18128,10 +18294,13 @@ class DsMobileWhenCanBookSheetComponent {
|
|
|
18128
18294
|
* Confirm selection and dismiss with data
|
|
18129
18295
|
*/
|
|
18130
18296
|
confirmSelection() {
|
|
18297
|
+
const duration = this.selectedDuration() === 'Vælg selv'
|
|
18298
|
+
? this.customDurationLabel()
|
|
18299
|
+
: this.selectedDuration();
|
|
18131
18300
|
const data = {
|
|
18132
18301
|
days: Array.from(this.selectedDays()),
|
|
18133
18302
|
timeRange: { start: this.startTime(), end: this.endTime() },
|
|
18134
|
-
duration
|
|
18303
|
+
duration
|
|
18135
18304
|
};
|
|
18136
18305
|
this.modalController.dismiss({ value: data }, 'select');
|
|
18137
18306
|
}
|
|
@@ -18142,7 +18311,7 @@ class DsMobileWhenCanBookSheetComponent {
|
|
|
18142
18311
|
this.modalController.dismiss(null, 'cancel');
|
|
18143
18312
|
}
|
|
18144
18313
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileWhenCanBookSheetComponent, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Component });
|
|
18145
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileWhenCanBookSheetComponent, isStandalone: true, selector: "ds-mobile-when-can-book-sheet", ngImport: i0, template: `
|
|
18314
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileWhenCanBookSheetComponent, isStandalone: true, selector: "ds-mobile-when-can-book-sheet", inputs: { maxDays: { classPropertyName: "maxDays", publicName: "maxDays", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
18146
18315
|
<ds-mobile-bottom-sheet-wrapper>
|
|
18147
18316
|
<!-- Header with back and done buttons -->
|
|
18148
18317
|
<ds-mobile-bottom-sheet-header
|
|
@@ -18175,9 +18344,9 @@ class DsMobileWhenCanBookSheetComponent {
|
|
|
18175
18344
|
<div class="section">
|
|
18176
18345
|
<ds-label size="md" className="form-section-label">I tidsrummet</ds-label>
|
|
18177
18346
|
<div class="time-inputs">
|
|
18178
|
-
<ds-input-time [(ngModel)]="startTime"></ds-input-time>
|
|
18347
|
+
<ds-input-time size="lg" [(ngModel)]="startTime"></ds-input-time>
|
|
18179
18348
|
<span class="separator">til</span>
|
|
18180
|
-
<ds-input-time [(ngModel)]="endTime"></ds-input-time>
|
|
18349
|
+
<ds-input-time size="lg" [(ngModel)]="endTime"></ds-input-time>
|
|
18181
18350
|
</div>
|
|
18182
18351
|
</div>
|
|
18183
18352
|
|
|
@@ -18189,16 +18358,79 @@ class DsMobileWhenCanBookSheetComponent {
|
|
|
18189
18358
|
<button
|
|
18190
18359
|
type="button"
|
|
18191
18360
|
class="duration-chip"
|
|
18361
|
+
[id]="duration.value === 'Vælg selv' ? 'vaelg-selv-chip' : null"
|
|
18192
18362
|
[class.active]="selectedDuration() === duration.value"
|
|
18193
|
-
(click)="
|
|
18194
|
-
|
|
18363
|
+
(click)="selectDuration(duration.value)">
|
|
18364
|
+
@if (duration.value === 'Vælg selv' && selectedDuration() === 'Vælg selv') {
|
|
18365
|
+
{{ customDurationLabel() || 'Vælg selv' }}
|
|
18366
|
+
} @else {
|
|
18367
|
+
{{ duration.label }}
|
|
18368
|
+
}
|
|
18195
18369
|
</button>
|
|
18196
18370
|
}
|
|
18197
18371
|
</div>
|
|
18372
|
+
|
|
18373
|
+
<!-- Desktop: inline inputs shown when "Vælg selv" is active -->
|
|
18374
|
+
@if (showInlineInputs()) {
|
|
18375
|
+
<div class="custom-duration-inputs">
|
|
18376
|
+
<input
|
|
18377
|
+
type="number"
|
|
18378
|
+
class="duration-number-input"
|
|
18379
|
+
min="0"
|
|
18380
|
+
[ngModel]="customHours()"
|
|
18381
|
+
(ngModelChange)="customHours.set(+$event)"
|
|
18382
|
+
(blur)="normalize()"
|
|
18383
|
+
/>
|
|
18384
|
+
<span class="duration-unit">timer</span>
|
|
18385
|
+
<input
|
|
18386
|
+
type="number"
|
|
18387
|
+
class="duration-number-input"
|
|
18388
|
+
min="0"
|
|
18389
|
+
max="59"
|
|
18390
|
+
[ngModel]="customMinutes()"
|
|
18391
|
+
(ngModelChange)="customMinutes.set(+$event)"
|
|
18392
|
+
(blur)="normalize()"
|
|
18393
|
+
/>
|
|
18394
|
+
<span class="duration-unit">min</span>
|
|
18395
|
+
</div>
|
|
18396
|
+
}
|
|
18397
|
+
|
|
18398
|
+
<!-- Mobile: drum-roll popover anchored to the "Vælg selv" chip -->
|
|
18399
|
+
@if (!isDesktop()) {
|
|
18400
|
+
<ds-mobile-dropdown
|
|
18401
|
+
trigger="vaelg-selv-chip"
|
|
18402
|
+
[isOpen]="pickerOpen()"
|
|
18403
|
+
maxWidth="240px"
|
|
18404
|
+
position="above"
|
|
18405
|
+
(closed)="onPickerDismiss()">
|
|
18406
|
+
<ng-template #customContent>
|
|
18407
|
+
<ion-picker style="--background: transparent; --fade-background-rgb: transparent; --highlight-background: rgba(0, 0, 0, 0.05); --highlight-border-radius: 9999px;">
|
|
18408
|
+
<ion-picker-column
|
|
18409
|
+
[value]="customHours()"
|
|
18410
|
+
style="--padding-start: 4px; --padding-end: 4px;"
|
|
18411
|
+
(ionChange)="customHours.set(+($event.detail.value ?? customHours()))">
|
|
18412
|
+
<div slot="suffix" class="picker-suffix">t</div>
|
|
18413
|
+
@for (h of hours; track h) {
|
|
18414
|
+
<ion-picker-column-option [value]="h">{{ h }}</ion-picker-column-option>
|
|
18415
|
+
}
|
|
18416
|
+
</ion-picker-column>
|
|
18417
|
+
<ion-picker-column
|
|
18418
|
+
[value]="customMinutes()"
|
|
18419
|
+
style="--padding-start: 4px; --padding-end: 4px;"
|
|
18420
|
+
(ionChange)="customMinutes.set(+($event.detail.value ?? customMinutes()))">
|
|
18421
|
+
<div slot="suffix" class="picker-suffix">min</div>
|
|
18422
|
+
@for (m of minuteOptions; track m) {
|
|
18423
|
+
<ion-picker-column-option [value]="m">{{ m }}</ion-picker-column-option>
|
|
18424
|
+
}
|
|
18425
|
+
</ion-picker-column>
|
|
18426
|
+
</ion-picker>
|
|
18427
|
+
</ng-template>
|
|
18428
|
+
</ds-mobile-dropdown>
|
|
18429
|
+
}
|
|
18198
18430
|
</div>
|
|
18199
18431
|
</div>
|
|
18200
18432
|
</ds-mobile-bottom-sheet-wrapper>
|
|
18201
|
-
`, isInline: true, styles: [".form-content{padding:16px}.section{margin-bottom:24px}.section:last-child{margin-bottom:0}::ng-deep ds-label.form-section-label{display:block;margin-bottom:12px}::ng-deep .form-section-label{font-weight:500}.day-chips{display:flex;gap:8px;flex-wrap:wrap;width:100%}.day-chip{flex:
|
|
18433
|
+
`, isInline: true, styles: [".form-content{padding:16px}.section{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.section:last-child{margin-bottom:0}::ng-deep ds-label.form-section-label{display:block;margin-bottom:12px}::ng-deep .form-section-label{font-weight:500}.day-chips{display:flex;gap:8px;flex-wrap:wrap;width:100%}.day-chip{flex:none;width:64px;padding:10px 16px;border:1px solid var(--border-color-default, #d1d5db);border-radius:8px;background:transparent;color:var(--color-text-primary);font-size:14px;font-weight:500;cursor:pointer;transition:all .2s ease;outline:none}.day-chip:hover{background:var(--color-bg-secondary)}.day-chip.active{background:var(--color-accent);color:#fff;border-color:var(--color-accent)}.time-inputs{display:flex;align-items:center;gap:12px}.separator{color:var(--color-text-secondary);font-size:14px}.duration-chips{display:flex;gap:8px;flex-wrap:wrap}.duration-chip{padding:10px 16px;border:1px solid var(--border-color-default, #d1d5db);border-radius:8px;background:transparent;color:var(--color-text-primary);font-size:14px;font-weight:500;cursor:pointer;transition:all .2s ease;outline:none}.duration-chip:hover{background:var(--color-bg-secondary)}.duration-chip.active{background:var(--color-accent);color:#fff;border-color:var(--color-accent)}.custom-duration-inputs{display:flex;align-items:center;gap:8px;margin-top:12px;animation:fadeSlideIn .15s ease}@keyframes fadeSlideIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.duration-number-input{width:64px;padding:8px 10px;border:1px solid var(--border-color-default, #d1d5db);border-radius:8px;background:transparent;color:var(--color-text-primary);font-size:14px;font-weight:500;text-align:center;outline:none;transition:border-color .2s ease}.duration-number-input:focus{border-color:var(--color-accent)}.duration-number-input::-webkit-inner-spin-button,.duration-number-input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.duration-number-input[type=number]{-moz-appearance:textfield}.duration-unit{color:var(--color-text-secondary);font-size:14px}.picker-suffix{margin-left:-24px;font-size:13px;color:var(--color-text-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$3.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: DsInputTimeComponent, selector: "ds-input-time", inputs: ["variant", "disabled", "readonly", "required", "clearable", "ghost", "size", "ariaLabel", "ariaDescribedBy", "ariaLabelledBy"], outputs: ["valueChange"] }, { kind: "component", type: DsLabelComponent, selector: "ds-label", inputs: ["className", "for", "id", "size"] }, { kind: "component", type: DsMobileBottomSheetWrapperComponent, selector: "ds-mobile-bottom-sheet-wrapper" }, { kind: "component", type: DsMobileBottomSheetHeaderComponent, selector: "ds-mobile-bottom-sheet-header", inputs: ["title", "leftButtonLabel", "rightButtonLabel", "rightButtonDisabled"], outputs: ["leftButtonClick", "rightButtonClick"] }, { kind: "component", type: DsMobileDropdownComponent, selector: "ds-mobile-dropdown", inputs: ["trigger", "keepFocusOn", "items", "isOpen", "position", "align", "maxHeight", "emptyMessage", "ariaLabel", "maxWidth"], outputs: ["itemSelected", "closed"] }, { kind: "component", type: IonPicker, selector: "ion-picker", inputs: ["mode"] }, { kind: "component", type: IonPickerColumn, selector: "ion-picker-column", inputs: ["color", "disabled", "mode", "value"] }, { kind: "component", type: IonPickerColumnOption, selector: "ion-picker-column-option", inputs: ["color", "disabled", "value"] }] });
|
|
18202
18434
|
}
|
|
18203
18435
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileWhenCanBookSheetComponent, decorators: [{
|
|
18204
18436
|
type: Component,
|
|
@@ -18208,7 +18440,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
18208
18440
|
DsInputTimeComponent,
|
|
18209
18441
|
DsLabelComponent,
|
|
18210
18442
|
DsMobileBottomSheetWrapperComponent,
|
|
18211
|
-
DsMobileBottomSheetHeaderComponent
|
|
18443
|
+
DsMobileBottomSheetHeaderComponent,
|
|
18444
|
+
DsMobileDropdownComponent,
|
|
18445
|
+
IonPicker,
|
|
18446
|
+
IonPickerColumn,
|
|
18447
|
+
IonPickerColumnOption,
|
|
18212
18448
|
], template: `
|
|
18213
18449
|
<ds-mobile-bottom-sheet-wrapper>
|
|
18214
18450
|
<!-- Header with back and done buttons -->
|
|
@@ -18242,9 +18478,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
18242
18478
|
<div class="section">
|
|
18243
18479
|
<ds-label size="md" className="form-section-label">I tidsrummet</ds-label>
|
|
18244
18480
|
<div class="time-inputs">
|
|
18245
|
-
<ds-input-time [(ngModel)]="startTime"></ds-input-time>
|
|
18481
|
+
<ds-input-time size="lg" [(ngModel)]="startTime"></ds-input-time>
|
|
18246
18482
|
<span class="separator">til</span>
|
|
18247
|
-
<ds-input-time [(ngModel)]="endTime"></ds-input-time>
|
|
18483
|
+
<ds-input-time size="lg" [(ngModel)]="endTime"></ds-input-time>
|
|
18248
18484
|
</div>
|
|
18249
18485
|
</div>
|
|
18250
18486
|
|
|
@@ -18256,17 +18492,80 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
18256
18492
|
<button
|
|
18257
18493
|
type="button"
|
|
18258
18494
|
class="duration-chip"
|
|
18495
|
+
[id]="duration.value === 'Vælg selv' ? 'vaelg-selv-chip' : null"
|
|
18259
18496
|
[class.active]="selectedDuration() === duration.value"
|
|
18260
|
-
(click)="
|
|
18261
|
-
|
|
18497
|
+
(click)="selectDuration(duration.value)">
|
|
18498
|
+
@if (duration.value === 'Vælg selv' && selectedDuration() === 'Vælg selv') {
|
|
18499
|
+
{{ customDurationLabel() || 'Vælg selv' }}
|
|
18500
|
+
} @else {
|
|
18501
|
+
{{ duration.label }}
|
|
18502
|
+
}
|
|
18262
18503
|
</button>
|
|
18263
18504
|
}
|
|
18264
18505
|
</div>
|
|
18506
|
+
|
|
18507
|
+
<!-- Desktop: inline inputs shown when "Vælg selv" is active -->
|
|
18508
|
+
@if (showInlineInputs()) {
|
|
18509
|
+
<div class="custom-duration-inputs">
|
|
18510
|
+
<input
|
|
18511
|
+
type="number"
|
|
18512
|
+
class="duration-number-input"
|
|
18513
|
+
min="0"
|
|
18514
|
+
[ngModel]="customHours()"
|
|
18515
|
+
(ngModelChange)="customHours.set(+$event)"
|
|
18516
|
+
(blur)="normalize()"
|
|
18517
|
+
/>
|
|
18518
|
+
<span class="duration-unit">timer</span>
|
|
18519
|
+
<input
|
|
18520
|
+
type="number"
|
|
18521
|
+
class="duration-number-input"
|
|
18522
|
+
min="0"
|
|
18523
|
+
max="59"
|
|
18524
|
+
[ngModel]="customMinutes()"
|
|
18525
|
+
(ngModelChange)="customMinutes.set(+$event)"
|
|
18526
|
+
(blur)="normalize()"
|
|
18527
|
+
/>
|
|
18528
|
+
<span class="duration-unit">min</span>
|
|
18529
|
+
</div>
|
|
18530
|
+
}
|
|
18531
|
+
|
|
18532
|
+
<!-- Mobile: drum-roll popover anchored to the "Vælg selv" chip -->
|
|
18533
|
+
@if (!isDesktop()) {
|
|
18534
|
+
<ds-mobile-dropdown
|
|
18535
|
+
trigger="vaelg-selv-chip"
|
|
18536
|
+
[isOpen]="pickerOpen()"
|
|
18537
|
+
maxWidth="240px"
|
|
18538
|
+
position="above"
|
|
18539
|
+
(closed)="onPickerDismiss()">
|
|
18540
|
+
<ng-template #customContent>
|
|
18541
|
+
<ion-picker style="--background: transparent; --fade-background-rgb: transparent; --highlight-background: rgba(0, 0, 0, 0.05); --highlight-border-radius: 9999px;">
|
|
18542
|
+
<ion-picker-column
|
|
18543
|
+
[value]="customHours()"
|
|
18544
|
+
style="--padding-start: 4px; --padding-end: 4px;"
|
|
18545
|
+
(ionChange)="customHours.set(+($event.detail.value ?? customHours()))">
|
|
18546
|
+
<div slot="suffix" class="picker-suffix">t</div>
|
|
18547
|
+
@for (h of hours; track h) {
|
|
18548
|
+
<ion-picker-column-option [value]="h">{{ h }}</ion-picker-column-option>
|
|
18549
|
+
}
|
|
18550
|
+
</ion-picker-column>
|
|
18551
|
+
<ion-picker-column
|
|
18552
|
+
[value]="customMinutes()"
|
|
18553
|
+
style="--padding-start: 4px; --padding-end: 4px;"
|
|
18554
|
+
(ionChange)="customMinutes.set(+($event.detail.value ?? customMinutes()))">
|
|
18555
|
+
<div slot="suffix" class="picker-suffix">min</div>
|
|
18556
|
+
@for (m of minuteOptions; track m) {
|
|
18557
|
+
<ion-picker-column-option [value]="m">{{ m }}</ion-picker-column-option>
|
|
18558
|
+
}
|
|
18559
|
+
</ion-picker-column>
|
|
18560
|
+
</ion-picker>
|
|
18561
|
+
</ng-template>
|
|
18562
|
+
</ds-mobile-dropdown>
|
|
18563
|
+
}
|
|
18265
18564
|
</div>
|
|
18266
18565
|
</div>
|
|
18267
18566
|
</ds-mobile-bottom-sheet-wrapper>
|
|
18268
|
-
`, styles: [".form-content{padding:16px}.section{margin-bottom:24px}.section:last-child{margin-bottom:0}::ng-deep ds-label.form-section-label{display:block;margin-bottom:12px}::ng-deep .form-section-label{font-weight:500}.day-chips{display:flex;gap:8px;flex-wrap:wrap;width:100%}.day-chip{flex:
|
|
18269
|
-
}], ctorParameters: () => [{ type: i1.ModalController }] });
|
|
18567
|
+
`, styles: [".form-content{padding:16px}.section{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.section:last-child{margin-bottom:0}::ng-deep ds-label.form-section-label{display:block;margin-bottom:12px}::ng-deep .form-section-label{font-weight:500}.day-chips{display:flex;gap:8px;flex-wrap:wrap;width:100%}.day-chip{flex:none;width:64px;padding:10px 16px;border:1px solid var(--border-color-default, #d1d5db);border-radius:8px;background:transparent;color:var(--color-text-primary);font-size:14px;font-weight:500;cursor:pointer;transition:all .2s ease;outline:none}.day-chip:hover{background:var(--color-bg-secondary)}.day-chip.active{background:var(--color-accent);color:#fff;border-color:var(--color-accent)}.time-inputs{display:flex;align-items:center;gap:12px}.separator{color:var(--color-text-secondary);font-size:14px}.duration-chips{display:flex;gap:8px;flex-wrap:wrap}.duration-chip{padding:10px 16px;border:1px solid var(--border-color-default, #d1d5db);border-radius:8px;background:transparent;color:var(--color-text-primary);font-size:14px;font-weight:500;cursor:pointer;transition:all .2s ease;outline:none}.duration-chip:hover{background:var(--color-bg-secondary)}.duration-chip.active{background:var(--color-accent);color:#fff;border-color:var(--color-accent)}.custom-duration-inputs{display:flex;align-items:center;gap:8px;margin-top:12px;animation:fadeSlideIn .15s ease}@keyframes fadeSlideIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.duration-number-input{width:64px;padding:8px 10px;border:1px solid var(--border-color-default, #d1d5db);border-radius:8px;background:transparent;color:var(--color-text-primary);font-size:14px;font-weight:500;text-align:center;outline:none;transition:border-color .2s ease}.duration-number-input:focus{border-color:var(--color-accent)}.duration-number-input::-webkit-inner-spin-button,.duration-number-input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.duration-number-input[type=number]{-moz-appearance:textfield}.duration-unit{color:var(--color-text-secondary);font-size:14px}.picker-suffix{margin-left:-24px;font-size:13px;color:var(--color-text-secondary)}\n"] }]
|
|
18568
|
+
}], ctorParameters: () => [{ type: i1.ModalController }], propDecorators: { maxDays: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDays", required: false }] }] } });
|
|
18270
18569
|
|
|
18271
18570
|
var dsMobileWhenCanBookSheet = /*#__PURE__*/Object.freeze({
|
|
18272
18571
|
__proto__: null,
|
|
@@ -18317,7 +18616,7 @@ class DsMobilePriceSheetComponent {
|
|
|
18317
18616
|
this.modalController.dismiss(null, 'cancel');
|
|
18318
18617
|
}
|
|
18319
18618
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobilePriceSheetComponent, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Component });
|
|
18320
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
18619
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobilePriceSheetComponent, isStandalone: true, selector: "ds-mobile-price-sheet", ngImport: i0, template: `
|
|
18321
18620
|
<ds-mobile-bottom-sheet-wrapper>
|
|
18322
18621
|
<!-- Header with back and done buttons -->
|
|
18323
18622
|
<ds-mobile-bottom-sheet-header
|
|
@@ -18330,29 +18629,33 @@ class DsMobilePriceSheetComponent {
|
|
|
18330
18629
|
</ds-mobile-bottom-sheet-header>
|
|
18331
18630
|
|
|
18332
18631
|
<div class="form-content">
|
|
18333
|
-
|
|
18334
|
-
|
|
18335
|
-
<
|
|
18336
|
-
|
|
18337
|
-
<div class="toggle-
|
|
18632
|
+
<div class="price-toggle-container">
|
|
18633
|
+
<!-- Toggle for Gratis -->
|
|
18634
|
+
<div class="toggle-row" (click)="toggleFree()">
|
|
18635
|
+
<ds-label size="md" className="form-section-label">Gratis</ds-label>
|
|
18636
|
+
<div class="toggle-switch" [class.active]="isFree()">
|
|
18637
|
+
<div class="toggle-knob"></div>
|
|
18638
|
+
</div>
|
|
18338
18639
|
</div>
|
|
18339
|
-
</div>
|
|
18340
18640
|
|
|
18341
|
-
|
|
18342
|
-
|
|
18343
|
-
|
|
18344
|
-
|
|
18345
|
-
|
|
18346
|
-
|
|
18347
|
-
|
|
18348
|
-
|
|
18349
|
-
|
|
18350
|
-
|
|
18351
|
-
|
|
18641
|
+
<!-- Custom price input inside same container -->
|
|
18642
|
+
@if (!isFree()) {
|
|
18643
|
+
<div class="price-input-row" (click)="$event.stopPropagation()">
|
|
18644
|
+
<ds-label size="md" className="form-section-label">Hvad skal det koste?</ds-label>
|
|
18645
|
+
<ds-input
|
|
18646
|
+
type="number"
|
|
18647
|
+
size="lg"
|
|
18648
|
+
[(ngModel)]="customPrice"
|
|
18649
|
+
placeholder="75"
|
|
18650
|
+
[suffix]="'kr. per booking'"
|
|
18651
|
+
class="price-input">
|
|
18652
|
+
</ds-input>
|
|
18653
|
+
</div>
|
|
18654
|
+
}
|
|
18352
18655
|
</div>
|
|
18353
18656
|
</div>
|
|
18354
18657
|
</ds-mobile-bottom-sheet-wrapper>
|
|
18355
|
-
`, isInline: true, styles: [".form-content{padding:16px}.toggle-
|
|
18658
|
+
`, isInline: true, styles: [".form-content{padding:16px}.price-toggle-container{display:flex;flex-direction:column;background:var(--color-background-neutral-primary, #f5f5f5);border:1px solid var(--border-color-default);border-radius:12px;margin-bottom:24px;overflow:hidden}.toggle-row{display:flex;justify-content:space-between;align-items:center;padding:16px;cursor:pointer;transition:background .2s ease}.toggle-row:hover{background:var(--color-background-neutral-primary-hover, #ebebeb)}::ng-deep ds-label.form-section-label{display:block;margin-bottom:8px}::ng-deep .form-section-label{font-weight:500}.toggle-switch{width:51px;height:32px;background:var(--color-background-neutral-tertiary);border-radius:16px;position:relative;transition:background .3s ease;cursor:pointer}.toggle-switch.active{background:var(--color-accent)}.toggle-knob{width:27px;height:27px;background:#fff;border-radius:50%;position:absolute;top:2px;left:2px;transition:transform .3s ease;box-shadow:0 2px 4px #0000001a}.toggle-switch.active .toggle-knob{transform:translate(20px)}.price-input-row{display:flex;flex-direction:column;gap:8px;padding:16px;border-top:1px solid var(--border-color-default)}::ng-deep .price-input .ds-input__field{height:48px!important;min-height:48px!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: DsInputComponent, selector: "ds-input", inputs: ["variant", "type", "placeholder", "disabled", "readonly", "required", "clearable", "ghost", "size", "leadingIcon", "trailingIcon", "prefix", "suffix", "format", "align", "ariaLabel", "ariaDescribedBy", "ariaLabelledBy"], outputs: ["valueChange", "focused", "blurred"] }, { kind: "component", type: DsLabelComponent, selector: "ds-label", inputs: ["className", "for", "id", "size"] }, { kind: "component", type: DsMobileBottomSheetWrapperComponent, selector: "ds-mobile-bottom-sheet-wrapper" }, { kind: "component", type: DsMobileBottomSheetHeaderComponent, selector: "ds-mobile-bottom-sheet-header", inputs: ["title", "leftButtonLabel", "rightButtonLabel", "rightButtonDisabled"], outputs: ["leftButtonClick", "rightButtonClick"] }] });
|
|
18356
18659
|
}
|
|
18357
18660
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobilePriceSheetComponent, decorators: [{
|
|
18358
18661
|
type: Component,
|
|
@@ -18376,29 +18679,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
18376
18679
|
</ds-mobile-bottom-sheet-header>
|
|
18377
18680
|
|
|
18378
18681
|
<div class="form-content">
|
|
18379
|
-
|
|
18380
|
-
|
|
18381
|
-
<
|
|
18382
|
-
|
|
18383
|
-
<div class="toggle-
|
|
18682
|
+
<div class="price-toggle-container">
|
|
18683
|
+
<!-- Toggle for Gratis -->
|
|
18684
|
+
<div class="toggle-row" (click)="toggleFree()">
|
|
18685
|
+
<ds-label size="md" className="form-section-label">Gratis</ds-label>
|
|
18686
|
+
<div class="toggle-switch" [class.active]="isFree()">
|
|
18687
|
+
<div class="toggle-knob"></div>
|
|
18688
|
+
</div>
|
|
18384
18689
|
</div>
|
|
18385
|
-
</div>
|
|
18386
18690
|
|
|
18387
|
-
|
|
18388
|
-
|
|
18389
|
-
|
|
18390
|
-
|
|
18391
|
-
|
|
18392
|
-
|
|
18393
|
-
|
|
18394
|
-
|
|
18395
|
-
|
|
18396
|
-
|
|
18397
|
-
|
|
18691
|
+
<!-- Custom price input inside same container -->
|
|
18692
|
+
@if (!isFree()) {
|
|
18693
|
+
<div class="price-input-row" (click)="$event.stopPropagation()">
|
|
18694
|
+
<ds-label size="md" className="form-section-label">Hvad skal det koste?</ds-label>
|
|
18695
|
+
<ds-input
|
|
18696
|
+
type="number"
|
|
18697
|
+
size="lg"
|
|
18698
|
+
[(ngModel)]="customPrice"
|
|
18699
|
+
placeholder="75"
|
|
18700
|
+
[suffix]="'kr. per booking'"
|
|
18701
|
+
class="price-input">
|
|
18702
|
+
</ds-input>
|
|
18703
|
+
</div>
|
|
18704
|
+
}
|
|
18398
18705
|
</div>
|
|
18399
18706
|
</div>
|
|
18400
18707
|
</ds-mobile-bottom-sheet-wrapper>
|
|
18401
|
-
`, styles: [".form-content{padding:16px}.toggle-
|
|
18708
|
+
`, styles: [".form-content{padding:16px}.price-toggle-container{display:flex;flex-direction:column;background:var(--color-background-neutral-primary, #f5f5f5);border:1px solid var(--border-color-default);border-radius:12px;margin-bottom:24px;overflow:hidden}.toggle-row{display:flex;justify-content:space-between;align-items:center;padding:16px;cursor:pointer;transition:background .2s ease}.toggle-row:hover{background:var(--color-background-neutral-primary-hover, #ebebeb)}::ng-deep ds-label.form-section-label{display:block;margin-bottom:8px}::ng-deep .form-section-label{font-weight:500}.toggle-switch{width:51px;height:32px;background:var(--color-background-neutral-tertiary);border-radius:16px;position:relative;transition:background .3s ease;cursor:pointer}.toggle-switch.active{background:var(--color-accent)}.toggle-knob{width:27px;height:27px;background:#fff;border-radius:50%;position:absolute;top:2px;left:2px;transition:transform .3s ease;box-shadow:0 2px 4px #0000001a}.toggle-switch.active .toggle-knob{transform:translate(20px)}.price-input-row{display:flex;flex-direction:column;gap:8px;padding:16px;border-top:1px solid var(--border-color-default)}::ng-deep .price-input .ds-input__field{height:48px!important;min-height:48px!important}\n"] }]
|
|
18402
18709
|
}], ctorParameters: () => [{ type: i1.ModalController }] });
|
|
18403
18710
|
|
|
18404
18711
|
var dsMobilePriceSheet = /*#__PURE__*/Object.freeze({
|
|
@@ -18599,25 +18906,6 @@ class DsMobileFacilityDetailModalComponent {
|
|
|
18599
18906
|
</div>
|
|
18600
18907
|
</ds-mobile-swiper>
|
|
18601
18908
|
|
|
18602
|
-
@if (facilityData.requirements || facilityData.bookingType) {
|
|
18603
|
-
<div class="info-items-container">
|
|
18604
|
-
<h2 class="section-headline">Ting, du skal vide</h2>
|
|
18605
|
-
@if (facilityData.requirements) {
|
|
18606
|
-
@for (requirement of facilityData.requirements; track requirement) {
|
|
18607
|
-
<div class="info-item">
|
|
18608
|
-
<ds-icon name="remixKeyLine" size="16px" color="--text-color-default-secondary" />
|
|
18609
|
-
<span>{{ requirement }}</span>
|
|
18610
|
-
</div>
|
|
18611
|
-
}
|
|
18612
|
-
}
|
|
18613
|
-
@if (facilityData.bookingType) {
|
|
18614
|
-
<div class="info-item">
|
|
18615
|
-
<ds-icon name="remixCheckboxCircleLine" size="16px" color="--text-color-default-secondary" />
|
|
18616
|
-
<span>{{ facilityData.bookingType }}</span>
|
|
18617
|
-
</div>
|
|
18618
|
-
}
|
|
18619
|
-
</div>
|
|
18620
|
-
}
|
|
18621
18909
|
</ds-mobile-section>
|
|
18622
18910
|
}
|
|
18623
18911
|
|
|
@@ -18681,25 +18969,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
18681
18969
|
</div>
|
|
18682
18970
|
</ds-mobile-swiper>
|
|
18683
18971
|
|
|
18684
|
-
@if (facilityData.requirements || facilityData.bookingType) {
|
|
18685
|
-
<div class="info-items-container">
|
|
18686
|
-
<h2 class="section-headline">Ting, du skal vide</h2>
|
|
18687
|
-
@if (facilityData.requirements) {
|
|
18688
|
-
@for (requirement of facilityData.requirements; track requirement) {
|
|
18689
|
-
<div class="info-item">
|
|
18690
|
-
<ds-icon name="remixKeyLine" size="16px" color="--text-color-default-secondary" />
|
|
18691
|
-
<span>{{ requirement }}</span>
|
|
18692
|
-
</div>
|
|
18693
|
-
}
|
|
18694
|
-
}
|
|
18695
|
-
@if (facilityData.bookingType) {
|
|
18696
|
-
<div class="info-item">
|
|
18697
|
-
<ds-icon name="remixCheckboxCircleLine" size="16px" color="--text-color-default-secondary" />
|
|
18698
|
-
<span>{{ facilityData.bookingType }}</span>
|
|
18699
|
-
</div>
|
|
18700
|
-
}
|
|
18701
|
-
</div>
|
|
18702
|
-
}
|
|
18703
18972
|
</ds-mobile-section>
|
|
18704
18973
|
}
|
|
18705
18974
|
|
|
@@ -21863,11 +22132,91 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
21863
22132
|
args: ['pageComponent']
|
|
21864
22133
|
}] } });
|
|
21865
22134
|
|
|
22135
|
+
class TrackingPermissionService {
|
|
22136
|
+
trackingPromptRequestedKey = 'tracking_prompt_requested_v1';
|
|
22137
|
+
platform = inject(Platform);
|
|
22138
|
+
trackingSettingsReminder = signal(false, ...(ngDevMode ? [{ debugName: "trackingSettingsReminder" }] : []));
|
|
22139
|
+
showTrackingSettingsReminder = this.trackingSettingsReminder.asReadonly();
|
|
22140
|
+
async requestOnFirstHomeEntry() {
|
|
22141
|
+
if (!this.isNativeIos()) {
|
|
22142
|
+
this.trackingSettingsReminder.set(false);
|
|
22143
|
+
return;
|
|
22144
|
+
}
|
|
22145
|
+
if (this.hasRequestedTrackingPrompt()) {
|
|
22146
|
+
await this.refreshTrackingStatus();
|
|
22147
|
+
return;
|
|
22148
|
+
}
|
|
22149
|
+
try {
|
|
22150
|
+
const { status } = await AppTrackingTransparency.getStatus();
|
|
22151
|
+
if (status === 'notDetermined') {
|
|
22152
|
+
await AppTrackingTransparency.requestPermission();
|
|
22153
|
+
}
|
|
22154
|
+
}
|
|
22155
|
+
catch (error) {
|
|
22156
|
+
console.log('Unable to request app tracking permission:', error);
|
|
22157
|
+
}
|
|
22158
|
+
finally {
|
|
22159
|
+
this.setTrackingPromptRequested();
|
|
22160
|
+
await this.refreshTrackingStatus();
|
|
22161
|
+
}
|
|
22162
|
+
}
|
|
22163
|
+
async getTrackingStatus() {
|
|
22164
|
+
if (!this.isNativeIos()) {
|
|
22165
|
+
return null;
|
|
22166
|
+
}
|
|
22167
|
+
try {
|
|
22168
|
+
const { status } = await AppTrackingTransparency.getStatus();
|
|
22169
|
+
return status;
|
|
22170
|
+
}
|
|
22171
|
+
catch (error) {
|
|
22172
|
+
console.log('Unable to read app tracking status:', error);
|
|
22173
|
+
return null;
|
|
22174
|
+
}
|
|
22175
|
+
}
|
|
22176
|
+
async openAppSettings() {
|
|
22177
|
+
if (!this.isNativeIos()) {
|
|
22178
|
+
return;
|
|
22179
|
+
}
|
|
22180
|
+
// iOS deep link for opening this app's system settings page.
|
|
22181
|
+
window.location.href = 'app-settings:';
|
|
22182
|
+
}
|
|
22183
|
+
shouldShowSettingsReminder() {
|
|
22184
|
+
return this.trackingSettingsReminder();
|
|
22185
|
+
}
|
|
22186
|
+
async refreshTrackingStatus() {
|
|
22187
|
+
if (!this.isNativeIos()) {
|
|
22188
|
+
this.trackingSettingsReminder.set(false);
|
|
22189
|
+
return;
|
|
22190
|
+
}
|
|
22191
|
+
const status = await this.getTrackingStatus();
|
|
22192
|
+
const hasRequested = this.hasRequestedTrackingPrompt();
|
|
22193
|
+
this.trackingSettingsReminder.set(Boolean(hasRequested && status && status !== 'authorized'));
|
|
22194
|
+
}
|
|
22195
|
+
isNativeIos() {
|
|
22196
|
+
return this.platform.is('ios') && this.platform.is('capacitor');
|
|
22197
|
+
}
|
|
22198
|
+
hasRequestedTrackingPrompt() {
|
|
22199
|
+
return localStorage.getItem(this.trackingPromptRequestedKey) === '1';
|
|
22200
|
+
}
|
|
22201
|
+
setTrackingPromptRequested() {
|
|
22202
|
+
localStorage.setItem(this.trackingPromptRequestedKey, '1');
|
|
22203
|
+
}
|
|
22204
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TrackingPermissionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
22205
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TrackingPermissionService, providedIn: 'root' });
|
|
22206
|
+
}
|
|
22207
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TrackingPermissionService, decorators: [{
|
|
22208
|
+
type: Injectable,
|
|
22209
|
+
args: [{
|
|
22210
|
+
providedIn: 'root',
|
|
22211
|
+
}]
|
|
22212
|
+
}] });
|
|
22213
|
+
|
|
21866
22214
|
class MobileHomePageComponent {
|
|
21867
22215
|
router;
|
|
21868
22216
|
userService;
|
|
21869
22217
|
postsService;
|
|
21870
22218
|
postModal;
|
|
22219
|
+
trackingPermissionService;
|
|
21871
22220
|
pageComponent;
|
|
21872
22221
|
// Get recent posts from PostsService - exclude pinned post (post-4) and limit to 3
|
|
21873
22222
|
recentPosts = computed(() => this.postsService.posts()
|
|
@@ -21901,13 +22250,17 @@ class MobileHomePageComponent {
|
|
|
21901
22250
|
openInquiries = computed(() => this.allInquiries()
|
|
21902
22251
|
.filter(inquiry => inquiry.status === 'open')
|
|
21903
22252
|
.slice(0, 3), ...(ngDevMode ? [{ debugName: "openInquiries" }] : []));
|
|
21904
|
-
constructor(router, userService, postsService, postModal) {
|
|
22253
|
+
constructor(router, userService, postsService, postModal, trackingPermissionService) {
|
|
21905
22254
|
this.router = router;
|
|
21906
22255
|
this.userService = userService;
|
|
21907
22256
|
this.postsService = postsService;
|
|
21908
22257
|
this.postModal = postModal;
|
|
22258
|
+
this.trackingPermissionService = trackingPermissionService;
|
|
21909
22259
|
console.log('MobileHomePageComponent constructor');
|
|
21910
22260
|
}
|
|
22261
|
+
ngOnInit() {
|
|
22262
|
+
void this.trackingPermissionService.requestOnFirstHomeEntry();
|
|
22263
|
+
}
|
|
21911
22264
|
handleRefresh(event) {
|
|
21912
22265
|
console.log('Pull-to-refresh triggered');
|
|
21913
22266
|
setTimeout(() => {
|
|
@@ -21944,7 +22297,7 @@ class MobileHomePageComponent {
|
|
|
21944
22297
|
console.log('Navigating to inquiries page');
|
|
21945
22298
|
this.router.navigate(['/inquiries']);
|
|
21946
22299
|
}
|
|
21947
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MobileHomePageComponent, deps: [{ token: i1$4.Router }, { token: UserService }, { token: PostsService }, { token: DsMobilePostDetailModalService }], target: i0.ɵɵFactoryTarget.Component });
|
|
22300
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MobileHomePageComponent, deps: [{ token: i1$4.Router }, { token: UserService }, { token: PostsService }, { token: DsMobilePostDetailModalService }, { token: TrackingPermissionService }], target: i0.ɵɵFactoryTarget.Component });
|
|
21948
22301
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MobileHomePageComponent, isStandalone: true, selector: "app-home-page", viewQueries: [{ propertyName: "pageComponent", first: true, predicate: ["pageComponent"], descendants: true }], ngImport: i0, template: `
|
|
21949
22302
|
<ds-mobile-page-main
|
|
21950
22303
|
#pageComponent
|
|
@@ -22196,7 +22549,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
22196
22549
|
</ds-mobile-section>
|
|
22197
22550
|
</ds-mobile-page-main>
|
|
22198
22551
|
`, styles: [".posts-list,.inquiries-list{display:flex;flex-direction:column}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;text-align:center}.empty-state ds-button{display:block;margin-top:16px}.empty-state ds-button::ng-deep .btn{width:100%;border-radius:9999px}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}\n"] }]
|
|
22199
|
-
}], ctorParameters: () => [{ type: i1$4.Router }, { type: UserService }, { type: PostsService }, { type: DsMobilePostDetailModalService }], propDecorators: { pageComponent: [{
|
|
22552
|
+
}], ctorParameters: () => [{ type: i1$4.Router }, { type: UserService }, { type: PostsService }, { type: DsMobilePostDetailModalService }, { type: TrackingPermissionService }], propDecorators: { pageComponent: [{
|
|
22200
22553
|
type: ViewChild,
|
|
22201
22554
|
args: ['pageComponent']
|
|
22202
22555
|
}] } });
|
|
@@ -24089,18 +24442,80 @@ class MobileTabsExampleComponent {
|
|
|
24089
24442
|
userService;
|
|
24090
24443
|
router;
|
|
24091
24444
|
whitelabelDemoModal = inject(WhitelabelDemoModalService);
|
|
24445
|
+
trackingPermissionService = inject(TrackingPermissionService);
|
|
24446
|
+
trackedProfileMenuItems = computed(() => {
|
|
24447
|
+
const accountActions = [
|
|
24448
|
+
{
|
|
24449
|
+
action: 'profile',
|
|
24450
|
+
title: 'Min profil',
|
|
24451
|
+
icon: 'remixUser3Line',
|
|
24452
|
+
destructive: false,
|
|
24453
|
+
},
|
|
24454
|
+
{
|
|
24455
|
+
action: 'settings',
|
|
24456
|
+
title: 'Indstillinger',
|
|
24457
|
+
icon: 'remixSettings3Line',
|
|
24458
|
+
destructive: false,
|
|
24459
|
+
},
|
|
24460
|
+
{
|
|
24461
|
+
action: 'appearance',
|
|
24462
|
+
title: 'Udseende',
|
|
24463
|
+
icon: 'remixPaletteLine',
|
|
24464
|
+
destructive: false,
|
|
24465
|
+
},
|
|
24466
|
+
];
|
|
24467
|
+
if (this.trackingPermissionService.shouldShowSettingsReminder()) {
|
|
24468
|
+
accountActions.push({
|
|
24469
|
+
action: 'tracking-settings',
|
|
24470
|
+
title: 'Sporingsindstillinger',
|
|
24471
|
+
icon: 'remixSettings3Line',
|
|
24472
|
+
destructive: false,
|
|
24473
|
+
});
|
|
24474
|
+
}
|
|
24475
|
+
return [
|
|
24476
|
+
{
|
|
24477
|
+
actions: accountActions,
|
|
24478
|
+
},
|
|
24479
|
+
{
|
|
24480
|
+
actions: [
|
|
24481
|
+
{
|
|
24482
|
+
action: 'language',
|
|
24483
|
+
title: 'Sprog',
|
|
24484
|
+
subtitle: 'Dansk',
|
|
24485
|
+
flagIcon: '/Assets/country-flags/denmark.svg',
|
|
24486
|
+
icon: 'remixGlobalLine',
|
|
24487
|
+
destructive: false,
|
|
24488
|
+
showChevron: true,
|
|
24489
|
+
},
|
|
24490
|
+
],
|
|
24491
|
+
},
|
|
24492
|
+
{
|
|
24493
|
+
actions: [
|
|
24494
|
+
{
|
|
24495
|
+
action: 'logout',
|
|
24496
|
+
title: 'Log ud',
|
|
24497
|
+
icon: 'remixLogoutBoxLine',
|
|
24498
|
+
destructive: true,
|
|
24499
|
+
},
|
|
24500
|
+
],
|
|
24501
|
+
},
|
|
24502
|
+
];
|
|
24503
|
+
}, ...(ngDevMode ? [{ debugName: "trackedProfileMenuItems" }] : []));
|
|
24092
24504
|
constructor(userService, router) {
|
|
24093
24505
|
this.userService = userService;
|
|
24094
24506
|
this.router = router;
|
|
24095
24507
|
console.log('MobileTabsExampleComponent constructor');
|
|
24508
|
+
effect(() => {
|
|
24509
|
+
this.userService.setProfileMenuItems(this.trackedProfileMenuItems());
|
|
24510
|
+
});
|
|
24096
24511
|
}
|
|
24097
24512
|
ngOnInit() {
|
|
24098
24513
|
console.log('MobileTabsExampleComponent ngOnInit');
|
|
24099
24514
|
// Configure user avatar globally - this is now the single source of truth
|
|
24100
24515
|
this.userService.setAvatarInitials('LM');
|
|
24101
24516
|
this.userService.setAvatarType('initials');
|
|
24102
|
-
//
|
|
24103
|
-
this.
|
|
24517
|
+
// Initial status refresh ensures menu reflects past ATT choice.
|
|
24518
|
+
void this.trackingPermissionService.refreshTrackingStatus();
|
|
24104
24519
|
}
|
|
24105
24520
|
tabs = [
|
|
24106
24521
|
{
|
|
@@ -24146,53 +24561,7 @@ class MobileTabsExampleComponent {
|
|
|
24146
24561
|
* throughout the entire application.
|
|
24147
24562
|
*/
|
|
24148
24563
|
get profileMenuItems() {
|
|
24149
|
-
return
|
|
24150
|
-
{
|
|
24151
|
-
actions: [
|
|
24152
|
-
{
|
|
24153
|
-
action: 'profile',
|
|
24154
|
-
title: 'Min profil',
|
|
24155
|
-
icon: 'remixUser3Line',
|
|
24156
|
-
destructive: false,
|
|
24157
|
-
},
|
|
24158
|
-
{
|
|
24159
|
-
action: 'settings',
|
|
24160
|
-
title: 'Indstillinger',
|
|
24161
|
-
icon: 'remixSettings3Line',
|
|
24162
|
-
destructive: false,
|
|
24163
|
-
},
|
|
24164
|
-
{
|
|
24165
|
-
action: 'appearance',
|
|
24166
|
-
title: 'Udseende',
|
|
24167
|
-
icon: 'remixPaletteLine',
|
|
24168
|
-
destructive: false,
|
|
24169
|
-
},
|
|
24170
|
-
],
|
|
24171
|
-
},
|
|
24172
|
-
{
|
|
24173
|
-
actions: [
|
|
24174
|
-
{
|
|
24175
|
-
action: 'language',
|
|
24176
|
-
title: 'Sprog',
|
|
24177
|
-
subtitle: 'Dansk',
|
|
24178
|
-
flagIcon: '/Assets/country-flags/denmark.svg',
|
|
24179
|
-
icon: 'remixGlobalLine',
|
|
24180
|
-
destructive: false,
|
|
24181
|
-
showChevron: true,
|
|
24182
|
-
},
|
|
24183
|
-
],
|
|
24184
|
-
},
|
|
24185
|
-
{
|
|
24186
|
-
actions: [
|
|
24187
|
-
{
|
|
24188
|
-
action: 'logout',
|
|
24189
|
-
title: 'Log ud',
|
|
24190
|
-
icon: 'remixLogoutBoxLine',
|
|
24191
|
-
destructive: true,
|
|
24192
|
-
},
|
|
24193
|
-
],
|
|
24194
|
-
},
|
|
24195
|
-
];
|
|
24564
|
+
return this.trackedProfileMenuItems();
|
|
24196
24565
|
}
|
|
24197
24566
|
/**
|
|
24198
24567
|
* Handle profile menu action selection.
|
|
@@ -24504,6 +24873,7 @@ class MobileBookingPageComponent {
|
|
|
24504
24873
|
[bookingTime]="booking.bookingTime || ''"
|
|
24505
24874
|
[align]="'center'"
|
|
24506
24875
|
[clickable]="true"
|
|
24876
|
+
[enableLongPress]="false"
|
|
24507
24877
|
[showChevron]="false"
|
|
24508
24878
|
(bookingClick)="openFacilityDetail(booking.id)"
|
|
24509
24879
|
/>
|
|
@@ -24611,6 +24981,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
24611
24981
|
[bookingTime]="booking.bookingTime || ''"
|
|
24612
24982
|
[align]="'center'"
|
|
24613
24983
|
[clickable]="true"
|
|
24984
|
+
[enableLongPress]="false"
|
|
24614
24985
|
[showChevron]="false"
|
|
24615
24986
|
(bookingClick)="openFacilityDetail(booking.id)"
|
|
24616
24987
|
/>
|