@propbinder/mobile-design 0.3.38 → 0.3.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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, computed, effect, Injectable, inject, Input, Component, input, output, Directive, EventEmitter, HostListener, Output, PLATFORM_ID, ElementRef, CUSTOM_ELEMENTS_SCHEMA, TemplateRef, ContentChild, forwardRef, ViewChild, afterNextRender, ViewEncapsulation, model, createComponent, ChangeDetectionStrategy, NgZone, Pipe, HostBinding, InjectionToken } from '@angular/core';
2
+ import { signal, computed, effect, Injectable, inject, Input, Component, input, output, Directive, EventEmitter, HostListener, Output, PLATFORM_ID, ElementRef, CUSTOM_ELEMENTS_SCHEMA, TemplateRef, ContentChild, forwardRef, ViewChild, afterNextRender, ViewEncapsulation, model, createComponent, ChangeDetectionStrategy, NgZone, HostBinding, Pipe, InjectionToken } from '@angular/core';
3
3
  import * as i1$1 from '@angular/common';
4
4
  import { CommonModule, isPlatformBrowser } from '@angular/common';
5
5
  import * as i1$3 from '@angular/router';
@@ -665,62 +665,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
665
665
  }] } });
666
666
 
667
667
  /**
668
- * DsMobileGlassSpinnerComponent
668
+ * DsMobileSkeletonLoaderComponent
669
669
  *
670
- * Reusable loader overlay with a glassmorphism (blurred) background and a spinner.
671
- * This is useful when you want to show a loading state without covering the entire screen
672
- * with a solid background, but rather blurring the content behind it.
670
+ * Reusable skeleton list loader overlay.
671
+ * Features a modern shimmer layout representing list data.
673
672
  *
674
673
  * Features:
675
- * - Glassmorphism blurred background
676
- * - Centered animated spinner
677
- * - Customizable spinner size
678
- * - Absolute positioning to cover parent
674
+ * - Skeleton list layout mimicking standard data rows
675
+ * - Shimmer animation effect
676
+ * - Transparent background (overlays content directly)
679
677
  */
680
- class DsMobileGlassSpinnerComponent {
681
- /**
682
- * Size of the spinner in pixels
683
- * @default 24
684
- */
685
- spinnerSize = input(24, ...(ngDevMode ? [{ debugName: "spinnerSize" }] : []));
678
+ class DsMobileSkeletonLoaderComponent {
686
679
  /**
687
680
  * Border radius of the overlay in pixels (should match parent's border radius)
688
681
  * @default 0
689
682
  */
690
683
  borderRadius = input(0, ...(ngDevMode ? [{ debugName: "borderRadius" }] : []));
691
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileGlassSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
692
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: DsMobileGlassSpinnerComponent, isStandalone: true, selector: "ds-mobile-glass-spinner", inputs: { spinnerSize: { classPropertyName: "spinnerSize", publicName: "spinnerSize", isSignal: true, isRequired: false, transformFunction: null }, borderRadius: { classPropertyName: "borderRadius", publicName: "borderRadius", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
693
- <div
694
- class="glass-spinner-overlay"
695
- [style.border-radius.px]="borderRadius()"
696
- role="status"
697
- aria-live="polite"
698
- aria-label="Loading">
699
- <div
700
- class="spinner"
701
- [style.width.px]="spinnerSize()"
702
- [style.height.px]="spinnerSize()">
703
- </div>
704
- </div>
705
- `, isInline: true, styles: [":host{display:contents}.glass-spinner-overlay{position:absolute;inset:0;background:#fff6;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:9999;border-radius:inherit}.spinner{border:2px solid var(--color-border-neutral-secondary, #E5E5E5);border-top-color:var(--color-accent, #6B5FF5);border-radius:50%;animation:spin .6s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-color-scheme: dark){.glass-spinner-overlay{background:#0000004d}.spinner{border-color:#fff3;border-top-color:var(--color-accent, #6B5FF5)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
684
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileSkeletonLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
685
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileSkeletonLoaderComponent, isStandalone: true, selector: "ds-mobile-skeleton-loader", inputs: { borderRadius: { classPropertyName: "borderRadius", publicName: "borderRadius", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
686
+ <div
687
+ class="skeleton-loader-overlay"
688
+ [style.border-radius.px]="borderRadius()"
689
+ role="status"
690
+ aria-live="polite"
691
+ aria-label="Loading">
692
+ <div class="skeleton-list">
693
+ <!-- Generate 4 skeleton rows to mimic a generic list -->
694
+ @for (i of [1, 2, 3, 4]; track i) {
695
+ <div class="skeleton-item">
696
+ <div class="skeleton-avatar shimmer"></div>
697
+ <div class="skeleton-text-container">
698
+ <div class="skeleton-text-line shimmer"></div>
699
+ <div class="skeleton-text-line shimmer short"></div>
700
+ </div>
701
+ </div>
702
+ }
703
+ </div>
704
+ </div>
705
+ `, isInline: true, styles: [":host{display:contents}.skeleton-loader-overlay{position:absolute;inset:0;display:flex;flex-direction:column;z-index:9999;border-radius:inherit;padding:16px;overflow:hidden;pointer-events:none}.skeleton-list{display:flex;flex-direction:column;gap:24px;width:100%}.skeleton-item{display:flex;flex-direction:row;align-items:center;gap:16px;width:100%}.skeleton-avatar{width:48px;height:48px;border-radius:50%;flex-shrink:0}.skeleton-text-container{display:flex;flex-direction:column;gap:10px;flex-grow:1}.skeleton-text-line{height:12px;border-radius:6px;width:100%}.skeleton-text-line.short{width:60%}.shimmer{background:var(--color-background-tertiary, #f0f0f0);background-image:linear-gradient(90deg,#fff0 0,#ffffff80 40px,#fff0 80px);background-size:600px 100%;animation:shimmer 1.5s infinite linear}@keyframes shimmer{0%{background-position:-300px 0}to{background-position:300px 0}}@media (prefers-color-scheme: dark){.shimmer{background:var(--color-background-tertiary-dark, #2a2a2a);background-image:linear-gradient(90deg,#fff0 0,#ffffff0d 40px,#fff0 80px)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
706
706
  }
707
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileGlassSpinnerComponent, decorators: [{
707
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileSkeletonLoaderComponent, decorators: [{
708
708
  type: Component,
709
- args: [{ selector: 'ds-mobile-glass-spinner', standalone: true, imports: [CommonModule], template: `
710
- <div
711
- class="glass-spinner-overlay"
712
- [style.border-radius.px]="borderRadius()"
713
- role="status"
714
- aria-live="polite"
715
- aria-label="Loading">
716
- <div
717
- class="spinner"
718
- [style.width.px]="spinnerSize()"
719
- [style.height.px]="spinnerSize()">
720
- </div>
721
- </div>
722
- `, styles: [":host{display:contents}.glass-spinner-overlay{position:absolute;inset:0;background:#fff6;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:9999;border-radius:inherit}.spinner{border:2px solid var(--color-border-neutral-secondary, #E5E5E5);border-top-color:var(--color-accent, #6B5FF5);border-radius:50%;animation:spin .6s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-color-scheme: dark){.glass-spinner-overlay{background:#0000004d}.spinner{border-color:#fff3;border-top-color:var(--color-accent, #6B5FF5)}}\n"] }]
723
- }], propDecorators: { spinnerSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "spinnerSize", required: false }] }], borderRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "borderRadius", required: false }] }] } });
709
+ args: [{ selector: 'ds-mobile-skeleton-loader', standalone: true, imports: [CommonModule], template: `
710
+ <div
711
+ class="skeleton-loader-overlay"
712
+ [style.border-radius.px]="borderRadius()"
713
+ role="status"
714
+ aria-live="polite"
715
+ aria-label="Loading">
716
+ <div class="skeleton-list">
717
+ <!-- Generate 4 skeleton rows to mimic a generic list -->
718
+ @for (i of [1, 2, 3, 4]; track i) {
719
+ <div class="skeleton-item">
720
+ <div class="skeleton-avatar shimmer"></div>
721
+ <div class="skeleton-text-container">
722
+ <div class="skeleton-text-line shimmer"></div>
723
+ <div class="skeleton-text-line shimmer short"></div>
724
+ </div>
725
+ </div>
726
+ }
727
+ </div>
728
+ </div>
729
+ `, styles: [":host{display:contents}.skeleton-loader-overlay{position:absolute;inset:0;display:flex;flex-direction:column;z-index:9999;border-radius:inherit;padding:16px;overflow:hidden;pointer-events:none}.skeleton-list{display:flex;flex-direction:column;gap:24px;width:100%}.skeleton-item{display:flex;flex-direction:row;align-items:center;gap:16px;width:100%}.skeleton-avatar{width:48px;height:48px;border-radius:50%;flex-shrink:0}.skeleton-text-container{display:flex;flex-direction:column;gap:10px;flex-grow:1}.skeleton-text-line{height:12px;border-radius:6px;width:100%}.skeleton-text-line.short{width:60%}.shimmer{background:var(--color-background-tertiary, #f0f0f0);background-image:linear-gradient(90deg,#fff0 0,#ffffff80 40px,#fff0 80px);background-size:600px 100%;animation:shimmer 1.5s infinite linear}@keyframes shimmer{0%{background-position:-300px 0}to{background-position:300px 0}}@media (prefers-color-scheme: dark){.shimmer{background:var(--color-background-tertiary-dark, #2a2a2a);background-image:linear-gradient(90deg,#fff0 0,#ffffff0d 40px,#fff0 80px)}}\n"] }]
730
+ }], propDecorators: { borderRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "borderRadius", required: false }] }] } });
724
731
 
725
732
  class DsMobileCountBadgeComponent {
726
733
  count = input.required(...(ngDevMode ? [{ debugName: "count" }] : []));
@@ -6186,7 +6193,7 @@ class DsMobilePageMainComponent extends MobilePageBase {
6186
6193
 
6187
6194
  <!-- Pull to refresh (only on native iOS/Android) -->
6188
6195
  @if (showRefresh() && isNativePlatform()) {
6189
- <ion-refresher slot="fixed" (ionRefresh)="handleRefresh($event)" [pullFactor]="0.4" [pullMin]="80" [pullMax]="240" closeDuration="600ms">
6196
+ <ion-refresher slot="fixed" (ionRefresh)="handleRefresh($event)" [pullFactor]="0.5" [pullMin]="80" [pullMax]="240" [snapbackDuration]="'280ms'" closeDuration="280ms">
6190
6197
  <ion-refresher-content pullingIcon="remixArrowDownS" refreshingSpinner="crescent"> </ion-refresher-content>
6191
6198
  </ion-refresher>
6192
6199
  }
@@ -6211,7 +6218,7 @@ class DsMobilePageMainComponent extends MobilePageBase {
6211
6218
  <!-- Content wrapper -->
6212
6219
  <div class="content-wrapper">
6213
6220
  @if (contentLoading()) {
6214
- <ds-mobile-glass-spinner [borderRadius]="24" />
6221
+ <ds-mobile-skeleton-loader [borderRadius]="24" />
6215
6222
  }
6216
6223
 
6217
6224
  <!-- Offline indicator slot (appears at top of content) -->
@@ -6223,11 +6230,11 @@ class DsMobilePageMainComponent extends MobilePageBase {
6223
6230
  </div>
6224
6231
  </div>
6225
6232
  </ion-content>
6226
- `, isInline: true, styles: [":host{display:flex;flex-direction:column;align-items:center;height:100%;background:var(--color-header-surface);width:100%}:host ion-header{background:var(--color-header-surface);box-shadow:none;height:72px;min-height:72px;margin-top:var(--app-header-top-offset)}:host ion-header ion-toolbar{--background: var(--color-header-surface);--border-width: 0;--box-shadow: none;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 72px;height:72px;min-height:72px;padding:0}@media (min-width: 768px){:host ion-header{height:88px;min-height:88px}:host ion-header ion-toolbar{--min-height: 88px;height:88px;min-height:88px}}@media (min-width: 768px){:host ion-header{display:none;height:auto}}:host .header-main,:host .header-details,.header-details{display:flex;align-items:center;justify-content:space-between;background:var(--color-header-surface);position:relative}:host .header-main__title,:host .header-details .header-title,.header-details .header-title{position:absolute;left:50%;transform:translate(-50%);font-size:var(--font-size-base);font-weight:600;color:var(--color-header-content);margin:0;padding:0;--color: var(--color-header-content)}.header-details .header-title{transform:translate(-50%) translateY(-100%);opacity:0!important;pointer-events:none;transition:transform .2s ease,opacity .2s ease!important}.header-scrolled .header-details .header-title{opacity:1!important;pointer-events:auto;transform:translate(-50%) translateY(0)}:host .header-details .back-button,.header-details .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--color-header-content);transition:opacity var(--transition-duration-fast, .2s) var(--ease-smooth, ease);z-index:10;position:relative}:host .header-details .back-button:hover,.header-details .back-button:hover{opacity:.8}:host .header-details .back-button:active,.header-details .back-button:active{opacity:.6}:host ion-content{--background: var(--color-header-surface);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;border-radius:24px 24px 0 0;overflow:hidden}:host ion-content::part(scroll){display:flex;flex-direction:column;min-height:100%;-webkit-overflow-scrolling:touch}.plt-ios :host ion-content{--background: var(--color-background-neutral-primary)}@media (min-width: 768px){:host ion-content{border-radius:24px 24px 0 0}}:host ion-header[collapse=condense]{display:none}@media (min-width: 768px){:host ion-header[collapse=condense]{display:none}}:host ion-refresher{z-index:0}:host ion-refresher-content{--color: var(--color-header-content)}:host .content-wrapper{width:100%;position:relative;z-index:20;flex:1;display:flex;flex-direction:column;background:var(--color-background-neutral-primary);border-radius:24px 24px 0 0;overflow:visible;transform:translateZ(0);will-change:transform;isolation:isolate;box-shadow:0 300px 0 0 var(--color-background-neutral-primary);padding-top:0;padding-left:var(--content-wrapper-padding, 20px);padding-right:var(--content-wrapper-padding, 20px);padding-bottom:calc(var(--mobile-content-spacing) + var(--mobile-tab-bar-height) + var(--app-safe-bottom, 0px))}:host .content-inner{max-width:640px;margin:0 auto;width:100%}@media (min-width: 768px){:host .content-wrapper{padding-top:0;padding-left:var(--content-wrapper-padding, 20px);padding-right:var(--content-wrapper-padding, 20px)}}:host .header-expandable{background:var(--color-header-surface);padding:32px 20px 24px;color:var(--header-content-color, white);position:sticky;top:0;z-index:5;transition:opacity .1s ease-out,transform .1s ease-out;flex:0 0 auto;min-height:-moz-min-content;min-height:min-content}:host .header-expandable-inner{display:flex;flex-direction:column;gap:20px;max-width:640px;margin:0 auto}:host .header-expandable__text{margin-bottom:0;gap:4px;display:flex;flex-direction:column}:host .header-expandable__title{font-size:var(--font-size-2xl);font-weight:600;color:var(--header-content-color, white);margin:0}:host .header-expandable__subtitle{font-size:var(--font-size-sm);font-weight:400;color:var(--header-content-color, white);opacity:.85;margin:0}@media (min-width: 768px){:host .header-expandable{padding:48px 20px 32px}:host .header-expandable__title{font-size:var(--font-size-3xl)}:host .header-expandable__subtitle{font-size:var(--font-size-base)}}@media (min-width: 992px){:host .header-expandable{padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){:host .header-expandable{padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){:host .header-expandable{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){:host .header-expandable{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}\n", ".header-main{padding:0 20px;height:72px}.header-main__title{transform:translate(-50%) translateY(-100%);opacity:0;transition:transform .6s ease,opacity .6s ease;padding:0;--color: var(--color-header-content)}.header-scrolled .header-main__title{opacity:1;transform:translate(-50%) translateY(0)}.header-main__actions{display:flex;align-items:center;gap:8px}.header-main__actions ds-avatar{cursor:pointer;-webkit-tap-highlight-color:transparent}@keyframes logoSlideIn{0%{transform:translateY(-200%);scale:.75;opacity:0}to{transform:translateY(0);scale:1;opacity:1}}.logo--first-entry{animation:logoSlideIn .75s var(--spring-curve-bouncy) .7s both}@media (min-width: 768px){.header-main{padding:16px 24px;height:88px}.header-main__title{display:none}}ion-refresher{--color: var(--color-header-content)}ion-refresher-content{--color: var(--color-header-content)}ion-refresher-content::part(spinner){color:var(--color-header-content)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { 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"] }, { kind: "component", type: DsMobileGlassSpinnerComponent, selector: "ds-mobile-glass-spinner", inputs: ["spinnerSize", "borderRadius"] }, { kind: "component", type: DsMobileNotificationButtonComponent, selector: "ds-mobile-notification-button", inputs: ["count"], outputs: ["clicked"] }] });
6233
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;align-items:center;height:100%;background:var(--color-header-surface);width:100%}:host ion-header{background:var(--color-header-surface);box-shadow:none;height:72px;min-height:72px;margin-top:var(--app-header-top-offset)}:host ion-header ion-toolbar{--background: var(--color-header-surface);--border-width: 0;--box-shadow: none;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 72px;height:72px;min-height:72px;padding:0}@media (min-width: 768px){:host ion-header{height:88px;min-height:88px}:host ion-header ion-toolbar{--min-height: 88px;height:88px;min-height:88px}}@media (min-width: 768px){:host ion-header{display:none;height:auto}}:host .header-main,:host .header-details,.header-details{display:flex;align-items:center;justify-content:space-between;background:var(--color-header-surface);position:relative}:host .header-main__title,:host .header-details .header-title,.header-details .header-title{position:absolute;left:50%;transform:translate(-50%);font-size:var(--font-size-base);font-weight:600;color:var(--color-header-content);margin:0;padding:0;--color: var(--color-header-content)}.header-details .header-title{transform:translate(-50%) translateY(-100%);opacity:0!important;pointer-events:none;transition:transform .2s ease,opacity .2s ease!important}.header-scrolled .header-details .header-title{opacity:1!important;pointer-events:auto;transform:translate(-50%) translateY(0)}:host .header-details .back-button,.header-details .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--color-header-content);transition:opacity var(--transition-duration-fast, .2s) var(--ease-smooth, ease);z-index:10;position:relative}:host .header-details .back-button:hover,.header-details .back-button:hover{opacity:.8}:host .header-details .back-button:active,.header-details .back-button:active{opacity:.6}:host ion-content{--background: var(--color-header-surface);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;border-radius:24px 24px 0 0;overflow:hidden}:host ion-content::part(scroll){display:flex;flex-direction:column;min-height:100%;-webkit-overflow-scrolling:touch}.plt-ios :host ion-content{--background: var(--color-background-neutral-primary)}@media (min-width: 768px){:host ion-content{border-radius:24px 24px 0 0}}:host ion-header[collapse=condense]{display:none}@media (min-width: 768px){:host ion-header[collapse=condense]{display:none}}:host ion-refresher{z-index:0}:host ion-refresher-content{--color: var(--color-header-content)}:host .content-wrapper{width:100%;position:relative;z-index:20;flex:1;display:flex;flex-direction:column;background:var(--color-background-neutral-primary);border-radius:24px 24px 0 0;overflow:visible;transform:translateZ(0);will-change:transform;isolation:isolate;box-shadow:0 300px 0 0 var(--color-background-neutral-primary);padding-top:0;padding-left:var(--content-wrapper-padding, 20px);padding-right:var(--content-wrapper-padding, 20px);padding-bottom:calc(var(--mobile-content-spacing) + var(--mobile-tab-bar-height) + var(--app-safe-bottom, 0px))}:host .content-inner{max-width:640px;margin:0 auto;width:100%}@media (min-width: 768px){:host .content-wrapper{padding-top:0;padding-left:var(--content-wrapper-padding, 20px);padding-right:var(--content-wrapper-padding, 20px)}}:host .header-expandable{background:var(--color-header-surface);padding:32px 20px 24px;color:var(--header-content-color, white);position:sticky;top:0;z-index:5;transition:opacity .1s ease-out,transform .1s ease-out;flex:0 0 auto;min-height:-moz-min-content;min-height:min-content}:host .header-expandable-inner{display:flex;flex-direction:column;gap:20px;max-width:640px;margin:0 auto}:host .header-expandable__text{margin-bottom:0;gap:4px;display:flex;flex-direction:column}:host .header-expandable__title{font-size:var(--font-size-2xl);font-weight:600;color:var(--header-content-color, white);margin:0}:host .header-expandable__subtitle{font-size:var(--font-size-sm);font-weight:400;color:var(--header-content-color, white);opacity:.85;margin:0}@media (min-width: 768px){:host .header-expandable{padding:48px 20px 32px}:host .header-expandable__title{font-size:var(--font-size-3xl)}:host .header-expandable__subtitle{font-size:var(--font-size-base)}}@media (min-width: 992px){:host .header-expandable{padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){:host .header-expandable{padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){:host .header-expandable{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){:host .header-expandable{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}\n", ".header-main{padding:0 20px;height:72px}.header-main__title{transform:translate(-50%) translateY(-100%);opacity:0;transition:transform .6s ease,opacity .6s ease;padding:0;--color: var(--color-header-content)}.header-scrolled .header-main__title{opacity:1;transform:translate(-50%) translateY(0)}.header-main__actions{display:flex;align-items:center;gap:8px}.header-main__actions ds-avatar{cursor:pointer;-webkit-tap-highlight-color:transparent}@keyframes logoSlideIn{0%{transform:translateY(-200%);scale:.75;opacity:0}to{transform:translateY(0);scale:1;opacity:1}}.logo--first-entry{animation:logoSlideIn .75s var(--spring-curve-bouncy) .7s both}@media (min-width: 768px){.header-main{padding:16px 24px;height:88px}.header-main__title{display:none}}ion-refresher{--color: var(--color-header-content)}ion-refresher-content{--color: var(--color-header-content)}ion-refresher-content::part(spinner){color:var(--color-header-content)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { 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"] }, { kind: "component", type: DsMobileSkeletonLoaderComponent, selector: "ds-mobile-skeleton-loader", inputs: ["borderRadius"] }, { kind: "component", type: DsMobileNotificationButtonComponent, selector: "ds-mobile-notification-button", inputs: ["count"], outputs: ["clicked"] }] });
6227
6234
  }
6228
6235
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobilePageMainComponent, decorators: [{
6229
6236
  type: Component,
6230
- args: [{ selector: 'ds-mobile-page-main', standalone: true, imports: [CommonModule, IonHeader, IonToolbar, IonTitle, IonContent, IonRefresher, IonRefresherContent, DsAvatarComponent, DsLogoComponent, DsMobileGlassSpinnerComponent, DsMobileNotificationButtonComponent], host: {
6237
+ args: [{ selector: 'ds-mobile-page-main', standalone: true, imports: [CommonModule, IonHeader, IonToolbar, IonTitle, IonContent, IonRefresher, IonRefresherContent, DsAvatarComponent, DsLogoComponent, DsMobileSkeletonLoaderComponent, DsMobileNotificationButtonComponent], host: {
6231
6238
  '[style.--content-wrapper-padding]': 'contentPadding()'
6232
6239
  }, template: `
6233
6240
  <!-- Fixed header at top -->
@@ -6275,7 +6282,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6275
6282
 
6276
6283
  <!-- Pull to refresh (only on native iOS/Android) -->
6277
6284
  @if (showRefresh() && isNativePlatform()) {
6278
- <ion-refresher slot="fixed" (ionRefresh)="handleRefresh($event)" [pullFactor]="0.4" [pullMin]="80" [pullMax]="240" closeDuration="600ms">
6285
+ <ion-refresher slot="fixed" (ionRefresh)="handleRefresh($event)" [pullFactor]="0.5" [pullMin]="80" [pullMax]="240" [snapbackDuration]="'280ms'" closeDuration="280ms">
6279
6286
  <ion-refresher-content pullingIcon="remixArrowDownS" refreshingSpinner="crescent"> </ion-refresher-content>
6280
6287
  </ion-refresher>
6281
6288
  }
@@ -6300,7 +6307,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6300
6307
  <!-- Content wrapper -->
6301
6308
  <div class="content-wrapper">
6302
6309
  @if (contentLoading()) {
6303
- <ds-mobile-glass-spinner [borderRadius]="24" />
6310
+ <ds-mobile-skeleton-loader [borderRadius]="24" />
6304
6311
  }
6305
6312
 
6306
6313
  <!-- Offline indicator slot (appears at top of content) -->
@@ -6727,10 +6734,11 @@ class DsMobilePageDetailsComponent extends MobilePageBase {
6727
6734
  <ion-refresher
6728
6735
  slot="fixed"
6729
6736
  (ionRefresh)="handleRefresh($event)"
6730
- [pullFactor]="0.4"
6737
+ [pullFactor]="0.5"
6731
6738
  [pullMin]="80"
6732
6739
  [pullMax]="240"
6733
- closeDuration="600ms">
6740
+ [snapbackDuration]="'280ms'"
6741
+ closeDuration="280ms">
6734
6742
  <ion-refresher-content
6735
6743
  pullingIcon="remixArrowDownS"
6736
6744
  refreshingSpinner="crescent">
@@ -6766,7 +6774,7 @@ class DsMobilePageDetailsComponent extends MobilePageBase {
6766
6774
  <!-- Content wrapper -->
6767
6775
  <div class="content-wrapper">
6768
6776
  @if (contentLoading()) {
6769
- <ds-mobile-glass-spinner [borderRadius]="24" />
6777
+ <ds-mobile-skeleton-loader [borderRadius]="24" />
6770
6778
  }
6771
6779
 
6772
6780
  <!-- Offline indicator slot (appears at top of content) -->
@@ -6777,7 +6785,7 @@ class DsMobilePageDetailsComponent extends MobilePageBase {
6777
6785
  </div>
6778
6786
  </div>
6779
6787
  </ion-content>
6780
- `, isInline: true, styles: [":host{display:flex;flex-direction:column;align-items:center;height:100%;background:var(--color-header-surface);width:100%}:host ion-header{background:var(--color-header-surface);box-shadow:none;height:72px;min-height:72px;margin-top:var(--app-header-top-offset)}:host ion-header ion-toolbar{--background: var(--color-header-surface);--border-width: 0;--box-shadow: none;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 72px;height:72px;min-height:72px;padding:0}@media (min-width: 768px){:host ion-header{height:88px;min-height:88px}:host ion-header ion-toolbar{--min-height: 88px;height:88px;min-height:88px}}@media (min-width: 768px){:host ion-header{display:none;height:auto}}:host .header-main,:host .header-details,.header-details{display:flex;align-items:center;justify-content:space-between;background:var(--color-header-surface);position:relative}:host .header-main__title,:host .header-details .header-title,.header-details .header-title{position:absolute;left:50%;transform:translate(-50%);font-size:var(--font-size-base);font-weight:600;color:var(--color-header-content);margin:0;padding:0;--color: var(--color-header-content)}.header-details .header-title{transform:translate(-50%) translateY(-100%);opacity:0!important;pointer-events:none;transition:transform .2s ease,opacity .2s ease!important}.header-scrolled .header-details .header-title{opacity:1!important;pointer-events:auto;transform:translate(-50%) translateY(0)}:host .header-details .back-button,.header-details .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--color-header-content);transition:opacity var(--transition-duration-fast, .2s) var(--ease-smooth, ease);z-index:10;position:relative}:host .header-details .back-button:hover,.header-details .back-button:hover{opacity:.8}:host .header-details .back-button:active,.header-details .back-button:active{opacity:.6}:host ion-content{--background: var(--color-header-surface);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;border-radius:24px 24px 0 0;overflow:hidden}:host ion-content::part(scroll){display:flex;flex-direction:column;min-height:100%;-webkit-overflow-scrolling:touch}.plt-ios :host ion-content{--background: var(--color-background-neutral-primary)}@media (min-width: 768px){:host ion-content{border-radius:24px 24px 0 0}}:host ion-header[collapse=condense]{display:none}@media (min-width: 768px){:host ion-header[collapse=condense]{display:none}}:host ion-refresher{z-index:0}:host ion-refresher-content{--color: var(--color-header-content)}:host .content-wrapper{width:100%;position:relative;z-index:20;flex:1;display:flex;flex-direction:column;background:var(--color-background-neutral-primary);border-radius:24px 24px 0 0;overflow:visible;transform:translateZ(0);will-change:transform;isolation:isolate;box-shadow:0 300px 0 0 var(--color-background-neutral-primary);padding-top:0;padding-left:var(--content-wrapper-padding, 20px);padding-right:var(--content-wrapper-padding, 20px);padding-bottom:calc(var(--mobile-content-spacing) + var(--mobile-tab-bar-height) + var(--app-safe-bottom, 0px))}:host .content-inner{max-width:640px;margin:0 auto;width:100%}@media (min-width: 768px){:host .content-wrapper{padding-top:0;padding-left:var(--content-wrapper-padding, 20px);padding-right:var(--content-wrapper-padding, 20px)}}:host .header-expandable{background:var(--color-header-surface);padding:32px 20px 24px;color:var(--header-content-color, white);position:sticky;top:0;z-index:5;transition:opacity .1s ease-out,transform .1s ease-out;flex:0 0 auto;min-height:-moz-min-content;min-height:min-content}:host .header-expandable-inner{display:flex;flex-direction:column;gap:20px;max-width:640px;margin:0 auto}:host .header-expandable__text{margin-bottom:0;gap:4px;display:flex;flex-direction:column}:host .header-expandable__title{font-size:var(--font-size-2xl);font-weight:600;color:var(--header-content-color, white);margin:0}:host .header-expandable__subtitle{font-size:var(--font-size-sm);font-weight:400;color:var(--header-content-color, white);opacity:.85;margin:0}@media (min-width: 768px){:host .header-expandable{padding:48px 20px 32px}:host .header-expandable__title{font-size:var(--font-size-3xl)}:host .header-expandable__subtitle{font-size:var(--font-size-base)}}@media (min-width: 992px){:host .header-expandable{padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){:host .header-expandable{padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){:host .header-expandable{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){:host .header-expandable{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}\n", "ion-refresher{--color: var(--color-header-content)}ion-refresher-content{--color: var(--color-header-content)}ion-refresher-content::part(spinner){color:var(--color-header-content)}.header-details{gap:12px;padding:0 20px;height:72px;min-height:72px}:host .header-details .back-button{width:36px;height:36px;border-radius:50%;background:color-mix(in srgb,var(--color-header-content) 10%,transparent)!important;flex-shrink:0;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--color-header-content);transition:background var(--transition-duration-fast) var(--ease-smooth);z-index:10}:host .header-details .back-button:hover{background:color-mix(in srgb,var(--color-header-content) 16%,transparent)!important}:host .header-details .back-button:active{background:color-mix(in srgb,var(--color-header-content) 22%,transparent)!important}.header-details .header-title{left:64px}@media (min-width: 768px){ion-header{display:block!important;height:88px;min-height:88px}ion-header ion-toolbar{--min-height: 88px;height:88px;min-height:88px}.header-details{padding:16px 24px;height:88px;min-height:88px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileGlassSpinnerComponent, selector: "ds-mobile-glass-spinner", inputs: ["spinnerSize", "borderRadius"] }, { kind: "component", type: DsMobileInlineTabsComponent, selector: "ds-mobile-inline-tabs", inputs: ["tabs", "activeTab"], outputs: ["tabChange"] }] });
6788
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;align-items:center;height:100%;background:var(--color-header-surface);width:100%}:host ion-header{background:var(--color-header-surface);box-shadow:none;height:72px;min-height:72px;margin-top:var(--app-header-top-offset)}:host ion-header ion-toolbar{--background: var(--color-header-surface);--border-width: 0;--box-shadow: none;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 72px;height:72px;min-height:72px;padding:0}@media (min-width: 768px){:host ion-header{height:88px;min-height:88px}:host ion-header ion-toolbar{--min-height: 88px;height:88px;min-height:88px}}@media (min-width: 768px){:host ion-header{display:none;height:auto}}:host .header-main,:host .header-details,.header-details{display:flex;align-items:center;justify-content:space-between;background:var(--color-header-surface);position:relative}:host .header-main__title,:host .header-details .header-title,.header-details .header-title{position:absolute;left:50%;transform:translate(-50%);font-size:var(--font-size-base);font-weight:600;color:var(--color-header-content);margin:0;padding:0;--color: var(--color-header-content)}.header-details .header-title{transform:translate(-50%) translateY(-100%);opacity:0!important;pointer-events:none;transition:transform .2s ease,opacity .2s ease!important}.header-scrolled .header-details .header-title{opacity:1!important;pointer-events:auto;transform:translate(-50%) translateY(0)}:host .header-details .back-button,.header-details .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--color-header-content);transition:opacity var(--transition-duration-fast, .2s) var(--ease-smooth, ease);z-index:10;position:relative}:host .header-details .back-button:hover,.header-details .back-button:hover{opacity:.8}:host .header-details .back-button:active,.header-details .back-button:active{opacity:.6}:host ion-content{--background: var(--color-header-surface);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;border-radius:24px 24px 0 0;overflow:hidden}:host ion-content::part(scroll){display:flex;flex-direction:column;min-height:100%;-webkit-overflow-scrolling:touch}.plt-ios :host ion-content{--background: var(--color-background-neutral-primary)}@media (min-width: 768px){:host ion-content{border-radius:24px 24px 0 0}}:host ion-header[collapse=condense]{display:none}@media (min-width: 768px){:host ion-header[collapse=condense]{display:none}}:host ion-refresher{z-index:0}:host ion-refresher-content{--color: var(--color-header-content)}:host .content-wrapper{width:100%;position:relative;z-index:20;flex:1;display:flex;flex-direction:column;background:var(--color-background-neutral-primary);border-radius:24px 24px 0 0;overflow:visible;transform:translateZ(0);will-change:transform;isolation:isolate;box-shadow:0 300px 0 0 var(--color-background-neutral-primary);padding-top:0;padding-left:var(--content-wrapper-padding, 20px);padding-right:var(--content-wrapper-padding, 20px);padding-bottom:calc(var(--mobile-content-spacing) + var(--mobile-tab-bar-height) + var(--app-safe-bottom, 0px))}:host .content-inner{max-width:640px;margin:0 auto;width:100%}@media (min-width: 768px){:host .content-wrapper{padding-top:0;padding-left:var(--content-wrapper-padding, 20px);padding-right:var(--content-wrapper-padding, 20px)}}:host .header-expandable{background:var(--color-header-surface);padding:32px 20px 24px;color:var(--header-content-color, white);position:sticky;top:0;z-index:5;transition:opacity .1s ease-out,transform .1s ease-out;flex:0 0 auto;min-height:-moz-min-content;min-height:min-content}:host .header-expandable-inner{display:flex;flex-direction:column;gap:20px;max-width:640px;margin:0 auto}:host .header-expandable__text{margin-bottom:0;gap:4px;display:flex;flex-direction:column}:host .header-expandable__title{font-size:var(--font-size-2xl);font-weight:600;color:var(--header-content-color, white);margin:0}:host .header-expandable__subtitle{font-size:var(--font-size-sm);font-weight:400;color:var(--header-content-color, white);opacity:.85;margin:0}@media (min-width: 768px){:host .header-expandable{padding:48px 20px 32px}:host .header-expandable__title{font-size:var(--font-size-3xl)}:host .header-expandable__subtitle{font-size:var(--font-size-base)}}@media (min-width: 992px){:host .header-expandable{padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){:host .header-expandable{padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){:host .header-expandable{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){:host .header-expandable{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}\n", "ion-refresher{--color: var(--color-header-content)}ion-refresher-content{--color: var(--color-header-content)}ion-refresher-content::part(spinner){color:var(--color-header-content)}.header-details{gap:12px;padding:0 20px;height:72px;min-height:72px}:host .header-details .back-button{width:36px;height:36px;border-radius:50%;background:color-mix(in srgb,var(--color-header-content) 10%,transparent)!important;flex-shrink:0;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--color-header-content);transition:background var(--transition-duration-fast) var(--ease-smooth);z-index:10}:host .header-details .back-button:hover{background:color-mix(in srgb,var(--color-header-content) 16%,transparent)!important}:host .header-details .back-button:active{background:color-mix(in srgb,var(--color-header-content) 22%,transparent)!important}.header-details .header-title{left:64px}@media (min-width: 768px){ion-header{display:block!important;height:88px;min-height:88px}ion-header ion-toolbar{--min-height: 88px;height:88px;min-height:88px}.header-details{padding:16px 24px;height:88px;min-height:88px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileSkeletonLoaderComponent, selector: "ds-mobile-skeleton-loader", inputs: ["borderRadius"] }, { kind: "component", type: DsMobileInlineTabsComponent, selector: "ds-mobile-inline-tabs", inputs: ["tabs", "activeTab"], outputs: ["tabChange"] }] });
6781
6789
  }
6782
6790
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobilePageDetailsComponent, decorators: [{
6783
6791
  type: Component,
@@ -6790,7 +6798,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6790
6798
  IonRefresher,
6791
6799
  IonRefresherContent,
6792
6800
  DsIconComponent,
6793
- DsMobileGlassSpinnerComponent,
6801
+ DsMobileSkeletonLoaderComponent,
6794
6802
  DsMobileInlineTabsComponent
6795
6803
  ], host: {
6796
6804
  '[style.--content-wrapper-padding]': 'contentPadding()'
@@ -6819,10 +6827,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6819
6827
  <ion-refresher
6820
6828
  slot="fixed"
6821
6829
  (ionRefresh)="handleRefresh($event)"
6822
- [pullFactor]="0.4"
6830
+ [pullFactor]="0.5"
6823
6831
  [pullMin]="80"
6824
6832
  [pullMax]="240"
6825
- closeDuration="600ms">
6833
+ [snapbackDuration]="'280ms'"
6834
+ closeDuration="280ms">
6826
6835
  <ion-refresher-content
6827
6836
  pullingIcon="remixArrowDownS"
6828
6837
  refreshingSpinner="crescent">
@@ -6858,7 +6867,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6858
6867
  <!-- Content wrapper -->
6859
6868
  <div class="content-wrapper">
6860
6869
  @if (contentLoading()) {
6861
- <ds-mobile-glass-spinner [borderRadius]="24" />
6870
+ <ds-mobile-skeleton-loader [borderRadius]="24" />
6862
6871
  }
6863
6872
 
6864
6873
  <!-- Offline indicator slot (appears at top of content) -->
@@ -7929,6 +7938,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
7929
7938
  `, styles: [":host{display:block;max-width:640px;cursor:pointer;transition:all .2s ease}.composer-container{display:flex;align-items:center;gap:12px}.composer-input-wrapper{flex:1;min-width:0}.composer-input{width:100%;background:rgba(var(--header-content-color-rgb, 255, 255, 255),.1);border:none;border-radius:24px;padding:10px 16px;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:20px;letter-spacing:-.3px;color:rgba(var(--header-content-color-rgb, 255, 255, 255),.75);outline:none;cursor:pointer;transition:all .2s ease;pointer-events:none;-webkit-user-select:none;user-select:none}.composer-input::placeholder{color:rgba(var(--header-content-color-rgb, 255, 255, 255),.75);opacity:1}@media (hover: hover){:host:hover .composer-input{opacity:.8}}\n"] }]
7930
7939
  }], 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 }] }], avatarIconName: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarIconName", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], buttonText: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonText", required: false }] }], composerClick: [{ type: i0.Output, args: ["composerClick"] }] } });
7931
7940
 
7941
+ /**
7942
+ * DsMobileGlassSpinnerComponent
7943
+ *
7944
+ * Reusable loader overlay with a glassmorphism (blurred) background and a spinner.
7945
+ * This is useful when you want to show a loading state without covering the entire screen
7946
+ * with a solid background, but rather blurring the content behind it.
7947
+ *
7948
+ * Features:
7949
+ * - Glassmorphism blurred background
7950
+ * - Centered animated spinner
7951
+ * - Customizable spinner size
7952
+ * - Absolute positioning to cover parent
7953
+ */
7954
+ class DsMobileGlassSpinnerComponent {
7955
+ /**
7956
+ * Size of the spinner in pixels
7957
+ * @default 24
7958
+ */
7959
+ spinnerSize = input(24, ...(ngDevMode ? [{ debugName: "spinnerSize" }] : []));
7960
+ /**
7961
+ * Border radius of the overlay in pixels (should match parent's border radius)
7962
+ * @default 0
7963
+ */
7964
+ borderRadius = input(0, ...(ngDevMode ? [{ debugName: "borderRadius" }] : []));
7965
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileGlassSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7966
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: DsMobileGlassSpinnerComponent, isStandalone: true, selector: "ds-mobile-glass-spinner", inputs: { spinnerSize: { classPropertyName: "spinnerSize", publicName: "spinnerSize", isSignal: true, isRequired: false, transformFunction: null }, borderRadius: { classPropertyName: "borderRadius", publicName: "borderRadius", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
7967
+ <div
7968
+ class="glass-spinner-overlay"
7969
+ [style.border-radius.px]="borderRadius()"
7970
+ role="status"
7971
+ aria-live="polite"
7972
+ aria-label="Loading">
7973
+ <div
7974
+ class="spinner"
7975
+ [style.width.px]="spinnerSize()"
7976
+ [style.height.px]="spinnerSize()">
7977
+ </div>
7978
+ </div>
7979
+ `, isInline: true, styles: [":host{display:contents}.glass-spinner-overlay{position:absolute;inset:0;background:#fff6;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:9999;border-radius:inherit}.spinner{border:2px solid var(--color-border-neutral-secondary, #E5E5E5);border-top-color:var(--color-accent, #6B5FF5);border-radius:50%;animation:spin .6s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-color-scheme: dark){.glass-spinner-overlay{background:#0000004d}.spinner{border-color:#fff3;border-top-color:var(--color-accent, #6B5FF5)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
7980
+ }
7981
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileGlassSpinnerComponent, decorators: [{
7982
+ type: Component,
7983
+ args: [{ selector: 'ds-mobile-glass-spinner', standalone: true, imports: [CommonModule], template: `
7984
+ <div
7985
+ class="glass-spinner-overlay"
7986
+ [style.border-radius.px]="borderRadius()"
7987
+ role="status"
7988
+ aria-live="polite"
7989
+ aria-label="Loading">
7990
+ <div
7991
+ class="spinner"
7992
+ [style.width.px]="spinnerSize()"
7993
+ [style.height.px]="spinnerSize()">
7994
+ </div>
7995
+ </div>
7996
+ `, styles: [":host{display:contents}.glass-spinner-overlay{position:absolute;inset:0;background:#fff6;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:9999;border-radius:inherit}.spinner{border:2px solid var(--color-border-neutral-secondary, #E5E5E5);border-top-color:var(--color-accent, #6B5FF5);border-radius:50%;animation:spin .6s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-color-scheme: dark){.glass-spinner-overlay{background:#0000004d}.spinner{border-color:#fff3;border-top-color:var(--color-accent, #6B5FF5)}}\n"] }]
7997
+ }], propDecorators: { spinnerSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "spinnerSize", required: false }] }], borderRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "borderRadius", required: false }] }] } });
7998
+
7932
7999
  /**
7933
8000
  * DsMobileAttachmentPreviewComponent
7934
8001
  *
@@ -22211,6 +22278,7 @@ class DsMobilePostDetailModalComponent {
22211
22278
  */
22212
22279
  cancelEdit() {
22213
22280
  this.editingComment.set(null);
22281
+ this.replyingTo.set(null);
22214
22282
  this.commentText.set('');
22215
22283
  }
22216
22284
  /**
@@ -22219,6 +22287,17 @@ class DsMobilePostDetailModalComponent {
22219
22287
  handleEditComment(comment) {
22220
22288
  // Clear reply state if active
22221
22289
  this.replyingTo.set(null);
22290
+ let contentToEdit = comment.content;
22291
+ const possibleNames = [this.post().authorName, ...(this.post().comments?.map((c) => c.authorName) || [])];
22292
+ const uniqueNames = Array.from(new Set(possibleNames)).sort((a, b) => b.length - a.length);
22293
+ for (const author of uniqueNames) {
22294
+ const tagPrefix = `@${author} `;
22295
+ if (contentToEdit.startsWith(tagPrefix)) {
22296
+ this.replyingTo.set({ authorName: author, content: '' });
22297
+ contentToEdit = contentToEdit.substring(tagPrefix.length);
22298
+ break;
22299
+ }
22300
+ }
22222
22301
  // Set edit state
22223
22302
  this.editingComment.set({
22224
22303
  id: comment.id,
@@ -22227,7 +22306,7 @@ class DsMobilePostDetailModalComponent {
22227
22306
  timestamp: comment.timestamp,
22228
22307
  });
22229
22308
  // Populate the input with existing content
22230
- this.commentText.set(comment.content);
22309
+ this.commentText.set(contentToEdit);
22231
22310
  // Focus the input, show keyboard, and auto-resize
22232
22311
  setTimeout(() => {
22233
22312
  if (this.commentInput?.nativeElement) {
@@ -22297,10 +22376,12 @@ class DsMobilePostDetailModalComponent {
22297
22376
  // console.log('[PostDetailModal] Updating comment:', text);
22298
22377
  const editing = this.editingComment();
22299
22378
  const updatedComments = currentPost.comments?.map((comment) => {
22300
- if (comment.id && editing.id && comment.id === editing.id) {
22379
+ const matchesId = comment.id && editing.id && comment.id === editing.id;
22380
+ const matchesContent = !comment.id && !editing.id && comment.authorName === editing.authorName && comment.content === editing.originalContent;
22381
+ if (matchesId || matchesContent) {
22301
22382
  return {
22302
22383
  ...comment,
22303
- content: text,
22384
+ content: finalText,
22304
22385
  timestamp: `${this.textJustNow} (${this.textEdited})`,
22305
22386
  };
22306
22387
  }
@@ -22318,6 +22399,7 @@ class DsMobilePostDetailModalComponent {
22318
22399
  });
22319
22400
  }
22320
22401
  this.editingComment.set(null);
22402
+ this.replyingTo.set(null);
22321
22403
  }
22322
22404
  else {
22323
22405
  // console.log('[PostDetailModal] Submitting comment:', finalText);
@@ -22552,8 +22634,10 @@ class DsMobilePostDetailModalComponent {
22552
22634
  <ds-icon name="remixCloseLine" size="16px" />
22553
22635
  </button>
22554
22636
  </div>
22555
- } @else if (replyingTo()) {
22637
+ }
22638
+
22556
22639
  <!-- Reply indicator -->
22640
+ @if (replyingTo()) {
22557
22641
  <div class="reply-indicator">
22558
22642
  <div class="reply-indicator-content">
22559
22643
  <ds-icon name="remixReplyLine" size="16px" />
@@ -22698,8 +22782,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
22698
22782
  <ds-icon name="remixCloseLine" size="16px" />
22699
22783
  </button>
22700
22784
  </div>
22701
- } @else if (replyingTo()) {
22785
+ }
22786
+
22702
22787
  <!-- Reply indicator -->
22788
+ @if (replyingTo()) {
22703
22789
  <div class="reply-indicator">
22704
22790
  <div class="reply-indicator-content">
22705
22791
  <ds-icon name="remixReplyLine" size="16px" />
@@ -24674,6 +24760,465 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
24674
24760
  args: [{ providedIn: 'root' }]
24675
24761
  }], ctorParameters: () => [{ type: i1.ModalController }] });
24676
24762
 
24763
+ class DsMobileBookingDetailSheetComponent {
24764
+ modalController;
24765
+ /** `sheet` = bottom sheet. `modal` = `ds-modal-base` shell (active + history bookings). */
24766
+ presentation = 'sheet';
24767
+ data;
24768
+ /** When true the modal sizes to its content instead of filling the screen. */
24769
+ autoHeight = false;
24770
+ get isModalPresentation() {
24771
+ return this.presentation === 'modal';
24772
+ }
24773
+ constructor(modalController) {
24774
+ this.modalController = modalController;
24775
+ }
24776
+ close() {
24777
+ this.modalController.dismiss(null, 'backdrop');
24778
+ }
24779
+ cancelBooking() {
24780
+ this.modalController.dismiss(null, 'cancel');
24781
+ }
24782
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetComponent, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Component });
24783
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileBookingDetailSheetComponent, isStandalone: true, selector: "ds-mobile-booking-detail-sheet", inputs: { presentation: "presentation", data: "data", autoHeight: "autoHeight" }, host: { properties: { "class.presentation-modal": "this.isModalPresentation" } }, ngImport: i0, template: `
24784
+ @if (presentation === 'modal') {
24785
+ <ds-mobile-modal-base
24786
+ [headerTitle]="data.facilityTitle"
24787
+ [closeButtonLabel]="'Luk'"
24788
+ [isAutoHeight]="autoHeight"
24789
+ [keyboardContentBehavior]="'follow'">
24790
+
24791
+ <ds-mobile-section
24792
+ [showBorder]="false"
24793
+ padding="20px 20px 0 20px">
24794
+ <div class="hero-image-container">
24795
+ @if (data.heroImage) {
24796
+ <img [src]="data.heroImage" [alt]="data.facilityTitle" class="hero-image" />
24797
+ } @else {
24798
+ <div class="hero-image-placeholder">
24799
+ <ds-icon name="remixImageLine" size="48px" color="rgba(255,255,255,0.5)" />
24800
+ </div>
24801
+ }
24802
+ </div>
24803
+ </ds-mobile-section>
24804
+
24805
+ <ds-mobile-section padding="20px 20px 20px 20px">
24806
+ <div class="booking-summary-card">
24807
+ <div class="details-section">
24808
+ <h3 class="details-heading">Booking detaljer</h3>
24809
+ <div class="info-rows">
24810
+ @if (data.bookingDate) {
24811
+ <div class="info-row">
24812
+ <ds-icon name="remixCalendarLine" size="16px" color="tertiary" />
24813
+ <span>{{ data.bookingDate }}</span>
24814
+ </div>
24815
+ }
24816
+ @if (data.bookingTime) {
24817
+ <div class="info-row">
24818
+ <ds-icon name="remixTimeLine" size="16px" color="tertiary" />
24819
+ <span>{{ data.bookingTime }}</span>
24820
+ </div>
24821
+ }
24822
+ @if (data.price) {
24823
+ <div class="info-row">
24824
+ <ds-icon name="remixPriceTag3Line" size="16px" color="tertiary" />
24825
+ <span>{{ data.price }}</span>
24826
+ </div>
24827
+ }
24828
+ @if (data.bookingType) {
24829
+ <div class="info-row">
24830
+ <ds-icon name="remixCheckboxCircleLine" size="16px" color="tertiary" />
24831
+ <span>{{ data.bookingType }}</span>
24832
+ </div>
24833
+ }
24834
+ @for (req of data.requirements || []; track req) {
24835
+ <div class="info-row">
24836
+ <ds-icon name="remixLockLine" size="16px" color="tertiary" />
24837
+ <span>{{ req }}</span>
24838
+ </div>
24839
+ }
24840
+ </div>
24841
+ </div>
24842
+ </div>
24843
+ </ds-mobile-section>
24844
+
24845
+ @if (data.canCancel) {
24846
+ <div class="booking-action">
24847
+ <div class="booking-actions-row">
24848
+ <ds-button
24849
+ class="cancel-primary"
24850
+ size="md"
24851
+ variant="secondary"
24852
+ (clicked)="cancelBooking()">
24853
+ Annuller booking
24854
+ </ds-button>
24855
+ </div>
24856
+ </div>
24857
+ }
24858
+ </ds-mobile-modal-base>
24859
+ } @else {
24860
+ <ds-mobile-bottom-sheet-wrapper [showDragHandle]="true">
24861
+ <div class="detail-header">
24862
+ <h2 class="detail-title">{{ data.facilityTitle }}</h2>
24863
+ <ds-icon-button
24864
+ icon="remixCloseLine"
24865
+ variant="ghost"
24866
+ size="sm"
24867
+ (clicked)="close()"
24868
+ aria-label="Luk"
24869
+ />
24870
+ </div>
24871
+
24872
+ <div class="detail-content">
24873
+ <div class="hero-image-container">
24874
+ @if (data.heroImage) {
24875
+ <img [src]="data.heroImage" [alt]="data.facilityTitle" class="hero-image" />
24876
+ } @else {
24877
+ <div class="hero-image-placeholder">
24878
+ <ds-icon name="remixImageLine" size="48px" color="rgba(255,255,255,0.5)" />
24879
+ </div>
24880
+ }
24881
+ </div>
24882
+
24883
+ <div class="booking-summary-card">
24884
+ <div class="details-section">
24885
+ <h3 class="details-heading">Booking detaljer</h3>
24886
+ <div class="info-rows">
24887
+ @if (data.bookingDate) {
24888
+ <div class="info-row">
24889
+ <ds-icon name="remixCalendarLine" size="16px" color="tertiary" />
24890
+ <span>{{ data.bookingDate }}</span>
24891
+ </div>
24892
+ }
24893
+ @if (data.bookingTime) {
24894
+ <div class="info-row">
24895
+ <ds-icon name="remixTimeLine" size="16px" color="tertiary" />
24896
+ <span>{{ data.bookingTime }}</span>
24897
+ </div>
24898
+ }
24899
+ @if (data.price) {
24900
+ <div class="info-row">
24901
+ <ds-icon name="remixPriceTag3Line" size="16px" color="tertiary" />
24902
+ <span>{{ data.price }}</span>
24903
+ </div>
24904
+ }
24905
+ @if (data.bookingType) {
24906
+ <div class="info-row">
24907
+ <ds-icon name="remixCheckboxCircleLine" size="16px" color="tertiary" />
24908
+ <span>{{ data.bookingType }}</span>
24909
+ </div>
24910
+ }
24911
+ @for (req of data.requirements || []; track req) {
24912
+ <div class="info-row">
24913
+ <ds-icon name="remixLockLine" size="16px" color="tertiary" />
24914
+ <span>{{ req }}</span>
24915
+ </div>
24916
+ }
24917
+ </div>
24918
+ </div>
24919
+ </div>
24920
+
24921
+ @if (data.canCancel) {
24922
+ <div class="footer-button-container">
24923
+ <div class="booking-actions-column">
24924
+ <ds-button
24925
+ size="md"
24926
+ variant="secondary"
24927
+ (clicked)="cancelBooking()">
24928
+ Annuller booking
24929
+ </ds-button>
24930
+ </div>
24931
+ </div>
24932
+ }
24933
+ </div>
24934
+ </ds-mobile-bottom-sheet-wrapper>
24935
+ }
24936
+ `, isInline: true, styles: [":host{display:block;height:auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;box-sizing:border-box}.detail-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 8px}.detail-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-lg, 18px);font-weight:600;color:var(--text-color-default-primary, #202227);margin:0;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:12px}.detail-content{padding:8px 20px 24px;display:flex;flex-direction:column;gap:20px}.hero-image-container{width:100%;aspect-ratio:16 / 9;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5)}.hero-image{width:100%;height:100%;object-fit:cover;display:block}.hero-image-placeholder{width:100%;height:100%;min-height:0;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,color-mix(in srgb,var(--color-accent, #6B5FF5) 30%,transparent),color-mix(in srgb,var(--color-accent, #6B5FF5) 60%,transparent))}.booking-summary-card{background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:16px;padding:16px}.details-section{display:flex;flex-direction:column;gap:12px}.details-heading{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);font-weight:600;color:var(--text-color-default-primary, #202227);margin:0}.info-rows{display:flex;flex-direction:column;gap:8px}.info-row{display:flex;align-items:center;gap:10px;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);color:var(--text-color-default-secondary, #545B66);line-height:1.4}.info-row ds-icon{flex-shrink:0}.footer-button-container{width:100%;padding:16px 20px 0}.footer-button-container ::ng-deep ds-button{display:block;width:100%}.footer-button-container ::ng-deep ds-button button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px}.booking-action{padding:16px 20px;padding-bottom:calc(16px + max(8px,env(safe-area-inset-bottom,0px) - 24px));background:var(--color-surface-primary, #ffffff)}.booking-actions-row{display:flex;flex-direction:row;align-items:center;gap:12px;width:100%}.booking-action .cancel-primary{flex:1;min-width:0;display:block}.booking-action .cancel-primary ::ng-deep button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px;padding-left:16px;padding-right:16px}:host.presentation-modal{display:block;height:auto;width:100%;min-height:0;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsMobileBottomSheetWrapperComponent, selector: "ds-mobile-bottom-sheet-wrapper", inputs: ["showDragHandle"] }, { kind: "component", type: DsMobileModalBaseComponent, selector: "ds-mobile-modal-base", inputs: ["headerTitleInteractive", "textLoading", "textErrorTitle", "showHeader"], outputs: ["titleClick"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { 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: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }] });
24937
+ }
24938
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetComponent, decorators: [{
24939
+ type: Component,
24940
+ args: [{ selector: 'ds-mobile-booking-detail-sheet', standalone: true, imports: [
24941
+ CommonModule,
24942
+ DsMobileBottomSheetWrapperComponent,
24943
+ DsMobileModalBaseComponent,
24944
+ DsMobileSectionComponent,
24945
+ DsButtonComponent,
24946
+ DsIconComponent,
24947
+ DsIconButtonComponent,
24948
+ ], template: `
24949
+ @if (presentation === 'modal') {
24950
+ <ds-mobile-modal-base
24951
+ [headerTitle]="data.facilityTitle"
24952
+ [closeButtonLabel]="'Luk'"
24953
+ [isAutoHeight]="autoHeight"
24954
+ [keyboardContentBehavior]="'follow'">
24955
+
24956
+ <ds-mobile-section
24957
+ [showBorder]="false"
24958
+ padding="20px 20px 0 20px">
24959
+ <div class="hero-image-container">
24960
+ @if (data.heroImage) {
24961
+ <img [src]="data.heroImage" [alt]="data.facilityTitle" class="hero-image" />
24962
+ } @else {
24963
+ <div class="hero-image-placeholder">
24964
+ <ds-icon name="remixImageLine" size="48px" color="rgba(255,255,255,0.5)" />
24965
+ </div>
24966
+ }
24967
+ </div>
24968
+ </ds-mobile-section>
24969
+
24970
+ <ds-mobile-section padding="20px 20px 20px 20px">
24971
+ <div class="booking-summary-card">
24972
+ <div class="details-section">
24973
+ <h3 class="details-heading">Booking detaljer</h3>
24974
+ <div class="info-rows">
24975
+ @if (data.bookingDate) {
24976
+ <div class="info-row">
24977
+ <ds-icon name="remixCalendarLine" size="16px" color="tertiary" />
24978
+ <span>{{ data.bookingDate }}</span>
24979
+ </div>
24980
+ }
24981
+ @if (data.bookingTime) {
24982
+ <div class="info-row">
24983
+ <ds-icon name="remixTimeLine" size="16px" color="tertiary" />
24984
+ <span>{{ data.bookingTime }}</span>
24985
+ </div>
24986
+ }
24987
+ @if (data.price) {
24988
+ <div class="info-row">
24989
+ <ds-icon name="remixPriceTag3Line" size="16px" color="tertiary" />
24990
+ <span>{{ data.price }}</span>
24991
+ </div>
24992
+ }
24993
+ @if (data.bookingType) {
24994
+ <div class="info-row">
24995
+ <ds-icon name="remixCheckboxCircleLine" size="16px" color="tertiary" />
24996
+ <span>{{ data.bookingType }}</span>
24997
+ </div>
24998
+ }
24999
+ @for (req of data.requirements || []; track req) {
25000
+ <div class="info-row">
25001
+ <ds-icon name="remixLockLine" size="16px" color="tertiary" />
25002
+ <span>{{ req }}</span>
25003
+ </div>
25004
+ }
25005
+ </div>
25006
+ </div>
25007
+ </div>
25008
+ </ds-mobile-section>
25009
+
25010
+ @if (data.canCancel) {
25011
+ <div class="booking-action">
25012
+ <div class="booking-actions-row">
25013
+ <ds-button
25014
+ class="cancel-primary"
25015
+ size="md"
25016
+ variant="secondary"
25017
+ (clicked)="cancelBooking()">
25018
+ Annuller booking
25019
+ </ds-button>
25020
+ </div>
25021
+ </div>
25022
+ }
25023
+ </ds-mobile-modal-base>
25024
+ } @else {
25025
+ <ds-mobile-bottom-sheet-wrapper [showDragHandle]="true">
25026
+ <div class="detail-header">
25027
+ <h2 class="detail-title">{{ data.facilityTitle }}</h2>
25028
+ <ds-icon-button
25029
+ icon="remixCloseLine"
25030
+ variant="ghost"
25031
+ size="sm"
25032
+ (clicked)="close()"
25033
+ aria-label="Luk"
25034
+ />
25035
+ </div>
25036
+
25037
+ <div class="detail-content">
25038
+ <div class="hero-image-container">
25039
+ @if (data.heroImage) {
25040
+ <img [src]="data.heroImage" [alt]="data.facilityTitle" class="hero-image" />
25041
+ } @else {
25042
+ <div class="hero-image-placeholder">
25043
+ <ds-icon name="remixImageLine" size="48px" color="rgba(255,255,255,0.5)" />
25044
+ </div>
25045
+ }
25046
+ </div>
25047
+
25048
+ <div class="booking-summary-card">
25049
+ <div class="details-section">
25050
+ <h3 class="details-heading">Booking detaljer</h3>
25051
+ <div class="info-rows">
25052
+ @if (data.bookingDate) {
25053
+ <div class="info-row">
25054
+ <ds-icon name="remixCalendarLine" size="16px" color="tertiary" />
25055
+ <span>{{ data.bookingDate }}</span>
25056
+ </div>
25057
+ }
25058
+ @if (data.bookingTime) {
25059
+ <div class="info-row">
25060
+ <ds-icon name="remixTimeLine" size="16px" color="tertiary" />
25061
+ <span>{{ data.bookingTime }}</span>
25062
+ </div>
25063
+ }
25064
+ @if (data.price) {
25065
+ <div class="info-row">
25066
+ <ds-icon name="remixPriceTag3Line" size="16px" color="tertiary" />
25067
+ <span>{{ data.price }}</span>
25068
+ </div>
25069
+ }
25070
+ @if (data.bookingType) {
25071
+ <div class="info-row">
25072
+ <ds-icon name="remixCheckboxCircleLine" size="16px" color="tertiary" />
25073
+ <span>{{ data.bookingType }}</span>
25074
+ </div>
25075
+ }
25076
+ @for (req of data.requirements || []; track req) {
25077
+ <div class="info-row">
25078
+ <ds-icon name="remixLockLine" size="16px" color="tertiary" />
25079
+ <span>{{ req }}</span>
25080
+ </div>
25081
+ }
25082
+ </div>
25083
+ </div>
25084
+ </div>
25085
+
25086
+ @if (data.canCancel) {
25087
+ <div class="footer-button-container">
25088
+ <div class="booking-actions-column">
25089
+ <ds-button
25090
+ size="md"
25091
+ variant="secondary"
25092
+ (clicked)="cancelBooking()">
25093
+ Annuller booking
25094
+ </ds-button>
25095
+ </div>
25096
+ </div>
25097
+ }
25098
+ </div>
25099
+ </ds-mobile-bottom-sheet-wrapper>
25100
+ }
25101
+ `, styles: [":host{display:block;height:auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;box-sizing:border-box}.detail-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 8px}.detail-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-lg, 18px);font-weight:600;color:var(--text-color-default-primary, #202227);margin:0;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:12px}.detail-content{padding:8px 20px 24px;display:flex;flex-direction:column;gap:20px}.hero-image-container{width:100%;aspect-ratio:16 / 9;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5)}.hero-image{width:100%;height:100%;object-fit:cover;display:block}.hero-image-placeholder{width:100%;height:100%;min-height:0;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,color-mix(in srgb,var(--color-accent, #6B5FF5) 30%,transparent),color-mix(in srgb,var(--color-accent, #6B5FF5) 60%,transparent))}.booking-summary-card{background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:16px;padding:16px}.details-section{display:flex;flex-direction:column;gap:12px}.details-heading{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);font-weight:600;color:var(--text-color-default-primary, #202227);margin:0}.info-rows{display:flex;flex-direction:column;gap:8px}.info-row{display:flex;align-items:center;gap:10px;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);color:var(--text-color-default-secondary, #545B66);line-height:1.4}.info-row ds-icon{flex-shrink:0}.footer-button-container{width:100%;padding:16px 20px 0}.footer-button-container ::ng-deep ds-button{display:block;width:100%}.footer-button-container ::ng-deep ds-button button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px}.booking-action{padding:16px 20px;padding-bottom:calc(16px + max(8px,env(safe-area-inset-bottom,0px) - 24px));background:var(--color-surface-primary, #ffffff)}.booking-actions-row{display:flex;flex-direction:row;align-items:center;gap:12px;width:100%}.booking-action .cancel-primary{flex:1;min-width:0;display:block}.booking-action .cancel-primary ::ng-deep button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px;padding-left:16px;padding-right:16px}:host.presentation-modal{display:block;height:auto;width:100%;min-height:0;overflow:hidden}\n"] }]
25102
+ }], ctorParameters: () => [{ type: i1.ModalController }], propDecorators: { presentation: [{
25103
+ type: Input
25104
+ }], data: [{
25105
+ type: Input
25106
+ }], autoHeight: [{
25107
+ type: Input
25108
+ }], isModalPresentation: [{
25109
+ type: HostBinding,
25110
+ args: ['class.presentation-modal']
25111
+ }] } });
25112
+
25113
+ class DsMobileBookingDetailSheetService extends BaseModalService {
25114
+ bottomSheet;
25115
+ constructor(modalController, bottomSheet) {
25116
+ super(modalController);
25117
+ this.bottomSheet = bottomSheet;
25118
+ }
25119
+ /**
25120
+ * Bottom-sheet presentation (draggable breakpoints). Prefer `openAsModal` for booking lists.
25121
+ */
25122
+ async open(data) {
25123
+ const modal = await this.bottomSheet.create({
25124
+ component: DsMobileBookingDetailSheetComponent,
25125
+ componentProps: { data },
25126
+ autoHeight: true,
25127
+ backdropDismiss: true,
25128
+ backdropBlur: true,
25129
+ });
25130
+ const result = await modal.onWillDismiss();
25131
+ return { role: result.role, data: result.data ?? undefined };
25132
+ }
25133
+ /** `ds-modal-base` shell — used for active and past bookings. Auto-heights to content. */
25134
+ async openAsModal(data) {
25135
+ const modal = await this.createModal(DsMobileBookingDetailSheetComponent, { data, presentation: 'modal', autoHeight: true }, { keyboardClose: true, autoHeight: true });
25136
+ await modal.present();
25137
+ const result = await modal.onWillDismiss();
25138
+ return { role: result.role, data: result.data ?? undefined };
25139
+ }
25140
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetService, deps: [{ token: i1.ModalController }, { token: DsMobileBottomSheetService }], target: i0.ɵɵFactoryTarget.Injectable });
25141
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetService, providedIn: 'root' });
25142
+ }
25143
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetService, decorators: [{
25144
+ type: Injectable,
25145
+ args: [{
25146
+ providedIn: 'root',
25147
+ }]
25148
+ }], ctorParameters: () => [{ type: i1.ModalController }, { type: DsMobileBottomSheetService }] });
25149
+
25150
+ class DsMobileBookingCancelConfirmationComponent {
25151
+ facilityTitle;
25152
+ facilityThumbnail;
25153
+ bookingDate;
25154
+ bookingTime;
25155
+ get confirmationMessage() {
25156
+ const datePart = this.bookingDate ? ` den ${this.bookingDate}` : '';
25157
+ return `Er du sikker på, at du vil annullere din booking af ${this.facilityTitle}${datePart}?`;
25158
+ }
25159
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingCancelConfirmationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
25160
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: DsMobileBookingCancelConfirmationComponent, isStandalone: true, selector: "ds-mobile-booking-cancel-confirmation", inputs: { facilityTitle: "facilityTitle", facilityThumbnail: "facilityThumbnail", bookingDate: "bookingDate", bookingTime: "bookingTime" }, ngImport: i0, template: `
25161
+ <ds-mobile-confirmation-sheet
25162
+ [title]="'Annuller booking?'"
25163
+ [message]="confirmationMessage"
25164
+ [buttonText]="'Ja, annuller booking'"
25165
+ [destructive]="true"
25166
+ [secondaryButtonText]="'Luk'"
25167
+ [secondaryButtonVariant]="'secondary'"
25168
+ [illustrationVariant]="'delete-warning'"
25169
+ [illustrationSize]="'140px'">
25170
+ <ng-template #summary>
25171
+ <ds-mobile-booking-summary
25172
+ [facilityTitle]="facilityTitle"
25173
+ [facilityThumbnail]="facilityThumbnail"
25174
+ [date]="bookingDate"
25175
+ [time]="bookingTime"
25176
+ />
25177
+ </ng-template>
25178
+ </ds-mobile-confirmation-sheet>
25179
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsMobileConfirmationSheetComponent, selector: "ds-mobile-confirmation-sheet", inputs: ["title", "message", "buttonText", "destructive", "showCancelButton", "cancelButtonText", "showIllustration", "illustrationVariant", "illustrationSize", "secondaryButtonText", "secondaryButtonVariant"] }, { kind: "component", type: DsMobileBookingSummaryComponent, selector: "ds-mobile-booking-summary", inputs: ["facilityTitle", "facilityThumbnail", "date", "time", "bookingCount"] }] });
25180
+ }
25181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingCancelConfirmationComponent, decorators: [{
25182
+ type: Component,
25183
+ args: [{
25184
+ selector: 'ds-mobile-booking-cancel-confirmation',
25185
+ standalone: true,
25186
+ imports: [
25187
+ CommonModule,
25188
+ DsMobileConfirmationSheetComponent,
25189
+ DsMobileBookingSummaryComponent
25190
+ ],
25191
+ template: `
25192
+ <ds-mobile-confirmation-sheet
25193
+ [title]="'Annuller booking?'"
25194
+ [message]="confirmationMessage"
25195
+ [buttonText]="'Ja, annuller booking'"
25196
+ [destructive]="true"
25197
+ [secondaryButtonText]="'Luk'"
25198
+ [secondaryButtonVariant]="'secondary'"
25199
+ [illustrationVariant]="'delete-warning'"
25200
+ [illustrationSize]="'140px'">
25201
+ <ng-template #summary>
25202
+ <ds-mobile-booking-summary
25203
+ [facilityTitle]="facilityTitle"
25204
+ [facilityThumbnail]="facilityThumbnail"
25205
+ [date]="bookingDate"
25206
+ [time]="bookingTime"
25207
+ />
25208
+ </ng-template>
25209
+ </ds-mobile-confirmation-sheet>
25210
+ `
25211
+ }]
25212
+ }], propDecorators: { facilityTitle: [{
25213
+ type: Input
25214
+ }], facilityThumbnail: [{
25215
+ type: Input
25216
+ }], bookingDate: [{
25217
+ type: Input
25218
+ }], bookingTime: [{
25219
+ type: Input
25220
+ }] } });
25221
+
24677
25222
  /**
24678
25223
  * DsMobileFacilityCreationModalComponent
24679
25224
  *
@@ -30301,393 +30846,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
30301
30846
  }]
30302
30847
  }], ctorParameters: () => [] });
30303
30848
 
30304
- class DsMobileBookingDetailSheetComponent {
30305
- modalController;
30306
- /** `sheet` = bottom sheet. `modal` = `ds-modal-base` shell (active + history bookings). */
30307
- presentation = 'sheet';
30308
- data;
30309
- /** When true the modal sizes to its content instead of filling the screen. */
30310
- autoHeight = false;
30311
- get isModalPresentation() {
30312
- return this.presentation === 'modal';
30313
- }
30314
- constructor(modalController) {
30315
- this.modalController = modalController;
30316
- }
30317
- close() {
30318
- this.modalController.dismiss(null, 'backdrop');
30319
- }
30320
- cancelBooking() {
30321
- this.modalController.dismiss(null, 'cancel');
30322
- }
30323
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetComponent, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Component });
30324
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileBookingDetailSheetComponent, isStandalone: true, selector: "ds-mobile-booking-detail-sheet", inputs: { presentation: "presentation", data: "data", autoHeight: "autoHeight" }, host: { properties: { "class.presentation-modal": "this.isModalPresentation" } }, ngImport: i0, template: `
30325
- @if (presentation === 'modal') {
30326
- <ds-mobile-modal-base
30327
- [headerTitle]="data.facilityTitle"
30328
- [closeButtonLabel]="'Luk'"
30329
- [isAutoHeight]="autoHeight"
30330
- [keyboardContentBehavior]="'follow'">
30331
-
30332
- <ds-mobile-section
30333
- [showBorder]="false"
30334
- padding="20px 20px 0 20px">
30335
- <div class="hero-image-container">
30336
- @if (data.heroImage) {
30337
- <img [src]="data.heroImage" [alt]="data.facilityTitle" class="hero-image" />
30338
- } @else {
30339
- <div class="hero-image-placeholder">
30340
- <ds-icon name="remixImageLine" size="48px" color="rgba(255,255,255,0.5)" />
30341
- </div>
30342
- }
30343
- </div>
30344
- </ds-mobile-section>
30345
-
30346
- <ds-mobile-section padding="20px 20px 20px 20px">
30347
- <div class="booking-summary-card">
30348
- <div class="details-section">
30349
- <h3 class="details-heading">Booking detaljer</h3>
30350
- <div class="info-rows">
30351
- @if (data.bookingDate) {
30352
- <div class="info-row">
30353
- <ds-icon name="remixCalendarLine" size="16px" color="tertiary" />
30354
- <span>{{ data.bookingDate }}</span>
30355
- </div>
30356
- }
30357
- @if (data.bookingTime) {
30358
- <div class="info-row">
30359
- <ds-icon name="remixTimeLine" size="16px" color="tertiary" />
30360
- <span>{{ data.bookingTime }}</span>
30361
- </div>
30362
- }
30363
- @if (data.price) {
30364
- <div class="info-row">
30365
- <ds-icon name="remixPriceTag3Line" size="16px" color="tertiary" />
30366
- <span>{{ data.price }}</span>
30367
- </div>
30368
- }
30369
- @if (data.bookingType) {
30370
- <div class="info-row">
30371
- <ds-icon name="remixCheckboxCircleLine" size="16px" color="tertiary" />
30372
- <span>{{ data.bookingType }}</span>
30373
- </div>
30374
- }
30375
- @for (req of data.requirements || []; track req) {
30376
- <div class="info-row">
30377
- <ds-icon name="remixLockLine" size="16px" color="tertiary" />
30378
- <span>{{ req }}</span>
30379
- </div>
30380
- }
30381
- </div>
30382
- </div>
30383
- </div>
30384
- </ds-mobile-section>
30385
-
30386
- @if (data.canCancel) {
30387
- <div class="booking-action">
30388
- <div class="booking-actions-row">
30389
- <ds-button
30390
- class="cancel-primary"
30391
- size="md"
30392
- variant="secondary"
30393
- (clicked)="cancelBooking()">
30394
- Annuller booking
30395
- </ds-button>
30396
- </div>
30397
- </div>
30398
- }
30399
- </ds-mobile-modal-base>
30400
- } @else {
30401
- <ds-mobile-bottom-sheet-wrapper [showDragHandle]="true">
30402
- <div class="detail-header">
30403
- <h2 class="detail-title">{{ data.facilityTitle }}</h2>
30404
- <ds-icon-button
30405
- icon="remixCloseLine"
30406
- variant="ghost"
30407
- size="sm"
30408
- (clicked)="close()"
30409
- aria-label="Luk"
30410
- />
30411
- </div>
30412
-
30413
- <div class="detail-content">
30414
- <div class="hero-image-container">
30415
- @if (data.heroImage) {
30416
- <img [src]="data.heroImage" [alt]="data.facilityTitle" class="hero-image" />
30417
- } @else {
30418
- <div class="hero-image-placeholder">
30419
- <ds-icon name="remixImageLine" size="48px" color="rgba(255,255,255,0.5)" />
30420
- </div>
30421
- }
30422
- </div>
30423
-
30424
- <div class="booking-summary-card">
30425
- <div class="details-section">
30426
- <h3 class="details-heading">Booking detaljer</h3>
30427
- <div class="info-rows">
30428
- @if (data.bookingDate) {
30429
- <div class="info-row">
30430
- <ds-icon name="remixCalendarLine" size="16px" color="tertiary" />
30431
- <span>{{ data.bookingDate }}</span>
30432
- </div>
30433
- }
30434
- @if (data.bookingTime) {
30435
- <div class="info-row">
30436
- <ds-icon name="remixTimeLine" size="16px" color="tertiary" />
30437
- <span>{{ data.bookingTime }}</span>
30438
- </div>
30439
- }
30440
- @if (data.price) {
30441
- <div class="info-row">
30442
- <ds-icon name="remixPriceTag3Line" size="16px" color="tertiary" />
30443
- <span>{{ data.price }}</span>
30444
- </div>
30445
- }
30446
- @if (data.bookingType) {
30447
- <div class="info-row">
30448
- <ds-icon name="remixCheckboxCircleLine" size="16px" color="tertiary" />
30449
- <span>{{ data.bookingType }}</span>
30450
- </div>
30451
- }
30452
- @for (req of data.requirements || []; track req) {
30453
- <div class="info-row">
30454
- <ds-icon name="remixLockLine" size="16px" color="tertiary" />
30455
- <span>{{ req }}</span>
30456
- </div>
30457
- }
30458
- </div>
30459
- </div>
30460
- </div>
30461
-
30462
- @if (data.canCancel) {
30463
- <div class="footer-button-container">
30464
- <div class="booking-actions-column">
30465
- <ds-button
30466
- size="md"
30467
- variant="secondary"
30468
- (clicked)="cancelBooking()">
30469
- Annuller booking
30470
- </ds-button>
30471
- </div>
30472
- </div>
30473
- }
30474
- </div>
30475
- </ds-mobile-bottom-sheet-wrapper>
30476
- }
30477
- `, isInline: true, styles: [":host{display:block;height:auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;box-sizing:border-box}.detail-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 8px}.detail-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-lg, 18px);font-weight:600;color:var(--text-color-default-primary, #202227);margin:0;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:12px}.detail-content{padding:8px 20px 24px;display:flex;flex-direction:column;gap:20px}.hero-image-container{width:100%;aspect-ratio:16 / 9;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5)}.hero-image{width:100%;height:100%;object-fit:cover;display:block}.hero-image-placeholder{width:100%;height:100%;min-height:0;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,color-mix(in srgb,var(--color-accent, #6B5FF5) 30%,transparent),color-mix(in srgb,var(--color-accent, #6B5FF5) 60%,transparent))}.booking-summary-card{background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:16px;padding:16px}.details-section{display:flex;flex-direction:column;gap:12px}.details-heading{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);font-weight:600;color:var(--text-color-default-primary, #202227);margin:0}.info-rows{display:flex;flex-direction:column;gap:8px}.info-row{display:flex;align-items:center;gap:10px;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);color:var(--text-color-default-secondary, #545B66);line-height:1.4}.info-row ds-icon{flex-shrink:0}.footer-button-container{width:100%;padding:16px 20px 0}.footer-button-container ::ng-deep ds-button{display:block;width:100%}.footer-button-container ::ng-deep ds-button button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px}.booking-action{padding:16px 20px;padding-bottom:calc(16px + max(8px,env(safe-area-inset-bottom,0px) - 24px));background:var(--color-surface-primary, #ffffff)}.booking-actions-row{display:flex;flex-direction:row;align-items:center;gap:12px;width:100%}.booking-action .cancel-primary{flex:1;min-width:0;display:block}.booking-action .cancel-primary ::ng-deep button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px;padding-left:16px;padding-right:16px}:host.presentation-modal{display:block;height:auto;width:100%;min-height:0;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsMobileBottomSheetWrapperComponent, selector: "ds-mobile-bottom-sheet-wrapper", inputs: ["showDragHandle"] }, { kind: "component", type: DsMobileModalBaseComponent, selector: "ds-mobile-modal-base", inputs: ["headerTitleInteractive", "textLoading", "textErrorTitle", "showHeader"], outputs: ["titleClick"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { 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: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }] });
30478
- }
30479
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetComponent, decorators: [{
30480
- type: Component,
30481
- args: [{ selector: 'ds-mobile-booking-detail-sheet', standalone: true, imports: [
30482
- CommonModule,
30483
- DsMobileBottomSheetWrapperComponent,
30484
- DsMobileModalBaseComponent,
30485
- DsMobileSectionComponent,
30486
- DsButtonComponent,
30487
- DsIconComponent,
30488
- DsIconButtonComponent,
30489
- ], template: `
30490
- @if (presentation === 'modal') {
30491
- <ds-mobile-modal-base
30492
- [headerTitle]="data.facilityTitle"
30493
- [closeButtonLabel]="'Luk'"
30494
- [isAutoHeight]="autoHeight"
30495
- [keyboardContentBehavior]="'follow'">
30496
-
30497
- <ds-mobile-section
30498
- [showBorder]="false"
30499
- padding="20px 20px 0 20px">
30500
- <div class="hero-image-container">
30501
- @if (data.heroImage) {
30502
- <img [src]="data.heroImage" [alt]="data.facilityTitle" class="hero-image" />
30503
- } @else {
30504
- <div class="hero-image-placeholder">
30505
- <ds-icon name="remixImageLine" size="48px" color="rgba(255,255,255,0.5)" />
30506
- </div>
30507
- }
30508
- </div>
30509
- </ds-mobile-section>
30510
-
30511
- <ds-mobile-section padding="20px 20px 20px 20px">
30512
- <div class="booking-summary-card">
30513
- <div class="details-section">
30514
- <h3 class="details-heading">Booking detaljer</h3>
30515
- <div class="info-rows">
30516
- @if (data.bookingDate) {
30517
- <div class="info-row">
30518
- <ds-icon name="remixCalendarLine" size="16px" color="tertiary" />
30519
- <span>{{ data.bookingDate }}</span>
30520
- </div>
30521
- }
30522
- @if (data.bookingTime) {
30523
- <div class="info-row">
30524
- <ds-icon name="remixTimeLine" size="16px" color="tertiary" />
30525
- <span>{{ data.bookingTime }}</span>
30526
- </div>
30527
- }
30528
- @if (data.price) {
30529
- <div class="info-row">
30530
- <ds-icon name="remixPriceTag3Line" size="16px" color="tertiary" />
30531
- <span>{{ data.price }}</span>
30532
- </div>
30533
- }
30534
- @if (data.bookingType) {
30535
- <div class="info-row">
30536
- <ds-icon name="remixCheckboxCircleLine" size="16px" color="tertiary" />
30537
- <span>{{ data.bookingType }}</span>
30538
- </div>
30539
- }
30540
- @for (req of data.requirements || []; track req) {
30541
- <div class="info-row">
30542
- <ds-icon name="remixLockLine" size="16px" color="tertiary" />
30543
- <span>{{ req }}</span>
30544
- </div>
30545
- }
30546
- </div>
30547
- </div>
30548
- </div>
30549
- </ds-mobile-section>
30550
-
30551
- @if (data.canCancel) {
30552
- <div class="booking-action">
30553
- <div class="booking-actions-row">
30554
- <ds-button
30555
- class="cancel-primary"
30556
- size="md"
30557
- variant="secondary"
30558
- (clicked)="cancelBooking()">
30559
- Annuller booking
30560
- </ds-button>
30561
- </div>
30562
- </div>
30563
- }
30564
- </ds-mobile-modal-base>
30565
- } @else {
30566
- <ds-mobile-bottom-sheet-wrapper [showDragHandle]="true">
30567
- <div class="detail-header">
30568
- <h2 class="detail-title">{{ data.facilityTitle }}</h2>
30569
- <ds-icon-button
30570
- icon="remixCloseLine"
30571
- variant="ghost"
30572
- size="sm"
30573
- (clicked)="close()"
30574
- aria-label="Luk"
30575
- />
30576
- </div>
30577
-
30578
- <div class="detail-content">
30579
- <div class="hero-image-container">
30580
- @if (data.heroImage) {
30581
- <img [src]="data.heroImage" [alt]="data.facilityTitle" class="hero-image" />
30582
- } @else {
30583
- <div class="hero-image-placeholder">
30584
- <ds-icon name="remixImageLine" size="48px" color="rgba(255,255,255,0.5)" />
30585
- </div>
30586
- }
30587
- </div>
30588
-
30589
- <div class="booking-summary-card">
30590
- <div class="details-section">
30591
- <h3 class="details-heading">Booking detaljer</h3>
30592
- <div class="info-rows">
30593
- @if (data.bookingDate) {
30594
- <div class="info-row">
30595
- <ds-icon name="remixCalendarLine" size="16px" color="tertiary" />
30596
- <span>{{ data.bookingDate }}</span>
30597
- </div>
30598
- }
30599
- @if (data.bookingTime) {
30600
- <div class="info-row">
30601
- <ds-icon name="remixTimeLine" size="16px" color="tertiary" />
30602
- <span>{{ data.bookingTime }}</span>
30603
- </div>
30604
- }
30605
- @if (data.price) {
30606
- <div class="info-row">
30607
- <ds-icon name="remixPriceTag3Line" size="16px" color="tertiary" />
30608
- <span>{{ data.price }}</span>
30609
- </div>
30610
- }
30611
- @if (data.bookingType) {
30612
- <div class="info-row">
30613
- <ds-icon name="remixCheckboxCircleLine" size="16px" color="tertiary" />
30614
- <span>{{ data.bookingType }}</span>
30615
- </div>
30616
- }
30617
- @for (req of data.requirements || []; track req) {
30618
- <div class="info-row">
30619
- <ds-icon name="remixLockLine" size="16px" color="tertiary" />
30620
- <span>{{ req }}</span>
30621
- </div>
30622
- }
30623
- </div>
30624
- </div>
30625
- </div>
30626
-
30627
- @if (data.canCancel) {
30628
- <div class="footer-button-container">
30629
- <div class="booking-actions-column">
30630
- <ds-button
30631
- size="md"
30632
- variant="secondary"
30633
- (clicked)="cancelBooking()">
30634
- Annuller booking
30635
- </ds-button>
30636
- </div>
30637
- </div>
30638
- }
30639
- </div>
30640
- </ds-mobile-bottom-sheet-wrapper>
30641
- }
30642
- `, styles: [":host{display:block;height:auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;box-sizing:border-box}.detail-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 8px}.detail-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-lg, 18px);font-weight:600;color:var(--text-color-default-primary, #202227);margin:0;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:12px}.detail-content{padding:8px 20px 24px;display:flex;flex-direction:column;gap:20px}.hero-image-container{width:100%;aspect-ratio:16 / 9;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5)}.hero-image{width:100%;height:100%;object-fit:cover;display:block}.hero-image-placeholder{width:100%;height:100%;min-height:0;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,color-mix(in srgb,var(--color-accent, #6B5FF5) 30%,transparent),color-mix(in srgb,var(--color-accent, #6B5FF5) 60%,transparent))}.booking-summary-card{background:var(--color-background-neutral-secondary, #f5f5f5);border-radius:16px;padding:16px}.details-section{display:flex;flex-direction:column;gap:12px}.details-heading{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);font-weight:600;color:var(--text-color-default-primary, #202227);margin:0}.info-rows{display:flex;flex-direction:column;gap:8px}.info-row{display:flex;align-items:center;gap:10px;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);color:var(--text-color-default-secondary, #545B66);line-height:1.4}.info-row ds-icon{flex-shrink:0}.footer-button-container{width:100%;padding:16px 20px 0}.footer-button-container ::ng-deep ds-button{display:block;width:100%}.footer-button-container ::ng-deep ds-button button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px}.booking-action{padding:16px 20px;padding-bottom:calc(16px + max(8px,env(safe-area-inset-bottom,0px) - 24px));background:var(--color-surface-primary, #ffffff)}.booking-actions-row{display:flex;flex-direction:row;align-items:center;gap:12px;width:100%}.booking-action .cancel-primary{flex:1;min-width:0;display:block}.booking-action .cancel-primary ::ng-deep button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px;padding-left:16px;padding-right:16px}:host.presentation-modal{display:block;height:auto;width:100%;min-height:0;overflow:hidden}\n"] }]
30643
- }], ctorParameters: () => [{ type: i1.ModalController }], propDecorators: { presentation: [{
30644
- type: Input
30645
- }], data: [{
30646
- type: Input
30647
- }], autoHeight: [{
30648
- type: Input
30649
- }], isModalPresentation: [{
30650
- type: HostBinding,
30651
- args: ['class.presentation-modal']
30652
- }] } });
30653
-
30654
- class DsMobileBookingDetailSheetService extends BaseModalService {
30655
- bottomSheet;
30656
- constructor(modalController, bottomSheet) {
30657
- super(modalController);
30658
- this.bottomSheet = bottomSheet;
30659
- }
30660
- /**
30661
- * Bottom-sheet presentation (draggable breakpoints). Prefer `openAsModal` for booking lists.
30662
- */
30663
- async open(data) {
30664
- const modal = await this.bottomSheet.create({
30665
- component: DsMobileBookingDetailSheetComponent,
30666
- componentProps: { data },
30667
- autoHeight: true,
30668
- backdropDismiss: true,
30669
- backdropBlur: true,
30670
- });
30671
- const result = await modal.onWillDismiss();
30672
- return { role: result.role, data: result.data ?? undefined };
30673
- }
30674
- /** `ds-modal-base` shell — used for active and past bookings. Auto-heights to content. */
30675
- async openAsModal(data) {
30676
- const modal = await this.createModal(DsMobileBookingDetailSheetComponent, { data, presentation: 'modal', autoHeight: true }, { keyboardClose: true, autoHeight: true });
30677
- await modal.present();
30678
- const result = await modal.onWillDismiss();
30679
- return { role: result.role, data: result.data ?? undefined };
30680
- }
30681
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetService, deps: [{ token: i1.ModalController }, { token: DsMobileBottomSheetService }], target: i0.ɵɵFactoryTarget.Injectable });
30682
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetService, providedIn: 'root' });
30683
- }
30684
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingDetailSheetService, decorators: [{
30685
- type: Injectable,
30686
- args: [{
30687
- providedIn: 'root',
30688
- }]
30689
- }], ctorParameters: () => [{ type: i1.ModalController }, { type: DsMobileBottomSheetService }] });
30690
-
30691
30849
  const VENDOR_MODAL_SERVICE = new InjectionToken('VendorModalService');
30692
30850
  const BOOKING_DETAIL_MAP = {
30693
30851
  'booking-1': {
@@ -35691,78 +35849,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
35691
35849
  `, styles: [":host{display:block;height:100dvh;width:100vw;position:relative}.app-error{position:fixed;inset:0;z-index:9999;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:40px 32px;background:var(--color-header-surface, #2D2356)}.app-error__title{font-family:Brockmann,sans-serif;font-size:var(--font-size-lg, 18px);font-weight:600;color:var(--color-header-content, #fff);text-align:center;margin:0}.app-error__description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:#ffffffa6;text-align:center;margin:0 0 8px}.app-error ds-button::ng-deep .btn{border-radius:9999px}\n"] }]
35692
35850
  }], ctorParameters: () => [{ type: UserService }, { type: i1$3.Router }, { type: i1.NavController }] });
35693
35851
 
35694
- class DsMobileBookingCancelConfirmationComponent {
35695
- facilityTitle;
35696
- facilityThumbnail;
35697
- bookingDate;
35698
- bookingTime;
35699
- get confirmationMessage() {
35700
- const datePart = this.bookingDate ? ` den ${this.bookingDate}` : '';
35701
- return `Er du sikker på, at du vil annullere din booking af ${this.facilityTitle}${datePart}?`;
35702
- }
35703
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingCancelConfirmationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
35704
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: DsMobileBookingCancelConfirmationComponent, isStandalone: true, selector: "ds-mobile-booking-cancel-confirmation", inputs: { facilityTitle: "facilityTitle", facilityThumbnail: "facilityThumbnail", bookingDate: "bookingDate", bookingTime: "bookingTime" }, ngImport: i0, template: `
35705
- <ds-mobile-confirmation-sheet
35706
- [title]="'Annuller booking?'"
35707
- [message]="confirmationMessage"
35708
- [buttonText]="'Ja, annuller booking'"
35709
- [destructive]="true"
35710
- [secondaryButtonText]="'Luk'"
35711
- [secondaryButtonVariant]="'secondary'"
35712
- [illustrationVariant]="'delete-warning'"
35713
- [illustrationSize]="'140px'">
35714
- <ng-template #summary>
35715
- <ds-mobile-booking-summary
35716
- [facilityTitle]="facilityTitle"
35717
- [facilityThumbnail]="facilityThumbnail"
35718
- [date]="bookingDate"
35719
- [time]="bookingTime"
35720
- />
35721
- </ng-template>
35722
- </ds-mobile-confirmation-sheet>
35723
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsMobileConfirmationSheetComponent, selector: "ds-mobile-confirmation-sheet", inputs: ["title", "message", "buttonText", "destructive", "showCancelButton", "cancelButtonText", "showIllustration", "illustrationVariant", "illustrationSize", "secondaryButtonText", "secondaryButtonVariant"] }, { kind: "component", type: DsMobileBookingSummaryComponent, selector: "ds-mobile-booking-summary", inputs: ["facilityTitle", "facilityThumbnail", "date", "time", "bookingCount"] }] });
35724
- }
35725
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileBookingCancelConfirmationComponent, decorators: [{
35726
- type: Component,
35727
- args: [{
35728
- selector: 'ds-mobile-booking-cancel-confirmation',
35729
- standalone: true,
35730
- imports: [
35731
- CommonModule,
35732
- DsMobileConfirmationSheetComponent,
35733
- DsMobileBookingSummaryComponent
35734
- ],
35735
- template: `
35736
- <ds-mobile-confirmation-sheet
35737
- [title]="'Annuller booking?'"
35738
- [message]="confirmationMessage"
35739
- [buttonText]="'Ja, annuller booking'"
35740
- [destructive]="true"
35741
- [secondaryButtonText]="'Luk'"
35742
- [secondaryButtonVariant]="'secondary'"
35743
- [illustrationVariant]="'delete-warning'"
35744
- [illustrationSize]="'140px'">
35745
- <ng-template #summary>
35746
- <ds-mobile-booking-summary
35747
- [facilityTitle]="facilityTitle"
35748
- [facilityThumbnail]="facilityThumbnail"
35749
- [date]="bookingDate"
35750
- [time]="bookingTime"
35751
- />
35752
- </ng-template>
35753
- </ds-mobile-confirmation-sheet>
35754
- `
35755
- }]
35756
- }], propDecorators: { facilityTitle: [{
35757
- type: Input
35758
- }], facilityThumbnail: [{
35759
- type: Input
35760
- }], bookingDate: [{
35761
- type: Input
35762
- }], bookingTime: [{
35763
- type: Input
35764
- }] } });
35765
-
35766
35852
  const HISTORY_LINK = {
35767
35853
  da: 'Historik',
35768
35854
  en: 'History',
@@ -38860,5 +38946,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
38860
38946
  * Generated bundle index. Do not edit.
38861
38947
  */
38862
38948
 
38863
- export { AcceptInvitePageComponent, ActionCommentComponent, ActionLikeComponent, AvatarUploadPageComponent, BaseModalService, ContentRowComponent, CreateAccountPageComponent, DEFAULT_SERVICE_PAGE_LABELS, DsAppIconComponent, DsAvatarWithBadgeComponent, DsLogoComponent, DsMobileAccessSheetComponent, DsMobileActionListItemComponent, DsMobileActionsBottomSheetComponent, DsMobileAddGroupTenantsModalComponent, DsMobileAppLoadingComponent, DsMobileAttachmentPreviewComponent, DsMobileBookingConfirmationWrapperComponent, DsMobileBookingModalComponent, DsMobileBookingModalService, DsMobileBookingSummaryComponent, DsMobileBottomSheetHeaderComponent, DsMobileBottomSheetService, DsMobileBottomSheetWrapperComponent, DsMobileCapacitySheetComponent, DsMobileCardInlineBannerComponent, DsMobileCardInlineComponent, DsMobileCardInlineContactComponent, DsMobileCardInlineFileComponent, DsMobileChatModalComponent, DsMobileChatModalService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileCommunityAdminPickerComponent, DsMobileCommunityAdminsModalComponent, DsMobileConfirmationSheetComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileCountBadgeComponent, DsMobileCreateGroupModalComponent, DsMobileDropdownComponent, DsMobileEditGroupModalComponent, DsMobileEmptyStateComponent, DsMobileFabComponent, DsMobileFacilityArchiveConfirmationComponent, DsMobileFacilityCreationConfirmationWrapperComponent, DsMobileFacilityCreationModalComponent, DsMobileFacilityCreationModalService, DsMobileFacilityDeleteConfirmationComponent, DsMobileFacilityDetailModalComponent, DsMobileFacilityDetailModalService, DsMobileFileAttachmentComponent, DsMobileGlassSpinnerComponent, DsMobileGroupAvatarStackComponent, DsMobileGroupMembersModalComponent, DsMobileHandbookDetailModalComponent, DsMobileHandbookDetailModalService, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileIllustrationComponent, DsMobileImagePlaceholderComponent, DsMobileInlinePhotoComponent, DsMobileInlineTabsComponent, DsMobileInteractiveListItemBookingComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxImageWithDescriptionComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileListItemStaticComponent, DsMobileListSearchComponent, DsMobileLoaderOverlayComponent, DsMobileLongPressDirective, DsMobileMediaActionsPanelComponent, DsMobileMessageBubbleComponent, DsMobileMessageComposerComponent, DsMobileModalBaseComponent, DsMobileModalService, DsMobileNewInquiryModalComponent, DsMobileNewInquiryModalService, DsMobileNotificationButtonComponent, DsMobileNotificationModalComponent, DsMobileNotificationModalService, DsMobileNotificationPromptComponent, DsMobileOfflineBannerComponent, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobilePillComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobilePriceSheetComponent, DsMobileProfileActionsSheetComponent, DsMobilePromptBottomSheetComponent, DsMobilePropertyBannerComponent, DsMobileRichTextEditorComponent, DsMobileSectionComponent, DsMobileServiceVendorModalService, DsMobileServiceVendorSheetComponent, DsMobileSwiperComponent, DsMobileSwiperWithNavComponent, DsMobileSystemMessageBannerComponent, DsMobileTabBarComponent, DsMobileTabsComponent, DsMobileTenantPickerModalComponent, DsMobileToggleComponent, DsMobileWhenCanBookSheetComponent, DsMobileWhoCanBookSheetComponent, DsTextInputComponent, FamilyAccessPageComponent, FamilyAccessService, InquiriesService, InviteSuccessPageComponent, MediaPickerService, MobileBookingPageComponent, MobileCommunityPageComponent, MobileHandbookPageComponent, MobileHomePageComponent, MobileInquiriesPageComponent, MobileInquiryDetailPageComponent, MobileModalBase, MobilePageBase, MobilePostDetailPageComponent, MobileTabsExampleComponent, NOTIFICATION_ICON_MAP, NotificationPromptService, NotificationService, PageLoadingService, PostActionsComponent, PostAttachmentsComponent, PostContentComponent, PostCreatePageComponent, PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent, PostsService, RelativeTimePipe, SAMPLE_NOTIFICATIONS, SectionHeaderComponent, ServicesPageComponent, SettingsModalService, SignInPageComponent, SignInToAcceptPageComponent, TenantChatPageComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent, TrackingPermissionService, UserService, VENDOR_MODAL_SERVICE, WhitelabelDemoModalComponent, WhitelabelDemoModalService, WhitelabelService, customBackTransition, customPageTransition, dateBucket };
38949
+ export { AcceptInvitePageComponent, ActionCommentComponent, ActionLikeComponent, AvatarUploadPageComponent, BaseModalService, ContentRowComponent, CreateAccountPageComponent, DEFAULT_SERVICE_PAGE_LABELS, DsAppIconComponent, DsAvatarWithBadgeComponent, DsLogoComponent, DsMobileAccessSheetComponent, DsMobileActionListItemComponent, DsMobileActionsBottomSheetComponent, DsMobileAddGroupTenantsModalComponent, DsMobileAppLoadingComponent, DsMobileAttachmentPreviewComponent, DsMobileBookingCancelConfirmationComponent, DsMobileBookingConfirmationWrapperComponent, DsMobileBookingDetailSheetComponent, DsMobileBookingDetailSheetService, DsMobileBookingModalComponent, DsMobileBookingModalService, DsMobileBookingSummaryComponent, DsMobileBottomSheetHeaderComponent, DsMobileBottomSheetService, DsMobileBottomSheetWrapperComponent, DsMobileCapacitySheetComponent, DsMobileCardInlineBannerComponent, DsMobileCardInlineComponent, DsMobileCardInlineContactComponent, DsMobileCardInlineFileComponent, DsMobileChatModalComponent, DsMobileChatModalService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileCommunityAdminPickerComponent, DsMobileCommunityAdminsModalComponent, DsMobileConfirmationSheetComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileCountBadgeComponent, DsMobileCreateGroupModalComponent, DsMobileDropdownComponent, DsMobileEditGroupModalComponent, DsMobileEmptyStateComponent, DsMobileFabComponent, DsMobileFacilityArchiveConfirmationComponent, DsMobileFacilityCreationConfirmationWrapperComponent, DsMobileFacilityCreationModalComponent, DsMobileFacilityCreationModalService, DsMobileFacilityDeleteConfirmationComponent, DsMobileFacilityDetailModalComponent, DsMobileFacilityDetailModalService, DsMobileFileAttachmentComponent, DsMobileGlassSpinnerComponent, DsMobileGroupAvatarStackComponent, DsMobileGroupMembersModalComponent, DsMobileHandbookDetailModalComponent, DsMobileHandbookDetailModalService, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileIllustrationComponent, DsMobileImagePlaceholderComponent, DsMobileInlinePhotoComponent, DsMobileInlineTabsComponent, DsMobileInteractiveListItemBookingComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxImageWithDescriptionComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileListItemStaticComponent, DsMobileListSearchComponent, DsMobileLoaderOverlayComponent, DsMobileLongPressDirective, DsMobileMediaActionsPanelComponent, DsMobileMessageBubbleComponent, DsMobileMessageComposerComponent, DsMobileModalBaseComponent, DsMobileModalService, DsMobileNewInquiryModalComponent, DsMobileNewInquiryModalService, DsMobileNotificationButtonComponent, DsMobileNotificationModalComponent, DsMobileNotificationModalService, DsMobileNotificationPromptComponent, DsMobileOfflineBannerComponent, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobilePillComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobilePriceSheetComponent, DsMobileProfileActionsSheetComponent, DsMobilePromptBottomSheetComponent, DsMobilePropertyBannerComponent, DsMobileRichTextEditorComponent, DsMobileSectionComponent, DsMobileServiceVendorModalService, DsMobileServiceVendorSheetComponent, DsMobileSwiperComponent, DsMobileSwiperWithNavComponent, DsMobileSystemMessageBannerComponent, DsMobileTabBarComponent, DsMobileTabsComponent, DsMobileTenantPickerModalComponent, DsMobileToggleComponent, DsMobileWhenCanBookSheetComponent, DsMobileWhoCanBookSheetComponent, DsTextInputComponent, FamilyAccessPageComponent, FamilyAccessService, InquiriesService, InviteSuccessPageComponent, MediaPickerService, MobileBookingPageComponent, MobileCommunityPageComponent, MobileHandbookPageComponent, MobileHomePageComponent, MobileInquiriesPageComponent, MobileInquiryDetailPageComponent, MobileModalBase, MobilePageBase, MobilePostDetailPageComponent, MobileTabsExampleComponent, NOTIFICATION_ICON_MAP, NotificationPromptService, NotificationService, PageLoadingService, PostActionsComponent, PostAttachmentsComponent, PostContentComponent, PostCreatePageComponent, PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent, PostsService, RelativeTimePipe, SAMPLE_NOTIFICATIONS, SectionHeaderComponent, ServicesPageComponent, SettingsModalService, SignInPageComponent, SignInToAcceptPageComponent, TenantChatPageComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent, TrackingPermissionService, UserService, VENDOR_MODAL_SERVICE, WhitelabelDemoModalComponent, WhitelabelDemoModalService, WhitelabelService, customBackTransition, customPageTransition, dateBucket };
38864
38950
  //# sourceMappingURL=propbinder-mobile-design.mjs.map