@propbinder/mobile-design 0.1.16 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/propbinder-mobile-design.mjs +1632 -1604
- package/fesm2022/propbinder-mobile-design.mjs.map +1 -1
- package/index.d.ts +276 -238
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, computed, effect, Injectable, inject, Input, Component, input, Directive, EventEmitter, HostListener, Output, PLATFORM_ID, output, ViewChild,
|
|
2
|
+
import { signal, computed, effect, Injectable, inject, Input, Component, input, Directive, EventEmitter, HostListener, Output, PLATFORM_ID, output, ViewChild, model, ElementRef, CUSTOM_ELEMENTS_SCHEMA, createComponent, forwardRef, ViewEncapsulation } from '@angular/core';
|
|
3
3
|
import * as i1$2 from '@angular/common';
|
|
4
4
|
import { CommonModule, isPlatformBrowser } from '@angular/common';
|
|
5
5
|
import * as i1$3 from '@angular/router';
|
|
6
6
|
import { Router, NavigationEnd } from '@angular/router';
|
|
7
7
|
import * as i1 from '@ionic/angular/standalone';
|
|
8
|
-
import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons,
|
|
8
|
+
import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, Platform, ModalController, IonRefresher, IonRefresherContent, IonTabBar, IonTabButton, IonLabel, IonTabs, IonTab, IonSpinner, IonButton } from '@ionic/angular/standalone';
|
|
9
9
|
import { ImpactStyle, Haptics } from '@capacitor/haptics';
|
|
10
10
|
import { DsIconButtonComponent, DsIconComponent, DsButtonComponent, DsAvatarComponent, DsShapeIndicatorComponent } from '@propbinder/design-system';
|
|
11
11
|
import { StatusBar } from '@capacitor/status-bar';
|
|
@@ -1815,1108 +1815,576 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
1815
1815
|
}] } });
|
|
1816
1816
|
|
|
1817
1817
|
/**
|
|
1818
|
-
*
|
|
1819
|
-
*
|
|
1820
|
-
* Displays an avatar with a logomark badge overlay.
|
|
1821
|
-
* Useful for showing user avatars with organization branding.
|
|
1822
|
-
*
|
|
1823
|
-
* @example
|
|
1824
|
-
* ```html
|
|
1825
|
-
* <ds-avatar-with-badge
|
|
1826
|
-
* [type]="'initials'"
|
|
1827
|
-
* [initials]="'JD'"
|
|
1828
|
-
* [size]="'lg'"
|
|
1829
|
-
* [badgePosition]="'bottom-right'"
|
|
1830
|
-
* />
|
|
1831
|
-
* ```
|
|
1818
|
+
* User service for managing current user data globally
|
|
1832
1819
|
*/
|
|
1833
|
-
class
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1820
|
+
class UserService {
|
|
1821
|
+
// User avatar configuration
|
|
1822
|
+
_avatarInitials = signal('LM', ...(ngDevMode ? [{ debugName: "_avatarInitials" }] : []));
|
|
1823
|
+
_avatarType = signal('initials', ...(ngDevMode ? [{ debugName: "_avatarType" }] : []));
|
|
1824
|
+
_avatarSrc = signal('', ...(ngDevMode ? [{ debugName: "_avatarSrc" }] : []));
|
|
1825
|
+
// Profile menu items configuration
|
|
1826
|
+
_profileMenuItems = signal(undefined, ...(ngDevMode ? [{ debugName: "_profileMenuItems" }] : []));
|
|
1827
|
+
// Readonly computed values
|
|
1828
|
+
avatarInitials = this._avatarInitials.asReadonly();
|
|
1829
|
+
avatarType = this._avatarType.asReadonly();
|
|
1830
|
+
avatarSrc = this._avatarSrc.asReadonly();
|
|
1831
|
+
profileMenuItems = this._profileMenuItems.asReadonly();
|
|
1832
|
+
/**
|
|
1833
|
+
* Update avatar configuration
|
|
1834
|
+
*/
|
|
1835
|
+
setAvatarInitials(initials) {
|
|
1836
|
+
this._avatarInitials.set(initials);
|
|
1837
|
+
}
|
|
1838
|
+
setAvatarType(type) {
|
|
1839
|
+
this._avatarType.set(type);
|
|
1840
|
+
}
|
|
1841
|
+
setAvatarSrc(src) {
|
|
1842
|
+
this._avatarSrc.set(src);
|
|
1843
|
+
}
|
|
1844
|
+
/**
|
|
1845
|
+
* Set profile menu items globally.
|
|
1846
|
+
* This will be used by both ds-mobile-tab-bar and ds-mobile-page-main
|
|
1847
|
+
* if they don't receive profileMenuItems as an input.
|
|
1848
|
+
*/
|
|
1849
|
+
setProfileMenuItems(items) {
|
|
1850
|
+
this._profileMenuItems.set(items);
|
|
1851
|
+
}
|
|
1852
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: UserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1853
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: UserService, providedIn: 'root' });
|
|
1865
1854
|
}
|
|
1866
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type:
|
|
1867
|
-
type:
|
|
1868
|
-
args: [{
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
[size]="size"
|
|
1873
|
-
[initials]="initials"
|
|
1874
|
-
[src]="src"
|
|
1875
|
-
[iconName]="iconName"
|
|
1876
|
-
/>
|
|
1877
|
-
|
|
1878
|
-
@if (showBadge) {
|
|
1879
|
-
<div [class]="badgeClasses()">
|
|
1880
|
-
<img [src]="whitelabelService.logoMarkUrl()" [alt]="whitelabelService.logoAlt()" />
|
|
1881
|
-
</div>
|
|
1882
|
-
}
|
|
1883
|
-
</div>
|
|
1884
|
-
`, styles: [":host{display:inline-block;position:relative}.avatar-badge-container{position:relative;display:inline-block}.avatar-badge{position:absolute;background:var(--color-brand-secondary, #5d5fef);border-radius:8px;display:flex;align-items:center;justify-content:center;border:2px solid var(--color-background-primary, #ffffff)}.avatar-badge img{width:10px;height:10px;object-fit:contain}.avatar-badge--bottom-right{bottom:-6px;right:-6px}.avatar-badge--bottom-left{bottom:-6px;left:-6px}.avatar-badge--top-right{top:-6px;right:-6px}.avatar-badge--top-left{top:-6px;left:-6px}.avatar-badge--xs{width:16px;height:16px}.avatar-badge--sm{width:18px;height:18px}.avatar-badge--md{width:20px;height:20px}.avatar-badge--lg{width:24px;height:24px}.avatar-badge--xl{width:28px;height:28px}\n"] }]
|
|
1885
|
-
}], propDecorators: { type: [{
|
|
1886
|
-
type: Input
|
|
1887
|
-
}], size: [{
|
|
1888
|
-
type: Input
|
|
1889
|
-
}], initials: [{
|
|
1890
|
-
type: Input
|
|
1891
|
-
}], src: [{
|
|
1892
|
-
type: Input
|
|
1893
|
-
}], iconName: [{
|
|
1894
|
-
type: Input
|
|
1895
|
-
}], showBadge: [{
|
|
1896
|
-
type: Input
|
|
1897
|
-
}], badgePosition: [{
|
|
1898
|
-
type: Input
|
|
1899
|
-
}] } });
|
|
1855
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: UserService, decorators: [{
|
|
1856
|
+
type: Injectable,
|
|
1857
|
+
args: [{
|
|
1858
|
+
providedIn: 'root'
|
|
1859
|
+
}]
|
|
1860
|
+
}] });
|
|
1900
1861
|
|
|
1901
1862
|
/**
|
|
1902
|
-
*
|
|
1863
|
+
* DsMobilePageMainComponent
|
|
1903
1864
|
*
|
|
1904
|
-
*
|
|
1905
|
-
*
|
|
1865
|
+
* A complete mobile page layout for main/tab pages with:
|
|
1866
|
+
* - Fixed header with logomark + title + avatar
|
|
1867
|
+
* - Purple expandable header section (scrolls with content)
|
|
1868
|
+
* - White rounded content wrapper
|
|
1869
|
+
* - Pull-to-refresh support
|
|
1870
|
+
* - Auto scroll title fade-in
|
|
1871
|
+
*
|
|
1872
|
+
* @example
|
|
1873
|
+
* ```html
|
|
1874
|
+
* <!-- Simple page -->
|
|
1875
|
+
* <ds-mobile-page-main
|
|
1876
|
+
* title="Inquiries"
|
|
1877
|
+
* [avatarInitials]="'JD'">
|
|
1878
|
+
* <div class="page-content">
|
|
1879
|
+
* <!-- Your content -->
|
|
1880
|
+
* </div>
|
|
1881
|
+
* </ds-mobile-page-main>
|
|
1882
|
+
*
|
|
1883
|
+
* <!-- Page with custom header content -->
|
|
1884
|
+
* <ds-mobile-page-main
|
|
1885
|
+
* title="Home"
|
|
1886
|
+
* headerTitle="Welcome, Lars"
|
|
1887
|
+
* headerSubtitle="Your rental property at a glance."
|
|
1888
|
+
* [avatarInitials]="'L'">
|
|
1889
|
+
*
|
|
1890
|
+
* <div header-content class="property-tiles">
|
|
1891
|
+
* <!-- Custom header content like tiles -->
|
|
1892
|
+
* </div>
|
|
1893
|
+
*
|
|
1894
|
+
* <div class="page-content">
|
|
1895
|
+
* <!-- Main page content -->
|
|
1896
|
+
* </div>
|
|
1897
|
+
* </ds-mobile-page-main>
|
|
1898
|
+
* ```
|
|
1906
1899
|
*/
|
|
1907
|
-
class
|
|
1908
|
-
|
|
1900
|
+
class DsMobilePageMainComponent extends MobilePageBase {
|
|
1901
|
+
elementRef;
|
|
1902
|
+
ionContent;
|
|
1903
|
+
// Platform detection
|
|
1904
|
+
platform = inject(Platform);
|
|
1909
1905
|
modalController = inject(ModalController);
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
//
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1906
|
+
router = inject(Router);
|
|
1907
|
+
userService = inject(UserService);
|
|
1908
|
+
// Computed property to check if running on native platform
|
|
1909
|
+
isNativePlatform = computed(() => this.platform.is('ios') ||
|
|
1910
|
+
this.platform.is('android') ||
|
|
1911
|
+
this.platform.is('capacitor'), ...(ngDevMode ? [{ debugName: "isNativePlatform" }] : []));
|
|
1912
|
+
// Inputs - Title
|
|
1913
|
+
title = input.required(...(ngDevMode ? [{ debugName: "title" }] : [])); // For fixed header title
|
|
1914
|
+
headerTitle = input('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : [])); // Optional different title for expandable header
|
|
1915
|
+
headerSubtitle = input('', ...(ngDevMode ? [{ debugName: "headerSubtitle" }] : []));
|
|
1916
|
+
// Inputs - Avatar
|
|
1917
|
+
avatarType = input('initials', ...(ngDevMode ? [{ debugName: "avatarType" }] : []));
|
|
1918
|
+
avatarInitials = input('U', ...(ngDevMode ? [{ debugName: "avatarInitials" }] : []));
|
|
1919
|
+
avatarSrc = input('', ...(ngDevMode ? [{ debugName: "avatarSrc" }] : []));
|
|
1920
|
+
avatarIconName = input('remixUser3Line', ...(ngDevMode ? [{ debugName: "avatarIconName" }] : []));
|
|
1921
|
+
// Inputs - Features
|
|
1922
|
+
showRefresh = input(true, ...(ngDevMode ? [{ debugName: "showRefresh" }] : []));
|
|
1923
|
+
showCondensedHeader = input(true, ...(ngDevMode ? [{ debugName: "showCondensedHeader" }] : []));
|
|
1924
|
+
scrollThreshold = input(160, ...(ngDevMode ? [{ debugName: "scrollThreshold" }] : [])); // Pixels to scroll before title appears
|
|
1925
|
+
headerFadeDistance = input(150, ...(ngDevMode ? [{ debugName: "headerFadeDistance" }] : [])); // Distance over which header fades out
|
|
1921
1926
|
/**
|
|
1922
|
-
*
|
|
1927
|
+
* Profile menu action groups to display when avatar is clicked.
|
|
1928
|
+
* If not provided, a default menu will be used (without Whitelabel Demo).
|
|
1929
|
+
*
|
|
1930
|
+
* @example
|
|
1931
|
+
* ```typescript
|
|
1932
|
+
* profileMenuItems: ActionGroup[] = [
|
|
1933
|
+
* {
|
|
1934
|
+
* actions: [
|
|
1935
|
+
* { action: 'profile', title: 'Min profil', icon: 'remixUser3Line' },
|
|
1936
|
+
* { action: 'settings', title: 'Indstillinger', icon: 'remixSettings3Line' }
|
|
1937
|
+
* ]
|
|
1938
|
+
* },
|
|
1939
|
+
* {
|
|
1940
|
+
* actions: [
|
|
1941
|
+
* { action: 'logout', title: 'Log ud', icon: 'remixLogoutBoxLine', destructive: true }
|
|
1942
|
+
* ]
|
|
1943
|
+
* }
|
|
1944
|
+
* ];
|
|
1945
|
+
* ```
|
|
1923
1946
|
*/
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
this.currentTheme = 'cej';
|
|
1928
|
-
}
|
|
1929
|
-
else if (secondarySurface === '#660036') {
|
|
1930
|
-
this.currentTheme = 'pka';
|
|
1931
|
-
}
|
|
1932
|
-
else if (secondarySurface === '#262424') {
|
|
1933
|
-
this.currentTheme = 'clave';
|
|
1934
|
-
}
|
|
1935
|
-
else {
|
|
1936
|
-
this.currentTheme = 'default';
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1947
|
+
profileMenuItems = input(undefined, ...(ngDevMode ? [{ debugName: "profileMenuItems" }] : []));
|
|
1948
|
+
// Outputs
|
|
1949
|
+
avatarClick = output();
|
|
1939
1950
|
/**
|
|
1940
|
-
*
|
|
1951
|
+
* Emitted when a profile menu action is selected.
|
|
1952
|
+
* Parent component should handle the action logic (navigation, logout, etc.).
|
|
1941
1953
|
*/
|
|
1942
|
-
|
|
1943
|
-
|
|
1954
|
+
profileActionSelected = output();
|
|
1955
|
+
refresh = output();
|
|
1956
|
+
scroll = output();
|
|
1957
|
+
constructor(elementRef) {
|
|
1958
|
+
super();
|
|
1959
|
+
this.elementRef = elementRef;
|
|
1944
1960
|
}
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
this.whitelabelService.updateConfig({
|
|
1948
|
-
logoUrl: '/Assets/logos/propbinder-logomark.svg',
|
|
1949
|
-
logoMarkUrl: '/Assets/logos/propbinder-logomark.svg',
|
|
1950
|
-
logoAlt: 'Propbinder',
|
|
1951
|
-
logoHeight: 28,
|
|
1952
|
-
primarySurface: '#6B5FF5',
|
|
1953
|
-
primaryContent: '#FFFFFF',
|
|
1954
|
-
secondarySurface: '#221a4c',
|
|
1955
|
-
secondaryContent: '#FFFFFF',
|
|
1956
|
-
organizationName: 'Propbinder',
|
|
1957
|
-
organizationId: 'default'
|
|
1958
|
-
});
|
|
1959
|
-
this.updateCustomColorInputs();
|
|
1961
|
+
ngAfterViewInit() {
|
|
1962
|
+
// Initial setup if needed
|
|
1960
1963
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
1964
|
+
/**
|
|
1965
|
+
* Handle avatar click - opens profile actions bottom sheet
|
|
1966
|
+
*/
|
|
1967
|
+
async handleAvatarClick() {
|
|
1968
|
+
console.log('Avatar clicked - opening profile bottom sheet');
|
|
1969
|
+
// Emit the event for any parent listeners
|
|
1970
|
+
this.avatarClick.emit();
|
|
1971
|
+
// Use input if provided, otherwise fall back to service, otherwise use default menu
|
|
1972
|
+
const menuItems = this.profileMenuItems() || this.userService.profileMenuItems() || [
|
|
1973
|
+
{
|
|
1974
|
+
actions: [
|
|
1975
|
+
{
|
|
1976
|
+
action: 'profile',
|
|
1977
|
+
title: 'Min profil',
|
|
1978
|
+
icon: 'remixUser3Line',
|
|
1979
|
+
destructive: false
|
|
1980
|
+
},
|
|
1981
|
+
{
|
|
1982
|
+
action: 'settings',
|
|
1983
|
+
title: 'Indstillinger',
|
|
1984
|
+
icon: 'remixSettings3Line',
|
|
1985
|
+
destructive: false
|
|
1986
|
+
}
|
|
1987
|
+
]
|
|
1988
|
+
},
|
|
1989
|
+
{
|
|
1990
|
+
actions: [
|
|
1991
|
+
{
|
|
1992
|
+
action: 'logout',
|
|
1993
|
+
title: 'Log ud',
|
|
1994
|
+
icon: 'remixLogoutBoxLine',
|
|
1995
|
+
destructive: true
|
|
1996
|
+
}
|
|
1997
|
+
]
|
|
1998
|
+
}
|
|
1999
|
+
];
|
|
2000
|
+
// If no menu items configured, just emit and return
|
|
2001
|
+
if (!menuItems || menuItems.length === 0) {
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
const sheet = await this.modalController.create({
|
|
2005
|
+
component: DsMobileActionsBottomSheetComponent,
|
|
2006
|
+
componentProps: {
|
|
2007
|
+
customActionGroups: menuItems
|
|
2008
|
+
},
|
|
2009
|
+
// Auto-height: no breakpoints, no handle
|
|
2010
|
+
cssClass: 'ds-bottom-sheet auto-height'
|
|
2006
2011
|
});
|
|
2007
|
-
|
|
2012
|
+
await sheet.present();
|
|
2013
|
+
const result = await sheet.onWillDismiss();
|
|
2014
|
+
if (result.data?.action) {
|
|
2015
|
+
// Emit the selected action to parent
|
|
2016
|
+
this.profileActionSelected.emit(result.data);
|
|
2017
|
+
}
|
|
2008
2018
|
}
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2019
|
+
/**
|
|
2020
|
+
* Handle scroll events
|
|
2021
|
+
* - Shows title in fixed header when scrolled past threshold
|
|
2022
|
+
* - Fades out expandable header content based on scroll position
|
|
2023
|
+
* - Emits scroll event for custom handling
|
|
2024
|
+
*/
|
|
2025
|
+
handleScroll(event) {
|
|
2026
|
+
const scrollTop = event.detail.scrollTop;
|
|
2027
|
+
const header = this.elementRef.nativeElement.querySelector('ion-header:not([collapse])');
|
|
2028
|
+
const headerExpandable = this.elementRef.nativeElement.querySelector('.header-expandable');
|
|
2029
|
+
// Show title in fixed header when scrolled past threshold
|
|
2030
|
+
if (scrollTop > this.scrollThreshold()) {
|
|
2031
|
+
header?.classList.add('header-scrolled');
|
|
2032
|
+
}
|
|
2033
|
+
else {
|
|
2034
|
+
header?.classList.remove('header-scrolled');
|
|
2035
|
+
}
|
|
2036
|
+
// Fade out header-expandable content based on scroll
|
|
2037
|
+
if (headerExpandable) {
|
|
2038
|
+
const fadeDistance = this.headerFadeDistance();
|
|
2039
|
+
const fadeProgress = Math.min(scrollTop / fadeDistance, 1);
|
|
2040
|
+
// Calculate opacity (1 to 0)
|
|
2041
|
+
const opacity = 1 - fadeProgress;
|
|
2042
|
+
// Calculate transform (0px to -20px upward)
|
|
2043
|
+
const translateY = fadeProgress * -20;
|
|
2044
|
+
// Apply styles
|
|
2045
|
+
headerExpandable.style.opacity = opacity.toString();
|
|
2046
|
+
headerExpandable.style.transform = `translateY(${translateY}px)`;
|
|
2047
|
+
}
|
|
2048
|
+
this.scroll.emit(event);
|
|
2016
2049
|
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2050
|
+
/**
|
|
2051
|
+
* Handle pull-to-refresh
|
|
2052
|
+
* Emits refresh event - parent should call event.target.complete()
|
|
2053
|
+
*/
|
|
2054
|
+
async handleRefresh(event) {
|
|
2055
|
+
// Haptic feedback for pull-to-refresh
|
|
2056
|
+
try {
|
|
2057
|
+
await Haptics.impact({ style: ImpactStyle.Medium });
|
|
2058
|
+
}
|
|
2059
|
+
catch {
|
|
2060
|
+
// Fallback to Web Vibration API if Capacitor Haptics is not available
|
|
2061
|
+
if ('vibrate' in navigator) {
|
|
2062
|
+
navigator.vibrate(50);
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
this.refresh.emit(event);
|
|
2022
2066
|
}
|
|
2023
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type:
|
|
2024
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
2025
|
-
<!-- Fixed
|
|
2026
|
-
<
|
|
2027
|
-
<
|
|
2028
|
-
<
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
variant="secondary"
|
|
2032
|
-
size="lg"
|
|
2033
|
-
(click)="close()"
|
|
2034
|
-
class="close-button"
|
|
2035
|
-
aria-label="Close">
|
|
2036
|
-
</ds-icon-button>
|
|
2037
|
-
</div>
|
|
2038
|
-
</div>
|
|
2039
|
-
|
|
2040
|
-
<!-- Scrollable Content -->
|
|
2041
|
-
<ion-content [scrollY]="true" class="modal-content">
|
|
2042
|
-
<div class="demo-container">
|
|
2043
|
-
<!-- Theme Selection -->
|
|
2044
|
-
<div class="demo-section">
|
|
2045
|
-
<h2>Theme</h2>
|
|
2046
|
-
<div class="theme-buttons">
|
|
2047
|
-
<button class="theme-btn" (click)="applyDefaultTheme()" [class.active]="currentTheme === 'default'">
|
|
2048
|
-
Propbinder
|
|
2049
|
-
</button>
|
|
2050
|
-
<button class="theme-btn" (click)="applyCejTheme()" [class.active]="currentTheme === 'cej'">
|
|
2051
|
-
CEJ
|
|
2052
|
-
</button>
|
|
2053
|
-
<button class="theme-btn" (click)="applyPkaTheme()" [class.active]="currentTheme === 'pka'">
|
|
2054
|
-
PKA
|
|
2055
|
-
</button>
|
|
2056
|
-
<button class="theme-btn" (click)="applyClaveTheme()" [class.active]="currentTheme === 'clave'">
|
|
2057
|
-
Clave
|
|
2058
|
-
</button>
|
|
2059
|
-
</div>
|
|
2060
|
-
</div>
|
|
2067
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobilePageMainComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
2068
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: DsMobilePageMainComponent, isStandalone: true, selector: "ds-mobile-page-main", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, headerTitle: { classPropertyName: "headerTitle", publicName: "headerTitle", isSignal: true, isRequired: false, transformFunction: null }, headerSubtitle: { classPropertyName: "headerSubtitle", publicName: "headerSubtitle", isSignal: true, isRequired: false, transformFunction: null }, avatarType: { classPropertyName: "avatarType", publicName: "avatarType", isSignal: true, isRequired: false, transformFunction: null }, avatarInitials: { classPropertyName: "avatarInitials", publicName: "avatarInitials", isSignal: true, isRequired: false, transformFunction: null }, avatarSrc: { classPropertyName: "avatarSrc", publicName: "avatarSrc", isSignal: true, isRequired: false, transformFunction: null }, avatarIconName: { classPropertyName: "avatarIconName", publicName: "avatarIconName", isSignal: true, isRequired: false, transformFunction: null }, showRefresh: { classPropertyName: "showRefresh", publicName: "showRefresh", isSignal: true, isRequired: false, transformFunction: null }, showCondensedHeader: { classPropertyName: "showCondensedHeader", publicName: "showCondensedHeader", isSignal: true, isRequired: false, transformFunction: null }, scrollThreshold: { classPropertyName: "scrollThreshold", publicName: "scrollThreshold", isSignal: true, isRequired: false, transformFunction: null }, headerFadeDistance: { classPropertyName: "headerFadeDistance", publicName: "headerFadeDistance", isSignal: true, isRequired: false, transformFunction: null }, profileMenuItems: { classPropertyName: "profileMenuItems", publicName: "profileMenuItems", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { avatarClick: "avatarClick", profileActionSelected: "profileActionSelected", refresh: "refresh", scroll: "scroll" }, viewQueries: [{ propertyName: "ionContent", first: true, predicate: IonContent, descendants: true }], usesInheritance: true, ngImport: i0, template: `
|
|
2069
|
+
<!-- Fixed header at top -->
|
|
2070
|
+
<ion-header>
|
|
2071
|
+
<ion-toolbar>
|
|
2072
|
+
<div class="header-home">
|
|
2073
|
+
<!-- Whitelabel Logomark -->
|
|
2074
|
+
<ds-logo variant="mark" size="lg" />
|
|
2061
2075
|
|
|
2062
|
-
<!--
|
|
2063
|
-
<
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2076
|
+
<!-- Title - fades in on scroll -->
|
|
2077
|
+
<ion-title class="header-home__title">{{ title() }}</ion-title>
|
|
2078
|
+
|
|
2079
|
+
<!-- Avatar -->
|
|
2080
|
+
<div class="header-home__actions">
|
|
2081
|
+
<ds-avatar
|
|
2082
|
+
[size]="'md'"
|
|
2083
|
+
[type]="avatarType()"
|
|
2084
|
+
[initials]="avatarInitials()"
|
|
2085
|
+
[src]="avatarSrc()"
|
|
2086
|
+
[iconName]="avatarIconName()"
|
|
2087
|
+
(click)="handleAvatarClick()"
|
|
2088
|
+
style="cursor: pointer;"
|
|
2089
|
+
/>
|
|
2090
|
+
</div>
|
|
2091
|
+
</div>
|
|
2092
|
+
</ion-toolbar>
|
|
2093
|
+
</ion-header>
|
|
2094
|
+
|
|
2095
|
+
<!-- Content with expandable header -->
|
|
2096
|
+
<ion-content [scrollEvents]="true" (ionScroll)="handleScroll($event)">
|
|
2097
|
+
<!-- Condensed header for Ionic scroll effects -->
|
|
2098
|
+
@if (showCondensedHeader()) {
|
|
2099
|
+
<ion-header collapse="condense">
|
|
2100
|
+
<ion-toolbar>
|
|
2101
|
+
<ion-title size="large">{{ title() }}</ion-title>
|
|
2102
|
+
</ion-toolbar>
|
|
2103
|
+
</ion-header>
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
<!-- Pull to refresh (only on native iOS/Android) -->
|
|
2107
|
+
@if (showRefresh() && isNativePlatform()) {
|
|
2108
|
+
<ion-refresher
|
|
2109
|
+
slot="fixed"
|
|
2110
|
+
(ionRefresh)="handleRefresh($event)"
|
|
2111
|
+
[pullFactor]="0.4"
|
|
2112
|
+
[pullMin]="80"
|
|
2113
|
+
[pullMax]="240"
|
|
2114
|
+
closeDuration="600ms">
|
|
2115
|
+
<ion-refresher-content
|
|
2116
|
+
pullingIcon="remixArrowDownS"
|
|
2117
|
+
refreshingSpinner="lines">
|
|
2118
|
+
</ion-refresher-content>
|
|
2119
|
+
</ion-refresher>
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
<!-- Expandable header section (purple background) -->
|
|
2123
|
+
<div class="header-expandable">
|
|
2124
|
+
<div class="header-expandable-inner">
|
|
2125
|
+
<div class="header-expandable__text">
|
|
2126
|
+
<h1 class="header-expandable__title">{{ headerTitle() || title() }}</h1>
|
|
2127
|
+
@if (headerSubtitle()) {
|
|
2128
|
+
<p class="header-expandable__subtitle">{{ headerSubtitle() }}</p>
|
|
2129
|
+
}
|
|
2084
2130
|
</div>
|
|
2085
2131
|
|
|
2086
|
-
<!--
|
|
2087
|
-
<
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
<div class="swatch-label">Primary Content</div>
|
|
2097
|
-
<div class="swatch-value">{{ whitelabelService.primaryContent() }}</div>
|
|
2098
|
-
</div>
|
|
2099
|
-
<div class="swatch swatch--secondary-surface">
|
|
2100
|
-
<div class="swatch-label">Secondary Surface</div>
|
|
2101
|
-
<div class="swatch-value">{{ whitelabelService.secondarySurface() }}</div>
|
|
2102
|
-
</div>
|
|
2103
|
-
<div class="swatch swatch--secondary-content">
|
|
2104
|
-
<div class="swatch-label">Secondary Content</div>
|
|
2105
|
-
<div class="swatch-value">{{ whitelabelService.secondaryContent() }}</div>
|
|
2106
|
-
</div>
|
|
2107
|
-
</div>
|
|
2108
|
-
|
|
2109
|
-
<div class="color-inputs">
|
|
2110
|
-
<div class="color-group-label">Primary</div>
|
|
2111
|
-
<div class="color-row">
|
|
2112
|
-
<label>Surface</label>
|
|
2113
|
-
<input
|
|
2114
|
-
type="color"
|
|
2115
|
-
[(ngModel)]="customPrimarySurface"
|
|
2116
|
-
(change)="applyCustomColors()"
|
|
2117
|
-
/>
|
|
2118
|
-
<input
|
|
2119
|
-
type="text"
|
|
2120
|
-
[(ngModel)]="customPrimarySurface"
|
|
2121
|
-
(change)="applyCustomColors()"
|
|
2122
|
-
/>
|
|
2123
|
-
</div>
|
|
2124
|
-
<div class="color-row">
|
|
2125
|
-
<label>Content</label>
|
|
2126
|
-
<input
|
|
2127
|
-
type="color"
|
|
2128
|
-
[(ngModel)]="customPrimaryContent"
|
|
2129
|
-
(change)="applyCustomColors()"
|
|
2130
|
-
/>
|
|
2131
|
-
<input
|
|
2132
|
-
type="text"
|
|
2133
|
-
[(ngModel)]="customPrimaryContent"
|
|
2134
|
-
(change)="applyCustomColors()"
|
|
2135
|
-
/>
|
|
2136
|
-
</div>
|
|
2137
|
-
|
|
2138
|
-
<div class="color-group-label">Secondary</div>
|
|
2139
|
-
<div class="color-row">
|
|
2140
|
-
<label>Surface</label>
|
|
2141
|
-
<input
|
|
2142
|
-
type="color"
|
|
2143
|
-
[(ngModel)]="customSecondarySurface"
|
|
2144
|
-
(change)="applyCustomColors()"
|
|
2145
|
-
/>
|
|
2146
|
-
<input
|
|
2147
|
-
type="text"
|
|
2148
|
-
[(ngModel)]="customSecondarySurface"
|
|
2149
|
-
(change)="applyCustomColors()"
|
|
2150
|
-
/>
|
|
2151
|
-
</div>
|
|
2152
|
-
<div class="color-row">
|
|
2153
|
-
<label>Content</label>
|
|
2154
|
-
<input
|
|
2155
|
-
type="color"
|
|
2156
|
-
[(ngModel)]="customSecondaryContent"
|
|
2157
|
-
(change)="applyCustomColors()"
|
|
2158
|
-
/>
|
|
2159
|
-
<input
|
|
2160
|
-
type="text"
|
|
2161
|
-
[(ngModel)]="customSecondaryContent"
|
|
2162
|
-
(change)="applyCustomColors()"
|
|
2163
|
-
/>
|
|
2164
|
-
</div>
|
|
2165
|
-
</div>
|
|
2166
|
-
</div>
|
|
2167
|
-
</div>
|
|
2132
|
+
<!-- Slot for custom header content (e.g., property tiles) -->
|
|
2133
|
+
<ng-content select="[header-content]"></ng-content>
|
|
2134
|
+
</div>
|
|
2135
|
+
</div>
|
|
2136
|
+
|
|
2137
|
+
<!-- Content wrapper -->
|
|
2138
|
+
<div class="content-wrapper">
|
|
2139
|
+
<div class="content-inner">
|
|
2140
|
+
<!-- Main page content -->
|
|
2141
|
+
<ng-content></ng-content>
|
|
2168
2142
|
</div>
|
|
2143
|
+
</div>
|
|
2169
2144
|
</ion-content>
|
|
2170
|
-
`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100
|
|
2145
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;align-items:center;height:100%}:host ion-header{background:var(--color-brand-secondary);box-shadow:none;height:72px;min-height:72px;margin-top:var(--app-header-top-offset)}ion-header ion-toolbar{--background: var(--color-brand-secondary);--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){ion-header{display:none;height:auto}}.header-home{display:flex;align-items:center;justify-content:space-between;padding:0 20px;background:var(--color-brand-secondary);height:72px}.header-home__title{position:absolute;left:50%;transform:translate(-50%) translateY(-100%);font-size:var(--font-size-base);font-weight:600;color:#fff;opacity:0;transition:transform .6s ease,opacity .6s ease;margin:0;padding:0;--color: white}.header-scrolled .header-home__title{opacity:1;transform:translate(-50%) translateY(0)}.header-home__actions{display:flex;align-items:center;gap:8px}.header-home__actions ds-avatar{cursor:pointer;-webkit-tap-highlight-color:transparent}.logomark{height:28px;width:auto;flex-shrink:0}@media (min-width: 768px){.header-home{padding:16px 24px}.logomark{height:32px}.header-home__title{display:none}}ion-content{--background: var(--color-brand-secondary);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;border-radius:24px;overflow:hidden}ion-content::part(scroll){display:flex;flex-direction:column}.plt-ios ion-content{--background: var(--color-background-neutral-primary)}@media (min-width: 768px){ion-content{border-radius:24px 24px 0 0}}ion-content::part(scroll){-webkit-overflow-scrolling:touch;display:flex;flex-direction:column}ion-header[collapse=condense]{display:none}@media (min-width: 768px){ion-header[collapse=condense]{display:none}}ion-refresher{z-index:0}ion-refresher-content{--color: white}.header-expandable{background:var(--color-brand-secondary);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}.header-expandable-inner{display:flex;flex-direction:column;gap:20px;max-width:640px;margin:0 auto}.header-expandable__text{margin-bottom:0}.header-expandable__title{font-size:var(--font-size-2xl);font-weight:600;color:var(--header-content-color, white);margin:0}.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){.header-expandable{padding:48px var(--content-padding-md)}.header-expandable__title{font-size:var(--font-size-3xl)}.header-expandable__subtitle{font-size:var(--font-size-base)}}@media (min-width: 992px){.header-expandable{padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){.header-expandable{padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.header-expandable{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.header-expandable{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}.content-wrapper{position:relative;z-index:20;padding:0;flex:1;display:flex;flex-direction:column}@media (min-width: 768px){.content-wrapper{width:100%}}.content-inner{background:var(--color-background-neutral-primary);border-radius:24px 24px 0 0;transform:translateZ(0);will-change:transform;isolation:isolate;box-shadow:0 200vh 0 0 var(--color-background-neutral-primary);flex:1;padding:24px 20px 32px;padding-bottom:calc(var(--mobile-content-spacing) + var(--mobile-tab-bar-height) + env(safe-area-inset-bottom,0px))}@media (min-width: 768px){.content-inner{border-radius:16px 16px 0 0;padding:32px var(--content-padding-md)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}}@media (min-width: 992px){.content-inner{padding:32px var(--content-padding-lg)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2))}}@media (min-width: 1440px){.content-inner{padding:32px var(--content-padding-xl)!important;max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2))}}@media (min-width: 1768px){.content-inner{padding:32px var(--content-padding-2xl)!important}}@media (min-width: 1920px){.content-inner{padding:32px var(--content-padding-3xl)!important}}\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"] }] });
|
|
2171
2146
|
}
|
|
2172
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type:
|
|
2147
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobilePageMainComponent, decorators: [{
|
|
2173
2148
|
type: Component,
|
|
2174
|
-
args: [{ selector: 'ds-
|
|
2149
|
+
args: [{ selector: 'ds-mobile-page-main', standalone: true, imports: [
|
|
2175
2150
|
CommonModule,
|
|
2176
|
-
|
|
2151
|
+
IonHeader,
|
|
2152
|
+
IonToolbar,
|
|
2153
|
+
IonTitle,
|
|
2177
2154
|
IonContent,
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
<
|
|
2187
|
-
|
|
2188
|
-
variant="
|
|
2189
|
-
size="lg"
|
|
2190
|
-
(click)="close()"
|
|
2191
|
-
class="close-button"
|
|
2192
|
-
aria-label="Close">
|
|
2193
|
-
</ds-icon-button>
|
|
2194
|
-
</div>
|
|
2195
|
-
</div>
|
|
2196
|
-
|
|
2197
|
-
<!-- Scrollable Content -->
|
|
2198
|
-
<ion-content [scrollY]="true" class="modal-content">
|
|
2199
|
-
<div class="demo-container">
|
|
2200
|
-
<!-- Theme Selection -->
|
|
2201
|
-
<div class="demo-section">
|
|
2202
|
-
<h2>Theme</h2>
|
|
2203
|
-
<div class="theme-buttons">
|
|
2204
|
-
<button class="theme-btn" (click)="applyDefaultTheme()" [class.active]="currentTheme === 'default'">
|
|
2205
|
-
Propbinder
|
|
2206
|
-
</button>
|
|
2207
|
-
<button class="theme-btn" (click)="applyCejTheme()" [class.active]="currentTheme === 'cej'">
|
|
2208
|
-
CEJ
|
|
2209
|
-
</button>
|
|
2210
|
-
<button class="theme-btn" (click)="applyPkaTheme()" [class.active]="currentTheme === 'pka'">
|
|
2211
|
-
PKA
|
|
2212
|
-
</button>
|
|
2213
|
-
<button class="theme-btn" (click)="applyClaveTheme()" [class.active]="currentTheme === 'clave'">
|
|
2214
|
-
Clave
|
|
2215
|
-
</button>
|
|
2216
|
-
</div>
|
|
2217
|
-
</div>
|
|
2155
|
+
IonRefresher,
|
|
2156
|
+
IonRefresherContent,
|
|
2157
|
+
DsAvatarComponent,
|
|
2158
|
+
DsLogoComponent
|
|
2159
|
+
], template: `
|
|
2160
|
+
<!-- Fixed header at top -->
|
|
2161
|
+
<ion-header>
|
|
2162
|
+
<ion-toolbar>
|
|
2163
|
+
<div class="header-home">
|
|
2164
|
+
<!-- Whitelabel Logomark -->
|
|
2165
|
+
<ds-logo variant="mark" size="lg" />
|
|
2218
2166
|
|
|
2219
|
-
<!--
|
|
2220
|
-
<
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2167
|
+
<!-- Title - fades in on scroll -->
|
|
2168
|
+
<ion-title class="header-home__title">{{ title() }}</ion-title>
|
|
2169
|
+
|
|
2170
|
+
<!-- Avatar -->
|
|
2171
|
+
<div class="header-home__actions">
|
|
2172
|
+
<ds-avatar
|
|
2173
|
+
[size]="'md'"
|
|
2174
|
+
[type]="avatarType()"
|
|
2175
|
+
[initials]="avatarInitials()"
|
|
2176
|
+
[src]="avatarSrc()"
|
|
2177
|
+
[iconName]="avatarIconName()"
|
|
2178
|
+
(click)="handleAvatarClick()"
|
|
2179
|
+
style="cursor: pointer;"
|
|
2180
|
+
/>
|
|
2181
|
+
</div>
|
|
2182
|
+
</div>
|
|
2183
|
+
</ion-toolbar>
|
|
2184
|
+
</ion-header>
|
|
2185
|
+
|
|
2186
|
+
<!-- Content with expandable header -->
|
|
2187
|
+
<ion-content [scrollEvents]="true" (ionScroll)="handleScroll($event)">
|
|
2188
|
+
<!-- Condensed header for Ionic scroll effects -->
|
|
2189
|
+
@if (showCondensedHeader()) {
|
|
2190
|
+
<ion-header collapse="condense">
|
|
2191
|
+
<ion-toolbar>
|
|
2192
|
+
<ion-title size="large">{{ title() }}</ion-title>
|
|
2193
|
+
</ion-toolbar>
|
|
2194
|
+
</ion-header>
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
<!-- Pull to refresh (only on native iOS/Android) -->
|
|
2198
|
+
@if (showRefresh() && isNativePlatform()) {
|
|
2199
|
+
<ion-refresher
|
|
2200
|
+
slot="fixed"
|
|
2201
|
+
(ionRefresh)="handleRefresh($event)"
|
|
2202
|
+
[pullFactor]="0.4"
|
|
2203
|
+
[pullMin]="80"
|
|
2204
|
+
[pullMax]="240"
|
|
2205
|
+
closeDuration="600ms">
|
|
2206
|
+
<ion-refresher-content
|
|
2207
|
+
pullingIcon="remixArrowDownS"
|
|
2208
|
+
refreshingSpinner="lines">
|
|
2209
|
+
</ion-refresher-content>
|
|
2210
|
+
</ion-refresher>
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
<!-- Expandable header section (purple background) -->
|
|
2214
|
+
<div class="header-expandable">
|
|
2215
|
+
<div class="header-expandable-inner">
|
|
2216
|
+
<div class="header-expandable__text">
|
|
2217
|
+
<h1 class="header-expandable__title">{{ headerTitle() || title() }}</h1>
|
|
2218
|
+
@if (headerSubtitle()) {
|
|
2219
|
+
<p class="header-expandable__subtitle">{{ headerSubtitle() }}</p>
|
|
2220
|
+
}
|
|
2241
2221
|
</div>
|
|
2242
2222
|
|
|
2243
|
-
<!--
|
|
2244
|
-
<
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
<div class="swatch-label">Primary Content</div>
|
|
2254
|
-
<div class="swatch-value">{{ whitelabelService.primaryContent() }}</div>
|
|
2255
|
-
</div>
|
|
2256
|
-
<div class="swatch swatch--secondary-surface">
|
|
2257
|
-
<div class="swatch-label">Secondary Surface</div>
|
|
2258
|
-
<div class="swatch-value">{{ whitelabelService.secondarySurface() }}</div>
|
|
2259
|
-
</div>
|
|
2260
|
-
<div class="swatch swatch--secondary-content">
|
|
2261
|
-
<div class="swatch-label">Secondary Content</div>
|
|
2262
|
-
<div class="swatch-value">{{ whitelabelService.secondaryContent() }}</div>
|
|
2263
|
-
</div>
|
|
2264
|
-
</div>
|
|
2265
|
-
|
|
2266
|
-
<div class="color-inputs">
|
|
2267
|
-
<div class="color-group-label">Primary</div>
|
|
2268
|
-
<div class="color-row">
|
|
2269
|
-
<label>Surface</label>
|
|
2270
|
-
<input
|
|
2271
|
-
type="color"
|
|
2272
|
-
[(ngModel)]="customPrimarySurface"
|
|
2273
|
-
(change)="applyCustomColors()"
|
|
2274
|
-
/>
|
|
2275
|
-
<input
|
|
2276
|
-
type="text"
|
|
2277
|
-
[(ngModel)]="customPrimarySurface"
|
|
2278
|
-
(change)="applyCustomColors()"
|
|
2279
|
-
/>
|
|
2280
|
-
</div>
|
|
2281
|
-
<div class="color-row">
|
|
2282
|
-
<label>Content</label>
|
|
2283
|
-
<input
|
|
2284
|
-
type="color"
|
|
2285
|
-
[(ngModel)]="customPrimaryContent"
|
|
2286
|
-
(change)="applyCustomColors()"
|
|
2287
|
-
/>
|
|
2288
|
-
<input
|
|
2289
|
-
type="text"
|
|
2290
|
-
[(ngModel)]="customPrimaryContent"
|
|
2291
|
-
(change)="applyCustomColors()"
|
|
2292
|
-
/>
|
|
2293
|
-
</div>
|
|
2294
|
-
|
|
2295
|
-
<div class="color-group-label">Secondary</div>
|
|
2296
|
-
<div class="color-row">
|
|
2297
|
-
<label>Surface</label>
|
|
2298
|
-
<input
|
|
2299
|
-
type="color"
|
|
2300
|
-
[(ngModel)]="customSecondarySurface"
|
|
2301
|
-
(change)="applyCustomColors()"
|
|
2302
|
-
/>
|
|
2303
|
-
<input
|
|
2304
|
-
type="text"
|
|
2305
|
-
[(ngModel)]="customSecondarySurface"
|
|
2306
|
-
(change)="applyCustomColors()"
|
|
2307
|
-
/>
|
|
2308
|
-
</div>
|
|
2309
|
-
<div class="color-row">
|
|
2310
|
-
<label>Content</label>
|
|
2311
|
-
<input
|
|
2312
|
-
type="color"
|
|
2313
|
-
[(ngModel)]="customSecondaryContent"
|
|
2314
|
-
(change)="applyCustomColors()"
|
|
2315
|
-
/>
|
|
2316
|
-
<input
|
|
2317
|
-
type="text"
|
|
2318
|
-
[(ngModel)]="customSecondaryContent"
|
|
2319
|
-
(change)="applyCustomColors()"
|
|
2320
|
-
/>
|
|
2321
|
-
</div>
|
|
2322
|
-
</div>
|
|
2323
|
-
</div>
|
|
2324
|
-
</div>
|
|
2223
|
+
<!-- Slot for custom header content (e.g., property tiles) -->
|
|
2224
|
+
<ng-content select="[header-content]"></ng-content>
|
|
2225
|
+
</div>
|
|
2226
|
+
</div>
|
|
2227
|
+
|
|
2228
|
+
<!-- Content wrapper -->
|
|
2229
|
+
<div class="content-wrapper">
|
|
2230
|
+
<div class="content-inner">
|
|
2231
|
+
<!-- Main page content -->
|
|
2232
|
+
<ng-content></ng-content>
|
|
2325
2233
|
</div>
|
|
2234
|
+
</div>
|
|
2326
2235
|
</ion-content>
|
|
2327
|
-
`, styles: [":host{display:flex;flex-direction:column;height:100
|
|
2328
|
-
}] }
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
*
|
|
2333
|
-
* Service for displaying the whitelabel demo in a full-screen modal.
|
|
2334
|
-
* Built on Ionic's modal system with native gestures and animations.
|
|
2335
|
-
*
|
|
2336
|
-
* @example
|
|
2337
|
-
* ```typescript
|
|
2338
|
-
* constructor(private whitelabelModal: WhitelabelDemoModalService) {}
|
|
2339
|
-
*
|
|
2340
|
-
* async openDemo() {
|
|
2341
|
-
* await this.whitelabelModal.open();
|
|
2342
|
-
* }
|
|
2343
|
-
* ```
|
|
2344
|
-
*/
|
|
2345
|
-
class WhitelabelDemoModalService {
|
|
2346
|
-
modalController;
|
|
2347
|
-
constructor(modalController) {
|
|
2348
|
-
this.modalController = modalController;
|
|
2349
|
-
}
|
|
2350
|
-
/**
|
|
2351
|
-
* Open the whitelabel demo modal
|
|
2352
|
-
*
|
|
2353
|
-
* @returns Promise that resolves when the modal is presented
|
|
2354
|
-
*/
|
|
2355
|
-
async open() {
|
|
2356
|
-
try {
|
|
2357
|
-
console.log('[WhitelabelDemoModal] Opening...');
|
|
2358
|
-
const modal = await this.modalController.create({
|
|
2359
|
-
component: WhitelabelDemoModalComponent,
|
|
2360
|
-
cssClass: 'ds-whitelabel-demo-modal',
|
|
2361
|
-
mode: 'ios',
|
|
2362
|
-
presentingElement: document.querySelector('ion-router-outlet') || undefined,
|
|
2363
|
-
backdropDismiss: true,
|
|
2364
|
-
showBackdrop: true,
|
|
2365
|
-
animated: true,
|
|
2366
|
-
keyboardClose: true
|
|
2367
|
-
});
|
|
2368
|
-
console.log('[WhitelabelDemoModal] Modal created, presenting...');
|
|
2369
|
-
await modal.present();
|
|
2370
|
-
console.log('[WhitelabelDemoModal] Modal presented');
|
|
2371
|
-
}
|
|
2372
|
-
catch (error) {
|
|
2373
|
-
console.error('[WhitelabelDemoModal] Error opening modal:', error);
|
|
2374
|
-
throw error;
|
|
2375
|
-
}
|
|
2376
|
-
}
|
|
2377
|
-
/**
|
|
2378
|
-
* Close the currently open whitelabel demo modal
|
|
2379
|
-
*
|
|
2380
|
-
* @param data Optional data to pass back when dismissing
|
|
2381
|
-
* @returns Promise that resolves when the modal is dismissed
|
|
2382
|
-
*/
|
|
2383
|
-
async close(data) {
|
|
2384
|
-
return this.modalController.dismiss(data);
|
|
2385
|
-
}
|
|
2386
|
-
/**
|
|
2387
|
-
* Get the top-most modal if one exists
|
|
2388
|
-
*
|
|
2389
|
-
* @returns Promise that resolves to the modal element or undefined
|
|
2390
|
-
*/
|
|
2391
|
-
async getTop() {
|
|
2392
|
-
return this.modalController.getTop();
|
|
2393
|
-
}
|
|
2394
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoModalService, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2395
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoModalService, providedIn: 'root' });
|
|
2396
|
-
}
|
|
2397
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoModalService, decorators: [{
|
|
2398
|
-
type: Injectable,
|
|
2399
|
-
args: [{
|
|
2400
|
-
providedIn: 'root'
|
|
2401
|
-
}]
|
|
2402
|
-
}], ctorParameters: () => [{ type: i1.ModalController }] });
|
|
2236
|
+
`, styles: [":host{display:flex;flex-direction:column;align-items:center;height:100%}:host ion-header{background:var(--color-brand-secondary);box-shadow:none;height:72px;min-height:72px;margin-top:var(--app-header-top-offset)}ion-header ion-toolbar{--background: var(--color-brand-secondary);--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){ion-header{display:none;height:auto}}.header-home{display:flex;align-items:center;justify-content:space-between;padding:0 20px;background:var(--color-brand-secondary);height:72px}.header-home__title{position:absolute;left:50%;transform:translate(-50%) translateY(-100%);font-size:var(--font-size-base);font-weight:600;color:#fff;opacity:0;transition:transform .6s ease,opacity .6s ease;margin:0;padding:0;--color: white}.header-scrolled .header-home__title{opacity:1;transform:translate(-50%) translateY(0)}.header-home__actions{display:flex;align-items:center;gap:8px}.header-home__actions ds-avatar{cursor:pointer;-webkit-tap-highlight-color:transparent}.logomark{height:28px;width:auto;flex-shrink:0}@media (min-width: 768px){.header-home{padding:16px 24px}.logomark{height:32px}.header-home__title{display:none}}ion-content{--background: var(--color-brand-secondary);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;border-radius:24px;overflow:hidden}ion-content::part(scroll){display:flex;flex-direction:column}.plt-ios ion-content{--background: var(--color-background-neutral-primary)}@media (min-width: 768px){ion-content{border-radius:24px 24px 0 0}}ion-content::part(scroll){-webkit-overflow-scrolling:touch;display:flex;flex-direction:column}ion-header[collapse=condense]{display:none}@media (min-width: 768px){ion-header[collapse=condense]{display:none}}ion-refresher{z-index:0}ion-refresher-content{--color: white}.header-expandable{background:var(--color-brand-secondary);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}.header-expandable-inner{display:flex;flex-direction:column;gap:20px;max-width:640px;margin:0 auto}.header-expandable__text{margin-bottom:0}.header-expandable__title{font-size:var(--font-size-2xl);font-weight:600;color:var(--header-content-color, white);margin:0}.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){.header-expandable{padding:48px var(--content-padding-md)}.header-expandable__title{font-size:var(--font-size-3xl)}.header-expandable__subtitle{font-size:var(--font-size-base)}}@media (min-width: 992px){.header-expandable{padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){.header-expandable{padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.header-expandable{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.header-expandable{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}.content-wrapper{position:relative;z-index:20;padding:0;flex:1;display:flex;flex-direction:column}@media (min-width: 768px){.content-wrapper{width:100%}}.content-inner{background:var(--color-background-neutral-primary);border-radius:24px 24px 0 0;transform:translateZ(0);will-change:transform;isolation:isolate;box-shadow:0 200vh 0 0 var(--color-background-neutral-primary);flex:1;padding:24px 20px 32px;padding-bottom:calc(var(--mobile-content-spacing) + var(--mobile-tab-bar-height) + env(safe-area-inset-bottom,0px))}@media (min-width: 768px){.content-inner{border-radius:16px 16px 0 0;padding:32px var(--content-padding-md)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}}@media (min-width: 992px){.content-inner{padding:32px var(--content-padding-lg)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2))}}@media (min-width: 1440px){.content-inner{padding:32px var(--content-padding-xl)!important;max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2))}}@media (min-width: 1768px){.content-inner{padding:32px var(--content-padding-2xl)!important}}@media (min-width: 1920px){.content-inner{padding:32px var(--content-padding-3xl)!important}}\n"] }]
|
|
2237
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { ionContent: [{
|
|
2238
|
+
type: ViewChild,
|
|
2239
|
+
args: [IonContent]
|
|
2240
|
+
}], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], headerTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerTitle", required: false }] }], headerSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerSubtitle", required: false }] }], avatarType: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarType", required: false }] }], avatarInitials: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarInitials", required: false }] }], avatarSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarSrc", required: false }] }], avatarIconName: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarIconName", required: false }] }], showRefresh: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRefresh", required: false }] }], showCondensedHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCondensedHeader", required: false }] }], scrollThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollThreshold", required: false }] }], headerFadeDistance: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerFadeDistance", required: false }] }], profileMenuItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "profileMenuItems", required: false }] }], avatarClick: [{ type: i0.Output, args: ["avatarClick"] }], profileActionSelected: [{ type: i0.Output, args: ["profileActionSelected"] }], refresh: [{ type: i0.Output, args: ["refresh"] }], scroll: [{ type: i0.Output, args: ["scroll"] }] } });
|
|
2403
2241
|
|
|
2404
2242
|
/**
|
|
2405
|
-
*
|
|
2243
|
+
* DsMobilePageDetailsComponent
|
|
2406
2244
|
*
|
|
2407
|
-
* A
|
|
2408
|
-
* -
|
|
2409
|
-
* -
|
|
2410
|
-
* -
|
|
2411
|
-
* - Pull-to-refresh support
|
|
2412
|
-
* - Auto scroll title fade-in
|
|
2245
|
+
* A mobile page layout for detail/drill-down pages with:
|
|
2246
|
+
* - Back button header (mobile + desktop variants)
|
|
2247
|
+
* - White background content area
|
|
2248
|
+
* - Responsive padding
|
|
2413
2249
|
*
|
|
2414
2250
|
* @example
|
|
2415
2251
|
* ```html
|
|
2416
|
-
* <!-- Simple page -->
|
|
2417
|
-
* <ds-mobile-page-
|
|
2418
|
-
* title="
|
|
2419
|
-
*
|
|
2252
|
+
* <!-- Simple detail page -->
|
|
2253
|
+
* <ds-mobile-page-details
|
|
2254
|
+
* title="Property Details"
|
|
2255
|
+
* (back)="goBack()">
|
|
2420
2256
|
* <div class="page-content">
|
|
2421
2257
|
* <!-- Your content -->
|
|
2422
2258
|
* </div>
|
|
2423
|
-
* </ds-mobile-page-
|
|
2424
|
-
*
|
|
2425
|
-
* <!-- Page with custom header content -->
|
|
2426
|
-
* <ds-mobile-page-main
|
|
2427
|
-
* title="Home"
|
|
2428
|
-
* headerTitle="Welcome, Lars"
|
|
2429
|
-
* headerSubtitle="Your rental property at a glance."
|
|
2430
|
-
* [avatarInitials]="'L'">
|
|
2431
|
-
*
|
|
2432
|
-
* <div header-content class="property-tiles">
|
|
2433
|
-
* <!-- Custom header content like tiles -->
|
|
2434
|
-
* </div>
|
|
2259
|
+
* </ds-mobile-page-details>
|
|
2435
2260
|
*
|
|
2261
|
+
* <!-- With default back route -->
|
|
2262
|
+
* <ds-mobile-page-details
|
|
2263
|
+
* title="Invoice Details"
|
|
2264
|
+
* backRoute="/invoices">
|
|
2436
2265
|
* <div class="page-content">
|
|
2437
|
-
* <!--
|
|
2266
|
+
* <!-- Your content -->
|
|
2438
2267
|
* </div>
|
|
2439
|
-
* </ds-mobile-page-
|
|
2268
|
+
* </ds-mobile-page-details>
|
|
2440
2269
|
* ```
|
|
2441
2270
|
*/
|
|
2442
|
-
class
|
|
2271
|
+
class DsMobilePageDetailsComponent extends MobilePageBase {
|
|
2272
|
+
navCtrl;
|
|
2443
2273
|
elementRef;
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
modalController = inject(ModalController);
|
|
2448
|
-
router = inject(Router);
|
|
2449
|
-
whitelabelDemoModal = inject(WhitelabelDemoModalService);
|
|
2450
|
-
// Computed property to check if running on native platform
|
|
2451
|
-
isNativePlatform = computed(() => this.platform.is('ios') ||
|
|
2452
|
-
this.platform.is('android') ||
|
|
2453
|
-
this.platform.is('capacitor'), ...(ngDevMode ? [{ debugName: "isNativePlatform" }] : []));
|
|
2454
|
-
// Inputs - Title
|
|
2455
|
-
title = input.required(...(ngDevMode ? [{ debugName: "title" }] : [])); // For fixed header title
|
|
2456
|
-
headerTitle = input('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : [])); // Optional different title for expandable header
|
|
2457
|
-
headerSubtitle = input('', ...(ngDevMode ? [{ debugName: "headerSubtitle" }] : []));
|
|
2458
|
-
// Inputs - Avatar
|
|
2459
|
-
avatarType = input('initials', ...(ngDevMode ? [{ debugName: "avatarType" }] : []));
|
|
2460
|
-
avatarInitials = input('U', ...(ngDevMode ? [{ debugName: "avatarInitials" }] : []));
|
|
2461
|
-
avatarSrc = input('', ...(ngDevMode ? [{ debugName: "avatarSrc" }] : []));
|
|
2462
|
-
avatarIconName = input('remixUser3Line', ...(ngDevMode ? [{ debugName: "avatarIconName" }] : []));
|
|
2463
|
-
// Inputs - Features
|
|
2464
|
-
showRefresh = input(true, ...(ngDevMode ? [{ debugName: "showRefresh" }] : []));
|
|
2465
|
-
showCondensedHeader = input(true, ...(ngDevMode ? [{ debugName: "showCondensedHeader" }] : []));
|
|
2466
|
-
scrollThreshold = input(160, ...(ngDevMode ? [{ debugName: "scrollThreshold" }] : [])); // Pixels to scroll before title appears
|
|
2467
|
-
headerFadeDistance = input(150, ...(ngDevMode ? [{ debugName: "headerFadeDistance" }] : [])); // Distance over which header fades out
|
|
2274
|
+
// Inputs
|
|
2275
|
+
title = input.required(...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2276
|
+
backRoute = input('', ...(ngDevMode ? [{ debugName: "backRoute" }] : [])); // Optional default back route
|
|
2468
2277
|
// Outputs
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
scroll = output();
|
|
2472
|
-
constructor(elementRef) {
|
|
2278
|
+
back = output();
|
|
2279
|
+
constructor(navCtrl, elementRef) {
|
|
2473
2280
|
super();
|
|
2281
|
+
this.navCtrl = navCtrl;
|
|
2474
2282
|
this.elementRef = elementRef;
|
|
2475
2283
|
}
|
|
2476
|
-
ngAfterViewInit() {
|
|
2477
|
-
// Initial setup if needed
|
|
2478
|
-
}
|
|
2479
2284
|
/**
|
|
2480
|
-
* Handle
|
|
2285
|
+
* Handle back navigation
|
|
2286
|
+
*
|
|
2287
|
+
* By default, navigates using the provided backRoute or browser back.
|
|
2288
|
+
* Parent components can listen to the (back) event to override this behavior.
|
|
2289
|
+
*
|
|
2290
|
+
* @example
|
|
2291
|
+
* ```html
|
|
2292
|
+
* <!-- Default behavior: uses backRoute or browser back -->
|
|
2293
|
+
* <ds-mobile-page-details
|
|
2294
|
+
* title="Details"
|
|
2295
|
+
* backRoute="/home">
|
|
2296
|
+
* </ds-mobile-page-details>
|
|
2297
|
+
*
|
|
2298
|
+
* <!-- Custom behavior: parent handles navigation -->
|
|
2299
|
+
* <ds-mobile-page-details
|
|
2300
|
+
* title="Details"
|
|
2301
|
+
* (back)="customBackHandler()">
|
|
2302
|
+
* </ds-mobile-page-details>
|
|
2303
|
+
* ```
|
|
2481
2304
|
*/
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
{
|
|
2491
|
-
actions: [
|
|
2492
|
-
{
|
|
2493
|
-
action: 'profile',
|
|
2494
|
-
title: 'Min profil',
|
|
2495
|
-
icon: 'remixUser3Line',
|
|
2496
|
-
destructive: false
|
|
2497
|
-
},
|
|
2498
|
-
{
|
|
2499
|
-
action: 'settings',
|
|
2500
|
-
title: 'Indstillinger',
|
|
2501
|
-
icon: 'remixSettings3Line',
|
|
2502
|
-
destructive: false
|
|
2503
|
-
},
|
|
2504
|
-
{
|
|
2505
|
-
action: 'whitelabel-demo',
|
|
2506
|
-
title: 'Whitelabel Demo',
|
|
2507
|
-
icon: 'remixPaletteLine',
|
|
2508
|
-
destructive: false
|
|
2509
|
-
}
|
|
2510
|
-
]
|
|
2511
|
-
},
|
|
2512
|
-
{
|
|
2513
|
-
actions: [
|
|
2514
|
-
{
|
|
2515
|
-
action: 'logout',
|
|
2516
|
-
title: 'Log ud',
|
|
2517
|
-
icon: 'remixLogoutBoxLine',
|
|
2518
|
-
destructive: true
|
|
2519
|
-
}
|
|
2520
|
-
]
|
|
2521
|
-
}
|
|
2522
|
-
]
|
|
2523
|
-
},
|
|
2524
|
-
// Auto-height: no breakpoints, no handle
|
|
2525
|
-
cssClass: 'ds-bottom-sheet auto-height'
|
|
2526
|
-
});
|
|
2527
|
-
await sheet.present();
|
|
2528
|
-
const result = await sheet.onWillDismiss();
|
|
2529
|
-
if (result.data?.action) {
|
|
2530
|
-
console.log('Profile action selected:', result.data.action);
|
|
2531
|
-
switch (result.data.action) {
|
|
2532
|
-
case 'logout':
|
|
2533
|
-
console.log('Logging out...');
|
|
2534
|
-
// TODO: Implement logout logic
|
|
2535
|
-
break;
|
|
2536
|
-
case 'profile':
|
|
2537
|
-
console.log('Opening profile...');
|
|
2538
|
-
// TODO: Navigate to profile page
|
|
2539
|
-
break;
|
|
2540
|
-
case 'settings':
|
|
2541
|
-
console.log('Opening settings...');
|
|
2542
|
-
// TODO: Navigate to settings page
|
|
2543
|
-
break;
|
|
2544
|
-
case 'whitelabel-demo':
|
|
2545
|
-
console.log('Whitelabel demo selected');
|
|
2546
|
-
await this.whitelabelDemoModal.open();
|
|
2547
|
-
break;
|
|
2548
|
-
}
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
/**
|
|
2552
|
-
* Handle scroll events
|
|
2553
|
-
* - Shows title in fixed header when scrolled past threshold
|
|
2554
|
-
* - Fades out expandable header content based on scroll position
|
|
2555
|
-
* - Emits scroll event for custom handling
|
|
2556
|
-
*/
|
|
2557
|
-
handleScroll(event) {
|
|
2558
|
-
const scrollTop = event.detail.scrollTop;
|
|
2559
|
-
const header = this.elementRef.nativeElement.querySelector('ion-header:not([collapse])');
|
|
2560
|
-
const headerExpandable = this.elementRef.nativeElement.querySelector('.header-expandable');
|
|
2561
|
-
// Show title in fixed header when scrolled past threshold
|
|
2562
|
-
if (scrollTop > this.scrollThreshold()) {
|
|
2563
|
-
header?.classList.add('header-scrolled');
|
|
2305
|
+
handleBack() {
|
|
2306
|
+
// Add class to trigger reverse animation
|
|
2307
|
+
this.elementRef.nativeElement.classList.add('navigating-back');
|
|
2308
|
+
// Emit event for parent to optionally handle
|
|
2309
|
+
this.back.emit();
|
|
2310
|
+
// Default behavior: navigate using backRoute or browser back
|
|
2311
|
+
if (this.backRoute()) {
|
|
2312
|
+
this.navCtrl.navigateBack(this.backRoute());
|
|
2564
2313
|
}
|
|
2565
2314
|
else {
|
|
2566
|
-
|
|
2567
|
-
}
|
|
2568
|
-
// Fade out header-expandable content based on scroll
|
|
2569
|
-
if (headerExpandable) {
|
|
2570
|
-
const fadeDistance = this.headerFadeDistance();
|
|
2571
|
-
const fadeProgress = Math.min(scrollTop / fadeDistance, 1);
|
|
2572
|
-
// Calculate opacity (1 to 0)
|
|
2573
|
-
const opacity = 1 - fadeProgress;
|
|
2574
|
-
// Calculate transform (0px to -20px upward)
|
|
2575
|
-
const translateY = fadeProgress * -20;
|
|
2576
|
-
// Apply styles
|
|
2577
|
-
headerExpandable.style.opacity = opacity.toString();
|
|
2578
|
-
headerExpandable.style.transform = `translateY(${translateY}px)`;
|
|
2579
|
-
}
|
|
2580
|
-
this.scroll.emit(event);
|
|
2581
|
-
}
|
|
2582
|
-
/**
|
|
2583
|
-
* Handle pull-to-refresh
|
|
2584
|
-
* Emits refresh event - parent should call event.target.complete()
|
|
2585
|
-
*/
|
|
2586
|
-
async handleRefresh(event) {
|
|
2587
|
-
// Haptic feedback for pull-to-refresh
|
|
2588
|
-
try {
|
|
2589
|
-
await Haptics.impact({ style: ImpactStyle.Medium });
|
|
2590
|
-
}
|
|
2591
|
-
catch {
|
|
2592
|
-
// Fallback to Web Vibration API if Capacitor Haptics is not available
|
|
2593
|
-
if ('vibrate' in navigator) {
|
|
2594
|
-
navigator.vibrate(50);
|
|
2595
|
-
}
|
|
2315
|
+
this.navCtrl.back();
|
|
2596
2316
|
}
|
|
2597
|
-
this.refresh.emit(event);
|
|
2598
2317
|
}
|
|
2599
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type:
|
|
2600
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
2601
|
-
<!--
|
|
2318
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobilePageDetailsComponent, deps: [{ token: i1.NavController }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
2319
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.14", type: DsMobilePageDetailsComponent, isStandalone: true, selector: "ds-mobile-page-details", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, backRoute: { classPropertyName: "backRoute", publicName: "backRoute", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { back: "back" }, usesInheritance: true, ngImport: i0, template: `
|
|
2320
|
+
<!-- Mobile header - hidden on desktop -->
|
|
2602
2321
|
<ion-header>
|
|
2603
2322
|
<ion-toolbar>
|
|
2604
|
-
<div class="header-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
<ion-title class="header-home__title">{{ title() }}</ion-title>
|
|
2610
|
-
|
|
2611
|
-
<!-- Avatar -->
|
|
2612
|
-
<div class="header-home__actions">
|
|
2613
|
-
<ds-avatar
|
|
2614
|
-
[size]="'md'"
|
|
2615
|
-
[type]="avatarType()"
|
|
2616
|
-
[initials]="avatarInitials()"
|
|
2617
|
-
[src]="avatarSrc()"
|
|
2618
|
-
[iconName]="avatarIconName()"
|
|
2619
|
-
(click)="handleAvatarClick()"
|
|
2620
|
-
style="cursor: pointer;"
|
|
2621
|
-
/>
|
|
2622
|
-
</div>
|
|
2323
|
+
<div class="header-back">
|
|
2324
|
+
<button class="back-button" (click)="handleBack()" [attr.aria-label]="'Go back'">
|
|
2325
|
+
<ds-icon name="remixArrowLeftLine" size="24px" />
|
|
2326
|
+
</button>
|
|
2327
|
+
<h1 class="header-title">{{ title() }}</h1>
|
|
2623
2328
|
</div>
|
|
2624
2329
|
</ion-toolbar>
|
|
2625
2330
|
</ion-header>
|
|
2626
2331
|
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
</ion-toolbar>
|
|
2635
|
-
</ion-header>
|
|
2636
|
-
}
|
|
2637
|
-
|
|
2638
|
-
<!-- Pull to refresh (only on native iOS/Android) -->
|
|
2639
|
-
@if (showRefresh() && isNativePlatform()) {
|
|
2640
|
-
<ion-refresher
|
|
2641
|
-
slot="fixed"
|
|
2642
|
-
(ionRefresh)="handleRefresh($event)"
|
|
2643
|
-
[pullFactor]="0.4"
|
|
2644
|
-
[pullMin]="80"
|
|
2645
|
-
[pullMax]="240"
|
|
2646
|
-
closeDuration="600ms">
|
|
2647
|
-
<ion-refresher-content
|
|
2648
|
-
pullingIcon="remixArrowDownS"
|
|
2649
|
-
refreshingSpinner="lines">
|
|
2650
|
-
</ion-refresher-content>
|
|
2651
|
-
</ion-refresher>
|
|
2652
|
-
}
|
|
2653
|
-
|
|
2654
|
-
<!-- Expandable header section (purple background) -->
|
|
2655
|
-
<div class="header-expandable">
|
|
2656
|
-
<div class="header-expandable-inner">
|
|
2657
|
-
<div class="header-expandable__text">
|
|
2658
|
-
<h1 class="header-expandable__title">{{ headerTitle() || title() }}</h1>
|
|
2659
|
-
@if (headerSubtitle()) {
|
|
2660
|
-
<p class="header-expandable__subtitle">{{ headerSubtitle() }}</p>
|
|
2661
|
-
}
|
|
2662
|
-
</div>
|
|
2663
|
-
|
|
2664
|
-
<!-- Slot for custom header content (e.g., property tiles) -->
|
|
2665
|
-
<ng-content select="[header-content]"></ng-content>
|
|
2666
|
-
</div>
|
|
2332
|
+
<ion-content>
|
|
2333
|
+
<!-- Desktop header above content -->
|
|
2334
|
+
<div class="desktop-header">
|
|
2335
|
+
<button class="back-button" (click)="handleBack()" [attr.aria-label]="'Go back'">
|
|
2336
|
+
<ds-icon name="remixArrowLeftLine" size="24px" />
|
|
2337
|
+
</button>
|
|
2338
|
+
<h1>{{ title() }}</h1>
|
|
2667
2339
|
</div>
|
|
2668
2340
|
|
|
2669
|
-
<!-- Content
|
|
2670
|
-
<div class="content
|
|
2671
|
-
<
|
|
2672
|
-
<!-- Main page content -->
|
|
2673
|
-
<ng-content></ng-content>
|
|
2674
|
-
</div>
|
|
2341
|
+
<!-- Content area -->
|
|
2342
|
+
<div class="detail-content">
|
|
2343
|
+
<ng-content></ng-content>
|
|
2675
2344
|
</div>
|
|
2676
2345
|
</ion-content>
|
|
2677
|
-
`, isInline: true, styles: [":host{display:flex;flex-direction:column;
|
|
2346
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}ion-header{background:var(--color-brand-secondary);box-shadow:none;height:64px}ion-header ion-toolbar{--background: var(--color-brand-secondary);--border-width: 0;--box-shadow: none;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 64px;height:100%;min-height:64px;padding:0}ion-header ion-toolbar::part(native){height:100%;min-height:64px;padding:0}@media (min-width: 768px){ion-header{display:none}}.header-back{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:var(--color-brand-secondary);position:relative;height:100%;min-height:64px}.header-back .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#fff;transition:opacity var(--transition-duration-fast) var(--ease-smooth);z-index:10}.header-back .back-button:hover{opacity:.8}.header-back .back-button:active{opacity:.6}.header-back .header-title{position:absolute;left:50%;transform:translate(-50%);font-size:var(--font-size-base);font-weight:600;color:#fff;margin:0}.desktop-header{display:none}@media (min-width: 768px){.desktop-header{display:flex;align-items:center;gap:16px;padding:32px var(--content-padding-md) 24px var(--content-padding-md);max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}.desktop-header .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text-color-default-primary);transition:opacity var(--transition-duration-fast) var(--ease-smooth)}.desktop-header .back-button:hover{opacity:.8}.desktop-header .back-button:active{opacity:.6}.desktop-header h1{font-size:var(--font-size-2xl);font-weight:600;margin:0;color:var(--text-color-default-primary)}}@media (min-width: 992px){.desktop-header{max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){.desktop-header{max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2));padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.desktop-header{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.desktop-header{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-content{--background: var(--color-background-neutral-primary);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;overflow:hidden}@media (max-width: 767px){ion-content{border-radius:24px 24px 36px 36px;animation:bottomRadiusOut .6s ease .3s forwards}:host(.navigating-back) ion-content{border-radius:24px 24px 0 0;animation:bottomRadiusIn .8s cubic-bezier(.36,.66,.04,1) forwards!important}}@keyframes bottomRadiusOut{0%{border-radius:24px 24px 36px 36px}to{border-radius:24px 24px 0 0}}@keyframes bottomRadiusIn{0%{border-radius:24px 24px 0 0}to{border-radius:24px 24px 36px 36px}}@media (min-width: 768px){ion-content{border-radius:24px 24px 0 0;animation:none}}ion-content::part(scroll){-webkit-overflow-scrolling:touch;overscroll-behavior-y:none}.detail-content{padding:24px 20px 32px}@media (min-width: 768px){.detail-content{padding:32px var(--content-padding-md)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}}@media (min-width: 992px){.detail-content{padding:32px var(--content-padding-lg)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2))}}@media (min-width: 1440px){.detail-content{padding:32px var(--content-padding-xl)!important;max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2))}}@media (min-width: 1768px){.detail-content{padding:32px var(--content-padding-2xl)!important}}@media (min-width: 1920px){.detail-content{padding:32px var(--content-padding-3xl)!important}}\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: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }] });
|
|
2678
2347
|
}
|
|
2679
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type:
|
|
2348
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobilePageDetailsComponent, decorators: [{
|
|
2680
2349
|
type: Component,
|
|
2681
|
-
args: [{ selector: 'ds-mobile-page-
|
|
2350
|
+
args: [{ selector: 'ds-mobile-page-details', standalone: true, imports: [
|
|
2682
2351
|
CommonModule,
|
|
2683
2352
|
IonHeader,
|
|
2684
2353
|
IonToolbar,
|
|
2685
|
-
IonTitle,
|
|
2686
2354
|
IonContent,
|
|
2687
|
-
|
|
2688
|
-
IonRefresherContent,
|
|
2689
|
-
DsAvatarComponent,
|
|
2690
|
-
DsLogoComponent
|
|
2355
|
+
DsIconComponent
|
|
2691
2356
|
], template: `
|
|
2692
|
-
<!--
|
|
2357
|
+
<!-- Mobile header - hidden on desktop -->
|
|
2693
2358
|
<ion-header>
|
|
2694
2359
|
<ion-toolbar>
|
|
2695
|
-
<div class="header-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
<ion-title class="header-home__title">{{ title() }}</ion-title>
|
|
2701
|
-
|
|
2702
|
-
<!-- Avatar -->
|
|
2703
|
-
<div class="header-home__actions">
|
|
2704
|
-
<ds-avatar
|
|
2705
|
-
[size]="'md'"
|
|
2706
|
-
[type]="avatarType()"
|
|
2707
|
-
[initials]="avatarInitials()"
|
|
2708
|
-
[src]="avatarSrc()"
|
|
2709
|
-
[iconName]="avatarIconName()"
|
|
2710
|
-
(click)="handleAvatarClick()"
|
|
2711
|
-
style="cursor: pointer;"
|
|
2712
|
-
/>
|
|
2713
|
-
</div>
|
|
2360
|
+
<div class="header-back">
|
|
2361
|
+
<button class="back-button" (click)="handleBack()" [attr.aria-label]="'Go back'">
|
|
2362
|
+
<ds-icon name="remixArrowLeftLine" size="24px" />
|
|
2363
|
+
</button>
|
|
2364
|
+
<h1 class="header-title">{{ title() }}</h1>
|
|
2714
2365
|
</div>
|
|
2715
2366
|
</ion-toolbar>
|
|
2716
2367
|
</ion-header>
|
|
2717
2368
|
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
</ion-toolbar>
|
|
2726
|
-
</ion-header>
|
|
2727
|
-
}
|
|
2728
|
-
|
|
2729
|
-
<!-- Pull to refresh (only on native iOS/Android) -->
|
|
2730
|
-
@if (showRefresh() && isNativePlatform()) {
|
|
2731
|
-
<ion-refresher
|
|
2732
|
-
slot="fixed"
|
|
2733
|
-
(ionRefresh)="handleRefresh($event)"
|
|
2734
|
-
[pullFactor]="0.4"
|
|
2735
|
-
[pullMin]="80"
|
|
2736
|
-
[pullMax]="240"
|
|
2737
|
-
closeDuration="600ms">
|
|
2738
|
-
<ion-refresher-content
|
|
2739
|
-
pullingIcon="remixArrowDownS"
|
|
2740
|
-
refreshingSpinner="lines">
|
|
2741
|
-
</ion-refresher-content>
|
|
2742
|
-
</ion-refresher>
|
|
2743
|
-
}
|
|
2744
|
-
|
|
2745
|
-
<!-- Expandable header section (purple background) -->
|
|
2746
|
-
<div class="header-expandable">
|
|
2747
|
-
<div class="header-expandable-inner">
|
|
2748
|
-
<div class="header-expandable__text">
|
|
2749
|
-
<h1 class="header-expandable__title">{{ headerTitle() || title() }}</h1>
|
|
2750
|
-
@if (headerSubtitle()) {
|
|
2751
|
-
<p class="header-expandable__subtitle">{{ headerSubtitle() }}</p>
|
|
2752
|
-
}
|
|
2753
|
-
</div>
|
|
2754
|
-
|
|
2755
|
-
<!-- Slot for custom header content (e.g., property tiles) -->
|
|
2756
|
-
<ng-content select="[header-content]"></ng-content>
|
|
2757
|
-
</div>
|
|
2369
|
+
<ion-content>
|
|
2370
|
+
<!-- Desktop header above content -->
|
|
2371
|
+
<div class="desktop-header">
|
|
2372
|
+
<button class="back-button" (click)="handleBack()" [attr.aria-label]="'Go back'">
|
|
2373
|
+
<ds-icon name="remixArrowLeftLine" size="24px" />
|
|
2374
|
+
</button>
|
|
2375
|
+
<h1>{{ title() }}</h1>
|
|
2758
2376
|
</div>
|
|
2759
2377
|
|
|
2760
|
-
<!-- Content
|
|
2761
|
-
<div class="content
|
|
2762
|
-
<
|
|
2763
|
-
<!-- Main page content -->
|
|
2764
|
-
<ng-content></ng-content>
|
|
2765
|
-
</div>
|
|
2378
|
+
<!-- Content area -->
|
|
2379
|
+
<div class="detail-content">
|
|
2380
|
+
<ng-content></ng-content>
|
|
2766
2381
|
</div>
|
|
2767
2382
|
</ion-content>
|
|
2768
|
-
`, styles: [":host{display:flex;flex-direction:column;
|
|
2769
|
-
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: {
|
|
2770
|
-
type: ViewChild,
|
|
2771
|
-
args: [IonContent]
|
|
2772
|
-
}], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], headerTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerTitle", required: false }] }], headerSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerSubtitle", required: false }] }], avatarType: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarType", required: false }] }], avatarInitials: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarInitials", required: false }] }], avatarSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarSrc", required: false }] }], avatarIconName: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarIconName", required: false }] }], showRefresh: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRefresh", required: false }] }], showCondensedHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCondensedHeader", required: false }] }], scrollThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollThreshold", required: false }] }], headerFadeDistance: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerFadeDistance", required: false }] }], avatarClick: [{ type: i0.Output, args: ["avatarClick"] }], refresh: [{ type: i0.Output, args: ["refresh"] }], scroll: [{ type: i0.Output, args: ["scroll"] }] } });
|
|
2383
|
+
`, styles: [":host{display:flex;flex-direction:column;height:100%}ion-header{background:var(--color-brand-secondary);box-shadow:none;height:64px}ion-header ion-toolbar{--background: var(--color-brand-secondary);--border-width: 0;--box-shadow: none;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 64px;height:100%;min-height:64px;padding:0}ion-header ion-toolbar::part(native){height:100%;min-height:64px;padding:0}@media (min-width: 768px){ion-header{display:none}}.header-back{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:var(--color-brand-secondary);position:relative;height:100%;min-height:64px}.header-back .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#fff;transition:opacity var(--transition-duration-fast) var(--ease-smooth);z-index:10}.header-back .back-button:hover{opacity:.8}.header-back .back-button:active{opacity:.6}.header-back .header-title{position:absolute;left:50%;transform:translate(-50%);font-size:var(--font-size-base);font-weight:600;color:#fff;margin:0}.desktop-header{display:none}@media (min-width: 768px){.desktop-header{display:flex;align-items:center;gap:16px;padding:32px var(--content-padding-md) 24px var(--content-padding-md);max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}.desktop-header .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text-color-default-primary);transition:opacity var(--transition-duration-fast) var(--ease-smooth)}.desktop-header .back-button:hover{opacity:.8}.desktop-header .back-button:active{opacity:.6}.desktop-header h1{font-size:var(--font-size-2xl);font-weight:600;margin:0;color:var(--text-color-default-primary)}}@media (min-width: 992px){.desktop-header{max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){.desktop-header{max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2));padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.desktop-header{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.desktop-header{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-content{--background: var(--color-background-neutral-primary);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;overflow:hidden}@media (max-width: 767px){ion-content{border-radius:24px 24px 36px 36px;animation:bottomRadiusOut .6s ease .3s forwards}:host(.navigating-back) ion-content{border-radius:24px 24px 0 0;animation:bottomRadiusIn .8s cubic-bezier(.36,.66,.04,1) forwards!important}}@keyframes bottomRadiusOut{0%{border-radius:24px 24px 36px 36px}to{border-radius:24px 24px 0 0}}@keyframes bottomRadiusIn{0%{border-radius:24px 24px 0 0}to{border-radius:24px 24px 36px 36px}}@media (min-width: 768px){ion-content{border-radius:24px 24px 0 0;animation:none}}ion-content::part(scroll){-webkit-overflow-scrolling:touch;overscroll-behavior-y:none}.detail-content{padding:24px 20px 32px}@media (min-width: 768px){.detail-content{padding:32px var(--content-padding-md)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}}@media (min-width: 992px){.detail-content{padding:32px var(--content-padding-lg)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2))}}@media (min-width: 1440px){.detail-content{padding:32px var(--content-padding-xl)!important;max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2))}}@media (min-width: 1768px){.detail-content{padding:32px var(--content-padding-2xl)!important}}@media (min-width: 1920px){.detail-content{padding:32px var(--content-padding-3xl)!important}}\n"] }]
|
|
2384
|
+
}], ctorParameters: () => [{ type: i1.NavController }, { type: i0.ElementRef }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], backRoute: [{ type: i0.Input, args: [{ isSignal: true, alias: "backRoute", required: false }] }], back: [{ type: i0.Output, args: ["back"] }] } });
|
|
2773
2385
|
|
|
2774
2386
|
/**
|
|
2775
|
-
*
|
|
2776
|
-
*
|
|
2777
|
-
* A mobile page layout for detail/drill-down pages with:
|
|
2778
|
-
* - Back button header (mobile + desktop variants)
|
|
2779
|
-
* - White background content area
|
|
2780
|
-
* - Responsive padding
|
|
2781
|
-
*
|
|
2782
|
-
* @example
|
|
2783
|
-
* ```html
|
|
2784
|
-
* <!-- Simple detail page -->
|
|
2785
|
-
* <ds-mobile-page-details
|
|
2786
|
-
* title="Property Details"
|
|
2787
|
-
* (back)="goBack()">
|
|
2788
|
-
* <div class="page-content">
|
|
2789
|
-
* <!-- Your content -->
|
|
2790
|
-
* </div>
|
|
2791
|
-
* </ds-mobile-page-details>
|
|
2792
|
-
*
|
|
2793
|
-
* <!-- With default back route -->
|
|
2794
|
-
* <ds-mobile-page-details
|
|
2795
|
-
* title="Invoice Details"
|
|
2796
|
-
* backRoute="/invoices">
|
|
2797
|
-
* <div class="page-content">
|
|
2798
|
-
* <!-- Your content -->
|
|
2799
|
-
* </div>
|
|
2800
|
-
* </ds-mobile-page-details>
|
|
2801
|
-
* ```
|
|
2802
|
-
*/
|
|
2803
|
-
class DsMobilePageDetailsComponent extends MobilePageBase {
|
|
2804
|
-
navCtrl;
|
|
2805
|
-
elementRef;
|
|
2806
|
-
// Inputs
|
|
2807
|
-
title = input.required(...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2808
|
-
backRoute = input('', ...(ngDevMode ? [{ debugName: "backRoute" }] : [])); // Optional default back route
|
|
2809
|
-
// Outputs
|
|
2810
|
-
back = output();
|
|
2811
|
-
constructor(navCtrl, elementRef) {
|
|
2812
|
-
super();
|
|
2813
|
-
this.navCtrl = navCtrl;
|
|
2814
|
-
this.elementRef = elementRef;
|
|
2815
|
-
}
|
|
2816
|
-
/**
|
|
2817
|
-
* Handle back navigation
|
|
2818
|
-
*
|
|
2819
|
-
* By default, navigates using the provided backRoute or browser back.
|
|
2820
|
-
* Parent components can listen to the (back) event to override this behavior.
|
|
2821
|
-
*
|
|
2822
|
-
* @example
|
|
2823
|
-
* ```html
|
|
2824
|
-
* <!-- Default behavior: uses backRoute or browser back -->
|
|
2825
|
-
* <ds-mobile-page-details
|
|
2826
|
-
* title="Details"
|
|
2827
|
-
* backRoute="/home">
|
|
2828
|
-
* </ds-mobile-page-details>
|
|
2829
|
-
*
|
|
2830
|
-
* <!-- Custom behavior: parent handles navigation -->
|
|
2831
|
-
* <ds-mobile-page-details
|
|
2832
|
-
* title="Details"
|
|
2833
|
-
* (back)="customBackHandler()">
|
|
2834
|
-
* </ds-mobile-page-details>
|
|
2835
|
-
* ```
|
|
2836
|
-
*/
|
|
2837
|
-
handleBack() {
|
|
2838
|
-
// Add class to trigger reverse animation
|
|
2839
|
-
this.elementRef.nativeElement.classList.add('navigating-back');
|
|
2840
|
-
// Emit event for parent to optionally handle
|
|
2841
|
-
this.back.emit();
|
|
2842
|
-
// Default behavior: navigate using backRoute or browser back
|
|
2843
|
-
if (this.backRoute()) {
|
|
2844
|
-
this.navCtrl.navigateBack(this.backRoute());
|
|
2845
|
-
}
|
|
2846
|
-
else {
|
|
2847
|
-
this.navCtrl.back();
|
|
2848
|
-
}
|
|
2849
|
-
}
|
|
2850
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobilePageDetailsComponent, deps: [{ token: i1.NavController }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
2851
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.14", type: DsMobilePageDetailsComponent, isStandalone: true, selector: "ds-mobile-page-details", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, backRoute: { classPropertyName: "backRoute", publicName: "backRoute", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { back: "back" }, usesInheritance: true, ngImport: i0, template: `
|
|
2852
|
-
<!-- Mobile header - hidden on desktop -->
|
|
2853
|
-
<ion-header>
|
|
2854
|
-
<ion-toolbar>
|
|
2855
|
-
<div class="header-back">
|
|
2856
|
-
<button class="back-button" (click)="handleBack()" [attr.aria-label]="'Go back'">
|
|
2857
|
-
<ds-icon name="remixArrowLeftLine" size="24px" />
|
|
2858
|
-
</button>
|
|
2859
|
-
<h1 class="header-title">{{ title() }}</h1>
|
|
2860
|
-
</div>
|
|
2861
|
-
</ion-toolbar>
|
|
2862
|
-
</ion-header>
|
|
2863
|
-
|
|
2864
|
-
<ion-content>
|
|
2865
|
-
<!-- Desktop header above content -->
|
|
2866
|
-
<div class="desktop-header">
|
|
2867
|
-
<button class="back-button" (click)="handleBack()" [attr.aria-label]="'Go back'">
|
|
2868
|
-
<ds-icon name="remixArrowLeftLine" size="24px" />
|
|
2869
|
-
</button>
|
|
2870
|
-
<h1>{{ title() }}</h1>
|
|
2871
|
-
</div>
|
|
2872
|
-
|
|
2873
|
-
<!-- Content area -->
|
|
2874
|
-
<div class="detail-content">
|
|
2875
|
-
<ng-content></ng-content>
|
|
2876
|
-
</div>
|
|
2877
|
-
</ion-content>
|
|
2878
|
-
`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}ion-header{background:var(--color-brand-secondary);box-shadow:none;height:64px}ion-header ion-toolbar{--background: var(--color-brand-secondary);--border-width: 0;--box-shadow: none;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 64px;height:100%;min-height:64px;padding:0}ion-header ion-toolbar::part(native){height:100%;min-height:64px;padding:0}@media (min-width: 768px){ion-header{display:none}}.header-back{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:var(--color-brand-secondary);position:relative;height:100%;min-height:64px}.header-back .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#fff;transition:opacity var(--transition-duration-fast) var(--ease-smooth);z-index:10}.header-back .back-button:hover{opacity:.8}.header-back .back-button:active{opacity:.6}.header-back .header-title{position:absolute;left:50%;transform:translate(-50%);font-size:var(--font-size-base);font-weight:600;color:#fff;margin:0}.desktop-header{display:none}@media (min-width: 768px){.desktop-header{display:flex;align-items:center;gap:16px;padding:32px var(--content-padding-md) 24px var(--content-padding-md);max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}.desktop-header .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text-color-default-primary);transition:opacity var(--transition-duration-fast) var(--ease-smooth)}.desktop-header .back-button:hover{opacity:.8}.desktop-header .back-button:active{opacity:.6}.desktop-header h1{font-size:var(--font-size-2xl);font-weight:600;margin:0;color:var(--text-color-default-primary)}}@media (min-width: 992px){.desktop-header{max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){.desktop-header{max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2));padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.desktop-header{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.desktop-header{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-content{--background: var(--color-background-neutral-primary);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;overflow:hidden}@media (max-width: 767px){ion-content{border-radius:24px 24px 36px 36px;animation:bottomRadiusOut .6s ease .3s forwards}:host(.navigating-back) ion-content{border-radius:24px 24px 0 0;animation:bottomRadiusIn .8s cubic-bezier(.36,.66,.04,1) forwards!important}}@keyframes bottomRadiusOut{0%{border-radius:24px 24px 36px 36px}to{border-radius:24px 24px 0 0}}@keyframes bottomRadiusIn{0%{border-radius:24px 24px 0 0}to{border-radius:24px 24px 36px 36px}}@media (min-width: 768px){ion-content{border-radius:24px 24px 0 0;animation:none}}ion-content::part(scroll){-webkit-overflow-scrolling:touch;overscroll-behavior-y:none}.detail-content{padding:24px 20px 32px}@media (min-width: 768px){.detail-content{padding:32px var(--content-padding-md)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}}@media (min-width: 992px){.detail-content{padding:32px var(--content-padding-lg)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2))}}@media (min-width: 1440px){.detail-content{padding:32px var(--content-padding-xl)!important;max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2))}}@media (min-width: 1768px){.detail-content{padding:32px var(--content-padding-2xl)!important}}@media (min-width: 1920px){.detail-content{padding:32px var(--content-padding-3xl)!important}}\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: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }] });
|
|
2879
|
-
}
|
|
2880
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobilePageDetailsComponent, decorators: [{
|
|
2881
|
-
type: Component,
|
|
2882
|
-
args: [{ selector: 'ds-mobile-page-details', standalone: true, imports: [
|
|
2883
|
-
CommonModule,
|
|
2884
|
-
IonHeader,
|
|
2885
|
-
IonToolbar,
|
|
2886
|
-
IonContent,
|
|
2887
|
-
DsIconComponent
|
|
2888
|
-
], template: `
|
|
2889
|
-
<!-- Mobile header - hidden on desktop -->
|
|
2890
|
-
<ion-header>
|
|
2891
|
-
<ion-toolbar>
|
|
2892
|
-
<div class="header-back">
|
|
2893
|
-
<button class="back-button" (click)="handleBack()" [attr.aria-label]="'Go back'">
|
|
2894
|
-
<ds-icon name="remixArrowLeftLine" size="24px" />
|
|
2895
|
-
</button>
|
|
2896
|
-
<h1 class="header-title">{{ title() }}</h1>
|
|
2897
|
-
</div>
|
|
2898
|
-
</ion-toolbar>
|
|
2899
|
-
</ion-header>
|
|
2900
|
-
|
|
2901
|
-
<ion-content>
|
|
2902
|
-
<!-- Desktop header above content -->
|
|
2903
|
-
<div class="desktop-header">
|
|
2904
|
-
<button class="back-button" (click)="handleBack()" [attr.aria-label]="'Go back'">
|
|
2905
|
-
<ds-icon name="remixArrowLeftLine" size="24px" />
|
|
2906
|
-
</button>
|
|
2907
|
-
<h1>{{ title() }}</h1>
|
|
2908
|
-
</div>
|
|
2909
|
-
|
|
2910
|
-
<!-- Content area -->
|
|
2911
|
-
<div class="detail-content">
|
|
2912
|
-
<ng-content></ng-content>
|
|
2913
|
-
</div>
|
|
2914
|
-
</ion-content>
|
|
2915
|
-
`, styles: [":host{display:flex;flex-direction:column;height:100%}ion-header{background:var(--color-brand-secondary);box-shadow:none;height:64px}ion-header ion-toolbar{--background: var(--color-brand-secondary);--border-width: 0;--box-shadow: none;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 64px;height:100%;min-height:64px;padding:0}ion-header ion-toolbar::part(native){height:100%;min-height:64px;padding:0}@media (min-width: 768px){ion-header{display:none}}.header-back{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;background:var(--color-brand-secondary);position:relative;height:100%;min-height:64px}.header-back .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#fff;transition:opacity var(--transition-duration-fast) var(--ease-smooth);z-index:10}.header-back .back-button:hover{opacity:.8}.header-back .back-button:active{opacity:.6}.header-back .header-title{position:absolute;left:50%;transform:translate(-50%);font-size:var(--font-size-base);font-weight:600;color:#fff;margin:0}.desktop-header{display:none}@media (min-width: 768px){.desktop-header{display:flex;align-items:center;gap:16px;padding:32px var(--content-padding-md) 24px var(--content-padding-md);max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}.desktop-header .back-button{background:none;border:none;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text-color-default-primary);transition:opacity var(--transition-duration-fast) var(--ease-smooth)}.desktop-header .back-button:hover{opacity:.8}.desktop-header .back-button:active{opacity:.6}.desktop-header h1{font-size:var(--font-size-2xl);font-weight:600;margin:0;color:var(--text-color-default-primary)}}@media (min-width: 992px){.desktop-header{max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){.desktop-header{max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2));padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.desktop-header{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.desktop-header{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-content{--background: var(--color-background-neutral-primary);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;overflow:hidden}@media (max-width: 767px){ion-content{border-radius:24px 24px 36px 36px;animation:bottomRadiusOut .6s ease .3s forwards}:host(.navigating-back) ion-content{border-radius:24px 24px 0 0;animation:bottomRadiusIn .8s cubic-bezier(.36,.66,.04,1) forwards!important}}@keyframes bottomRadiusOut{0%{border-radius:24px 24px 36px 36px}to{border-radius:24px 24px 0 0}}@keyframes bottomRadiusIn{0%{border-radius:24px 24px 0 0}to{border-radius:24px 24px 36px 36px}}@media (min-width: 768px){ion-content{border-radius:24px 24px 0 0;animation:none}}ion-content::part(scroll){-webkit-overflow-scrolling:touch;overscroll-behavior-y:none}.detail-content{padding:24px 20px 32px}@media (min-width: 768px){.detail-content{padding:32px var(--content-padding-md)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));margin:0 auto;width:100%}}@media (min-width: 992px){.detail-content{padding:32px var(--content-padding-lg)!important;max-width:calc(var(--content-max-width-md) + (var(--content-padding-md) * 2))}}@media (min-width: 1440px){.detail-content{padding:32px var(--content-padding-xl)!important;max-width:calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2))}}@media (min-width: 1768px){.detail-content{padding:32px var(--content-padding-2xl)!important}}@media (min-width: 1920px){.detail-content{padding:32px var(--content-padding-3xl)!important}}\n"] }]
|
|
2916
|
-
}], ctorParameters: () => [{ type: i1.NavController }, { type: i0.ElementRef }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], backRoute: [{ type: i0.Input, args: [{ isSignal: true, alias: "backRoute", required: false }] }], back: [{ type: i0.Output, args: ["back"] }] } });
|
|
2917
|
-
|
|
2918
|
-
/**
|
|
2919
|
-
* DsMobileContentComponent
|
|
2387
|
+
* DsMobileContentComponent
|
|
2920
2388
|
*
|
|
2921
2389
|
* Main content container for mobile pages with flexible layout options.
|
|
2922
2390
|
* Provides consistent spacing and layout patterns.
|
|
@@ -4720,6 +4188,7 @@ class DsMobileTabBarComponent {
|
|
|
4720
4188
|
routerSubscription;
|
|
4721
4189
|
router;
|
|
4722
4190
|
modalController = inject(ModalController);
|
|
4191
|
+
userService = inject(UserService);
|
|
4723
4192
|
constructor(elementRef) {
|
|
4724
4193
|
this.elementRef = elementRef;
|
|
4725
4194
|
// Inject Router optionally
|
|
@@ -5168,15 +4637,17 @@ class DsMobileTabBarComponent {
|
|
|
5168
4637
|
async handleAvatarClick() {
|
|
5169
4638
|
// Emit the basic click event (for backwards compatibility)
|
|
5170
4639
|
this.avatarClick.emit();
|
|
4640
|
+
// Use input if provided, otherwise fall back to service
|
|
4641
|
+
const menuItems = this.profileMenuItems || this.userService.profileMenuItems();
|
|
5171
4642
|
// If no menu items configured, just emit and return
|
|
5172
|
-
if (!
|
|
4643
|
+
if (!menuItems || menuItems.length === 0) {
|
|
5173
4644
|
return;
|
|
5174
4645
|
}
|
|
5175
4646
|
// Open the bottom sheet with configured menu items
|
|
5176
4647
|
const sheet = await this.modalController.create({
|
|
5177
4648
|
component: DsMobileActionsBottomSheetComponent,
|
|
5178
4649
|
componentProps: {
|
|
5179
|
-
customActionGroups:
|
|
4650
|
+
customActionGroups: menuItems
|
|
5180
4651
|
},
|
|
5181
4652
|
// Auto-height: no breakpoints, no handle
|
|
5182
4653
|
cssClass: 'ds-bottom-sheet auto-height'
|
|
@@ -9774,40 +9245,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
9774
9245
|
|
|
9775
9246
|
// Mobile Page Components
|
|
9776
9247
|
|
|
9777
|
-
/**
|
|
9778
|
-
* User service for managing current user data globally
|
|
9779
|
-
*/
|
|
9780
|
-
class UserService {
|
|
9781
|
-
// User avatar configuration
|
|
9782
|
-
_avatarInitials = signal('LM', ...(ngDevMode ? [{ debugName: "_avatarInitials" }] : []));
|
|
9783
|
-
_avatarType = signal('initials', ...(ngDevMode ? [{ debugName: "_avatarType" }] : []));
|
|
9784
|
-
_avatarSrc = signal('', ...(ngDevMode ? [{ debugName: "_avatarSrc" }] : []));
|
|
9785
|
-
// Readonly computed values
|
|
9786
|
-
avatarInitials = this._avatarInitials.asReadonly();
|
|
9787
|
-
avatarType = this._avatarType.asReadonly();
|
|
9788
|
-
avatarSrc = this._avatarSrc.asReadonly();
|
|
9789
|
-
/**
|
|
9790
|
-
* Update avatar configuration
|
|
9791
|
-
*/
|
|
9792
|
-
setAvatarInitials(initials) {
|
|
9793
|
-
this._avatarInitials.set(initials);
|
|
9794
|
-
}
|
|
9795
|
-
setAvatarType(type) {
|
|
9796
|
-
this._avatarType.set(type);
|
|
9797
|
-
}
|
|
9798
|
-
setAvatarSrc(src) {
|
|
9799
|
-
this._avatarSrc.set(src);
|
|
9800
|
-
}
|
|
9801
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: UserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
9802
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: UserService, providedIn: 'root' });
|
|
9803
|
-
}
|
|
9804
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: UserService, decorators: [{
|
|
9805
|
-
type: Injectable,
|
|
9806
|
-
args: [{
|
|
9807
|
-
providedIn: 'root'
|
|
9808
|
-
}]
|
|
9809
|
-
}] });
|
|
9810
|
-
|
|
9811
9248
|
class MobileCommunityPageComponent {
|
|
9812
9249
|
router;
|
|
9813
9250
|
route;
|
|
@@ -10453,7 +9890,7 @@ class MobileCommunityPageComponent {
|
|
|
10453
9890
|
</div>
|
|
10454
9891
|
</ds-mobile-content>
|
|
10455
9892
|
</ds-mobile-page-main>
|
|
10456
|
-
`, isInline: true, styles: [".post-feed{display:flex;flex-direction:column;max-width:640px}.post-list-wrapper{display:flex;flex-direction:column}.pinned-posts-section{margin:-12px -12px 12px;padding:0 12px 12px;box-shadow:var(--box-shadow-sm);border-radius:16px;border:1px solid var(--border-color-default)}.clickable-image{cursor:pointer;transition:transform .2s ease,opacity .2s ease;border-radius:8px;display:block;width:100%;aspect-ratio:16/9;object-fit:cover}.clickable-image:active{transform:scale(.98);opacity:.9}.community-empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;text-align:center}.empty-state-image{width:96px;height:96px;margin-bottom:24px}\n"], dependencies: [{ kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance"], outputs: ["avatarClick", "refresh", "scroll"] }, { kind: "component", type: DsMobileContentComponent, selector: "ds-mobile-content", inputs: ["layout"] }, { kind: "component", type: DsMobileInteractiveListItemPostComponent, selector: "ds-mobile-interactive-list-item-post", inputs: ["authorName", "authorRole", "timestamp", "avatarInitials", "avatarType", "avatarSrc", "avatarIconName", "showBadge", "variant", "clickable"], outputs: ["postClick", "commentClick", "longPress"] }, { kind: "component", type: DsMobilePostComposerComponent, selector: "ds-mobile-post-composer", inputs: ["avatarInitials", "avatarType", "avatarSrc", "avatarIconName", "placeholder", "buttonText"], outputs: ["composerClick"] }, { kind: "component", type: PostContentComponent, selector: "post-content" }, { kind: "component", type: PostTextComponent, selector: "post-text" }, { kind: "component", type: PostMediaComponent, selector: "post-media" }, { kind: "component", type: PostAttachmentsComponent, selector: "post-attachments" }, { kind: "component", type: PostActionsComponent, selector: "post-actions" }, { kind: "component", type: ActionLikeComponent, selector: "action-like", inputs: ["active", "count"], outputs: ["activeChange", "countChange", "likeClick"] }, { kind: "component", type: ActionCommentComponent, selector: "action-comment", inputs: ["count"], outputs: ["commentClick"] }, { kind: "component", type: DsMobileCardInlineFileComponent, selector: "ds-mobile-card-inline-file", inputs: ["fileName", "fileSize", "variant", "layout"], outputs: ["fileClick"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileInlinePhotoComponent, selector: "ds-mobile-inline-photo", inputs: ["images", "author", "maxVisible"], outputs: ["photoClick"] }] });
|
|
9893
|
+
`, isInline: true, styles: [".post-feed{display:flex;flex-direction:column;max-width:640px}.post-list-wrapper{display:flex;flex-direction:column}.pinned-posts-section{margin:-12px -12px 12px;padding:0 12px 12px;box-shadow:var(--box-shadow-sm);border-radius:16px;border:1px solid var(--border-color-default)}.clickable-image{cursor:pointer;transition:transform .2s ease,opacity .2s ease;border-radius:8px;display:block;width:100%;aspect-ratio:16/9;object-fit:cover}.clickable-image:active{transform:scale(.98);opacity:.9}.community-empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;text-align:center}.empty-state-image{width:96px;height:96px;margin-bottom:24px}\n"], dependencies: [{ kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance", "profileMenuItems"], outputs: ["avatarClick", "profileActionSelected", "refresh", "scroll"] }, { kind: "component", type: DsMobileContentComponent, selector: "ds-mobile-content", inputs: ["layout"] }, { kind: "component", type: DsMobileInteractiveListItemPostComponent, selector: "ds-mobile-interactive-list-item-post", inputs: ["authorName", "authorRole", "timestamp", "avatarInitials", "avatarType", "avatarSrc", "avatarIconName", "showBadge", "variant", "clickable"], outputs: ["postClick", "commentClick", "longPress"] }, { kind: "component", type: DsMobilePostComposerComponent, selector: "ds-mobile-post-composer", inputs: ["avatarInitials", "avatarType", "avatarSrc", "avatarIconName", "placeholder", "buttonText"], outputs: ["composerClick"] }, { kind: "component", type: PostContentComponent, selector: "post-content" }, { kind: "component", type: PostTextComponent, selector: "post-text" }, { kind: "component", type: PostMediaComponent, selector: "post-media" }, { kind: "component", type: PostAttachmentsComponent, selector: "post-attachments" }, { kind: "component", type: PostActionsComponent, selector: "post-actions" }, { kind: "component", type: ActionLikeComponent, selector: "action-like", inputs: ["active", "count"], outputs: ["activeChange", "countChange", "likeClick"] }, { kind: "component", type: ActionCommentComponent, selector: "action-comment", inputs: ["count"], outputs: ["commentClick"] }, { kind: "component", type: DsMobileCardInlineFileComponent, selector: "ds-mobile-card-inline-file", inputs: ["fileName", "fileSize", "variant", "layout"], outputs: ["fileClick"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileInlinePhotoComponent, selector: "ds-mobile-inline-photo", inputs: ["images", "author", "maxVisible"], outputs: ["photoClick"] }] });
|
|
10457
9894
|
}
|
|
10458
9895
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileCommunityPageComponent, decorators: [{
|
|
10459
9896
|
type: Component,
|
|
@@ -10982,7 +10419,7 @@ class MobileHandbookPageComponent {
|
|
|
10982
10419
|
</ds-mobile-content-section>
|
|
10983
10420
|
</ds-mobile-content>
|
|
10984
10421
|
</ds-mobile-page-main>
|
|
10985
|
-
`, isInline: true, styles: [".folders-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:20px;justify-items:center}@media (min-width: 768px){.folders-grid{grid-template-columns:repeat(3,1fr)}}ds-mobile-handbook-folder{width:100%}\n"], dependencies: [{ kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance"], outputs: ["avatarClick", "refresh", "scroll"] }, { kind: "component", type: DsMobileContentComponent, selector: "ds-mobile-content", inputs: ["layout"] }, { kind: "component", type: DsMobileContentSectionComponent, selector: "ds-mobile-content-section" }, { kind: "component", type: DsMobileHandbookFolderComponent, selector: "ds-mobile-handbook-folder", inputs: ["variant", "iconName", "itemCount", "label", "items", "loading", "error"] }] });
|
|
10422
|
+
`, isInline: true, styles: [".folders-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:20px;justify-items:center}@media (min-width: 768px){.folders-grid{grid-template-columns:repeat(3,1fr)}}ds-mobile-handbook-folder{width:100%}\n"], dependencies: [{ kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance", "profileMenuItems"], outputs: ["avatarClick", "profileActionSelected", "refresh", "scroll"] }, { kind: "component", type: DsMobileContentComponent, selector: "ds-mobile-content", inputs: ["layout"] }, { kind: "component", type: DsMobileContentSectionComponent, selector: "ds-mobile-content-section" }, { kind: "component", type: DsMobileHandbookFolderComponent, selector: "ds-mobile-handbook-folder", inputs: ["variant", "iconName", "itemCount", "label", "items", "loading", "error"] }] });
|
|
10986
10423
|
}
|
|
10987
10424
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileHandbookPageComponent, decorators: [{
|
|
10988
10425
|
type: Component,
|
|
@@ -11173,7 +10610,7 @@ class MobileHomePageComponent {
|
|
|
11173
10610
|
</ds-mobile-content-section>
|
|
11174
10611
|
</ds-mobile-content>
|
|
11175
10612
|
</ds-mobile-page-main>
|
|
11176
|
-
`, isInline: true, styles: [".grey-box{height:120px;border-radius:12px;background:var(--color-background-neutral-tertiary);flex:1}.grey-box.clickable{background:var(--color-background-brand);cursor:pointer;transition:transform var(--transition-duration-fast) var(--ease-smooth)}.grey-box.clickable:active{transform:scale(.98)}\n"], dependencies: [{ kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance"], outputs: ["avatarClick", "refresh", "scroll"] }, { kind: "component", type: DsMobileHeaderContentComponent, selector: "ds-mobile-header-content" }, { kind: "component", type: DsMobileHeaderContentTileComponent, selector: "ds-mobile-header-content-tile" }, { kind: "component", type: TileIconComponent, selector: "tile-icon" }, { kind: "component", type: TileContentComponent, selector: "tile-content" }, { kind: "component", type: TileLabelComponent, selector: "tile-label" }, { kind: "component", type: TileValueComponent, selector: "tile-value" }, { kind: "component", type: DsMobileContentComponent, selector: "ds-mobile-content", inputs: ["layout"] }, { kind: "component", type: DsMobileContentSectionComponent, selector: "ds-mobile-content-section" }, { kind: "component", type: SectionHeaderComponent, selector: "section-header", inputs: ["width"] }, { kind: "component", type: ContentRowComponent, selector: "content-row" }] });
|
|
10613
|
+
`, isInline: true, styles: [".grey-box{height:120px;border-radius:12px;background:var(--color-background-neutral-tertiary);flex:1}.grey-box.clickable{background:var(--color-background-brand);cursor:pointer;transition:transform var(--transition-duration-fast) var(--ease-smooth)}.grey-box.clickable:active{transform:scale(.98)}\n"], dependencies: [{ kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance", "profileMenuItems"], outputs: ["avatarClick", "profileActionSelected", "refresh", "scroll"] }, { kind: "component", type: DsMobileHeaderContentComponent, selector: "ds-mobile-header-content" }, { kind: "component", type: DsMobileHeaderContentTileComponent, selector: "ds-mobile-header-content-tile" }, { kind: "component", type: TileIconComponent, selector: "tile-icon" }, { kind: "component", type: TileContentComponent, selector: "tile-content" }, { kind: "component", type: TileLabelComponent, selector: "tile-label" }, { kind: "component", type: TileValueComponent, selector: "tile-value" }, { kind: "component", type: DsMobileContentComponent, selector: "ds-mobile-content", inputs: ["layout"] }, { kind: "component", type: DsMobileContentSectionComponent, selector: "ds-mobile-content-section" }, { kind: "component", type: SectionHeaderComponent, selector: "section-header", inputs: ["width"] }, { kind: "component", type: ContentRowComponent, selector: "content-row" }] });
|
|
11177
10614
|
}
|
|
11178
10615
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileHomePageComponent, decorators: [{
|
|
11179
10616
|
type: Component,
|
|
@@ -11501,7 +10938,7 @@ class MobileInquiriesPageComponent {
|
|
|
11501
10938
|
</div>
|
|
11502
10939
|
</ds-mobile-content>
|
|
11503
10940
|
</ds-mobile-page-main>
|
|
11504
|
-
`, isInline: true, styles: [".inquiries-container{display:flex;flex-direction:column;max-width:640px}.inquiry-list-wrapper{display:flex;flex-direction:column}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;text-align:center}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin:16px 0 8px}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}\n"], dependencies: [{ kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance"], outputs: ["avatarClick", "refresh", "scroll"] }, { kind: "component", type: DsMobileContentComponent, selector: "ds-mobile-content", inputs: ["layout"] }, { kind: "component", type: DsMobileInteractiveListItemInquiryComponent, selector: "ds-mobile-interactive-list-item-inquiry", inputs: ["title", "description", "status", "statusLabel", "timestamp", "iconName", "iconColor", "variant", "clickable", "showChevron"], outputs: ["inquiryClick", "longPress"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileInlineTabsComponent, selector: "ds-mobile-inline-tabs", inputs: ["tabs", "activeTab"], outputs: ["tabChange"] }] });
|
|
10941
|
+
`, isInline: true, styles: [".inquiries-container{display:flex;flex-direction:column;max-width:640px}.inquiry-list-wrapper{display:flex;flex-direction:column}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;text-align:center}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin:16px 0 8px}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}\n"], dependencies: [{ kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance", "profileMenuItems"], outputs: ["avatarClick", "profileActionSelected", "refresh", "scroll"] }, { kind: "component", type: DsMobileContentComponent, selector: "ds-mobile-content", inputs: ["layout"] }, { kind: "component", type: DsMobileInteractiveListItemInquiryComponent, selector: "ds-mobile-interactive-list-item-inquiry", inputs: ["title", "description", "status", "statusLabel", "timestamp", "iconName", "iconColor", "variant", "clickable", "showChevron"], outputs: ["inquiryClick", "longPress"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileInlineTabsComponent, selector: "ds-mobile-inline-tabs", inputs: ["tabs", "activeTab"], outputs: ["tabChange"] }] });
|
|
11505
10942
|
}
|
|
11506
10943
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileInquiriesPageComponent, decorators: [{
|
|
11507
10944
|
type: Component,
|
|
@@ -11528,600 +10965,1187 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
11528
10965
|
</ds-mobile-inline-tabs>
|
|
11529
10966
|
</div>
|
|
11530
10967
|
|
|
11531
|
-
<ds-mobile-content>
|
|
11532
|
-
<div class="inquiries-container">
|
|
11533
|
-
@if (filteredInquiries().length > 0) {
|
|
11534
|
-
<div class="inquiry-list-wrapper">
|
|
11535
|
-
@for (inquiry of filteredInquiries(); track inquiry.id; let idx = $index) {
|
|
11536
|
-
<ds-mobile-interactive-list-item-inquiry
|
|
11537
|
-
[title]="inquiry.title"
|
|
11538
|
-
[description]="inquiry.description"
|
|
11539
|
-
[status]="inquiry.status"
|
|
11540
|
-
[timestamp]="inquiry.timestamp"
|
|
11541
|
-
[iconName]="getInquiryIcon(inquiry.category)"
|
|
11542
|
-
[clickable]="true"
|
|
11543
|
-
[showChevron]="false"
|
|
11544
|
-
(inquiryClick)="openInquiryDetail(inquiry.id)"
|
|
11545
|
-
(longPress)="showInquiryActions(inquiry.id)">
|
|
11546
|
-
</ds-mobile-interactive-list-item-inquiry>
|
|
11547
|
-
|
|
11548
|
-
}
|
|
11549
|
-
</div>
|
|
11550
|
-
} @else {
|
|
11551
|
-
<!-- Empty state -->
|
|
11552
|
-
<div class="empty-state">
|
|
11553
|
-
<ds-icon name="remixInboxLine" size="48px" color="tertiary" />
|
|
11554
|
-
<h3 class="empty-state-title">Ingen henvendelser endnu</h3>
|
|
11555
|
-
<p class="empty-state-description">
|
|
11556
|
-
@if (filterStatus() === 'open') {
|
|
11557
|
-
Du har ingen åbne henvendelser
|
|
11558
|
-
} @else if (filterStatus() === 'closed') {
|
|
11559
|
-
Du har ingen lukkede henvendelser
|
|
11560
|
-
} @else {
|
|
11561
|
-
Du har ikke oprettet nogen henvendelser endnu
|
|
11562
|
-
}
|
|
11563
|
-
</p>
|
|
11564
|
-
</div>
|
|
11565
|
-
}
|
|
10968
|
+
<ds-mobile-content>
|
|
10969
|
+
<div class="inquiries-container">
|
|
10970
|
+
@if (filteredInquiries().length > 0) {
|
|
10971
|
+
<div class="inquiry-list-wrapper">
|
|
10972
|
+
@for (inquiry of filteredInquiries(); track inquiry.id; let idx = $index) {
|
|
10973
|
+
<ds-mobile-interactive-list-item-inquiry
|
|
10974
|
+
[title]="inquiry.title"
|
|
10975
|
+
[description]="inquiry.description"
|
|
10976
|
+
[status]="inquiry.status"
|
|
10977
|
+
[timestamp]="inquiry.timestamp"
|
|
10978
|
+
[iconName]="getInquiryIcon(inquiry.category)"
|
|
10979
|
+
[clickable]="true"
|
|
10980
|
+
[showChevron]="false"
|
|
10981
|
+
(inquiryClick)="openInquiryDetail(inquiry.id)"
|
|
10982
|
+
(longPress)="showInquiryActions(inquiry.id)">
|
|
10983
|
+
</ds-mobile-interactive-list-item-inquiry>
|
|
10984
|
+
|
|
10985
|
+
}
|
|
10986
|
+
</div>
|
|
10987
|
+
} @else {
|
|
10988
|
+
<!-- Empty state -->
|
|
10989
|
+
<div class="empty-state">
|
|
10990
|
+
<ds-icon name="remixInboxLine" size="48px" color="tertiary" />
|
|
10991
|
+
<h3 class="empty-state-title">Ingen henvendelser endnu</h3>
|
|
10992
|
+
<p class="empty-state-description">
|
|
10993
|
+
@if (filterStatus() === 'open') {
|
|
10994
|
+
Du har ingen åbne henvendelser
|
|
10995
|
+
} @else if (filterStatus() === 'closed') {
|
|
10996
|
+
Du har ingen lukkede henvendelser
|
|
10997
|
+
} @else {
|
|
10998
|
+
Du har ikke oprettet nogen henvendelser endnu
|
|
10999
|
+
}
|
|
11000
|
+
</p>
|
|
11001
|
+
</div>
|
|
11002
|
+
}
|
|
11003
|
+
</div>
|
|
11004
|
+
</ds-mobile-content>
|
|
11005
|
+
</ds-mobile-page-main>
|
|
11006
|
+
`, styles: [".inquiries-container{display:flex;flex-direction:column;max-width:640px}.inquiry-list-wrapper{display:flex;flex-direction:column}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;text-align:center}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin:16px 0 8px}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}\n"] }]
|
|
11007
|
+
}], ctorParameters: () => [{ type: UserService }, { type: i1.NavController }] });
|
|
11008
|
+
|
|
11009
|
+
class MobileInquiryDetailPageComponent extends MobilePageBase {
|
|
11010
|
+
userService;
|
|
11011
|
+
navCtrl;
|
|
11012
|
+
elementRef;
|
|
11013
|
+
ionContent;
|
|
11014
|
+
// Platform detection
|
|
11015
|
+
platform = inject(Platform);
|
|
11016
|
+
// Computed property to check if running on native platform
|
|
11017
|
+
isNativePlatform = computed(() => this.platform.is('ios') ||
|
|
11018
|
+
this.platform.is('android') ||
|
|
11019
|
+
this.platform.is('capacitor'), ...(ngDevMode ? [{ debugName: "isNativePlatform" }] : []));
|
|
11020
|
+
inquiryTitle = 'Tørretumbler virker ikke';
|
|
11021
|
+
activeTab = signal('activity', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
|
|
11022
|
+
tabItems = [
|
|
11023
|
+
{ id: 'activity', label: 'Aktivitet' },
|
|
11024
|
+
{ id: 'messages', label: 'Beskeder', badge: 0 },
|
|
11025
|
+
{ id: 'details', label: 'Detaljer' }
|
|
11026
|
+
];
|
|
11027
|
+
activities = [
|
|
11028
|
+
{
|
|
11029
|
+
id: '1',
|
|
11030
|
+
type: 'assignment',
|
|
11031
|
+
actor: 'Martin Smith',
|
|
11032
|
+
actorInitials: 'MS',
|
|
11033
|
+
title: 'er blevet tildelt som din dedikerede tekniker.',
|
|
11034
|
+
timestamp: '2 dage siden',
|
|
11035
|
+
date: '28. feb 2025',
|
|
11036
|
+
iconName: 'remixUserAddLine'
|
|
11037
|
+
},
|
|
11038
|
+
{
|
|
11039
|
+
id: '2',
|
|
11040
|
+
type: 'assignment',
|
|
11041
|
+
actor: 'Ricki Meihlen',
|
|
11042
|
+
actorInitials: 'RM',
|
|
11043
|
+
title: 'er blevet tildelt til at håndtere din henvendelse.',
|
|
11044
|
+
timestamp: '8 dage siden',
|
|
11045
|
+
date: '22. feb 2025',
|
|
11046
|
+
iconName: 'remixUserLine'
|
|
11047
|
+
},
|
|
11048
|
+
{
|
|
11049
|
+
id: '3',
|
|
11050
|
+
type: 'creation',
|
|
11051
|
+
title: 'Henvendelse oprettet',
|
|
11052
|
+
timestamp: '8 dage siden',
|
|
11053
|
+
date: '22. feb 2025',
|
|
11054
|
+
iconName: 'remixAddCircleLine'
|
|
11055
|
+
}
|
|
11056
|
+
];
|
|
11057
|
+
messageThreads = [
|
|
11058
|
+
{
|
|
11059
|
+
id: '1',
|
|
11060
|
+
senderName: 'Ove Hindborg',
|
|
11061
|
+
senderAvatar: '',
|
|
11062
|
+
senderInitials: 'OH',
|
|
11063
|
+
message: 'Dejligt at høre! Jeg venter på din teknikerbesøg tidsplan.',
|
|
11064
|
+
role: 'Sagsbehandler',
|
|
11065
|
+
timestamp: '2t siden',
|
|
11066
|
+
unread: true
|
|
11067
|
+
},
|
|
11068
|
+
{
|
|
11069
|
+
id: '2',
|
|
11070
|
+
senderName: 'Martin Smith',
|
|
11071
|
+
senderAvatar: '',
|
|
11072
|
+
senderInitials: 'MS',
|
|
11073
|
+
message: 'Dejligt at høre! Jeg venter på din teknikerbesøg tidsplan.',
|
|
11074
|
+
role: 'Tekniker',
|
|
11075
|
+
timestamp: '4t siden',
|
|
11076
|
+
unread: true
|
|
11077
|
+
}
|
|
11078
|
+
];
|
|
11079
|
+
unreadMessagesCount = computed(() => {
|
|
11080
|
+
const count = this.messageThreads.filter(m => m.unread).length;
|
|
11081
|
+
// Update badge in tab items
|
|
11082
|
+
const messagesTab = this.tabItems.find(t => t.id === 'messages');
|
|
11083
|
+
if (messagesTab) {
|
|
11084
|
+
messagesTab.badge = count;
|
|
11085
|
+
}
|
|
11086
|
+
return count;
|
|
11087
|
+
}, ...(ngDevMode ? [{ debugName: "unreadMessagesCount" }] : []));
|
|
11088
|
+
constructor(userService, navCtrl, elementRef) {
|
|
11089
|
+
super();
|
|
11090
|
+
this.userService = userService;
|
|
11091
|
+
this.navCtrl = navCtrl;
|
|
11092
|
+
this.elementRef = elementRef;
|
|
11093
|
+
// Trigger initial badge update
|
|
11094
|
+
this.unreadMessagesCount();
|
|
11095
|
+
}
|
|
11096
|
+
ngAfterViewInit() {
|
|
11097
|
+
// Initial setup if needed
|
|
11098
|
+
}
|
|
11099
|
+
setActiveTab(tabId) {
|
|
11100
|
+
this.activeTab.set(tabId);
|
|
11101
|
+
}
|
|
11102
|
+
goBack() {
|
|
11103
|
+
this.navCtrl.back({ animation: customBackTransition });
|
|
11104
|
+
}
|
|
11105
|
+
handleScroll(event) {
|
|
11106
|
+
const scrollTop = event.detail.scrollTop;
|
|
11107
|
+
const threshold = 160;
|
|
11108
|
+
const fadeDistance = 200;
|
|
11109
|
+
const header = this.elementRef.nativeElement.querySelector('ion-header:not([collapse])');
|
|
11110
|
+
const headerExpandable = this.elementRef.nativeElement.querySelector('.header-expandable');
|
|
11111
|
+
// Show title in fixed header when scrolled past threshold
|
|
11112
|
+
if (scrollTop > threshold) {
|
|
11113
|
+
header?.classList.add('header-scrolled');
|
|
11114
|
+
}
|
|
11115
|
+
else {
|
|
11116
|
+
header?.classList.remove('header-scrolled');
|
|
11117
|
+
}
|
|
11118
|
+
// Fade out header-expandable content based on scroll
|
|
11119
|
+
if (headerExpandable) {
|
|
11120
|
+
const fadeProgress = Math.min(scrollTop / fadeDistance, 1);
|
|
11121
|
+
// Calculate opacity (1 to 0)
|
|
11122
|
+
const opacity = 1 - fadeProgress;
|
|
11123
|
+
// Calculate transform (0px to -20px upward)
|
|
11124
|
+
const translateY = fadeProgress * -20;
|
|
11125
|
+
// Apply styles
|
|
11126
|
+
headerExpandable.style.opacity = opacity.toString();
|
|
11127
|
+
headerExpandable.style.transform = `translateY(${translateY}px)`;
|
|
11128
|
+
}
|
|
11129
|
+
}
|
|
11130
|
+
handleRefresh(event) {
|
|
11131
|
+
console.log('Pull-to-refresh triggered');
|
|
11132
|
+
setTimeout(() => {
|
|
11133
|
+
console.log('Refresh complete');
|
|
11134
|
+
event.target.complete();
|
|
11135
|
+
}, 1000);
|
|
11136
|
+
}
|
|
11137
|
+
openMessage(messageId) {
|
|
11138
|
+
console.log('Opening message:', messageId);
|
|
11139
|
+
// Navigate to message thread detail
|
|
11140
|
+
}
|
|
11141
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileInquiryDetailPageComponent, deps: [{ token: UserService }, { token: i1.NavController }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
11142
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: MobileInquiryDetailPageComponent, isStandalone: true, selector: "app-mobile-inquiry-detail-page", host: { classAttribute: "ion-page" }, viewQueries: [{ propertyName: "ionContent", first: true, predicate: IonContent, descendants: true }], usesInheritance: true, ngImport: i0, template: `
|
|
11143
|
+
<!-- Fixed header at top -->
|
|
11144
|
+
<ion-header>
|
|
11145
|
+
<ion-toolbar>
|
|
11146
|
+
<div class="header-detail">
|
|
11147
|
+
<!-- Back Button -->
|
|
11148
|
+
<button class="back-button" (click)="goBack()" [attr.aria-label]="'Go back'">
|
|
11149
|
+
<ds-icon name="remixArrowLeftSLine" size="24px" color="white" />
|
|
11150
|
+
</button>
|
|
11151
|
+
|
|
11152
|
+
<!-- Title - fades in on scroll -->
|
|
11153
|
+
<ion-title class="header-detail__title">{{ inquiryTitle }}</ion-title>
|
|
11154
|
+
</div>
|
|
11155
|
+
</ion-toolbar>
|
|
11156
|
+
</ion-header>
|
|
11157
|
+
|
|
11158
|
+
<!-- Content with expandable header -->
|
|
11159
|
+
<ion-content [scrollEvents]="true" (ionScroll)="handleScroll($event)">
|
|
11160
|
+
<!-- Pull to refresh (only on native iOS/Android) -->
|
|
11161
|
+
@if (isNativePlatform()) {
|
|
11162
|
+
<ion-refresher
|
|
11163
|
+
slot="fixed"
|
|
11164
|
+
(ionRefresh)="handleRefresh($event)"
|
|
11165
|
+
[pullFactor]="0.4"
|
|
11166
|
+
[pullMin]="80"
|
|
11167
|
+
[pullMax]="240"
|
|
11168
|
+
closeDuration="600ms">
|
|
11169
|
+
<ion-refresher-content
|
|
11170
|
+
pullingIcon="remixArrowDownS"
|
|
11171
|
+
refreshingSpinner="lines">
|
|
11172
|
+
</ion-refresher-content>
|
|
11173
|
+
</ion-refresher>
|
|
11174
|
+
}
|
|
11175
|
+
|
|
11176
|
+
<!-- Expandable header section (purple background) -->
|
|
11177
|
+
<div class="header-expandable">
|
|
11178
|
+
<div class="header-expandable-inner">
|
|
11179
|
+
<div class="header-expandable__text">
|
|
11180
|
+
<h1 class="header-expandable__title">{{ inquiryTitle }}</h1>
|
|
11181
|
+
</div>
|
|
11182
|
+
|
|
11183
|
+
<!-- Tabs in header -->
|
|
11184
|
+
<ds-mobile-inline-tabs
|
|
11185
|
+
[tabs]="tabItems"
|
|
11186
|
+
[activeTab]="activeTab()"
|
|
11187
|
+
(tabChange)="setActiveTab($event)">
|
|
11188
|
+
</ds-mobile-inline-tabs>
|
|
11189
|
+
</div>
|
|
11190
|
+
</div>
|
|
11191
|
+
|
|
11192
|
+
<!-- Content wrapper -->
|
|
11193
|
+
<div class="content-wrapper">
|
|
11194
|
+
<div class="content-inner">
|
|
11195
|
+
<!-- Activity Tab Content -->
|
|
11196
|
+
@if (activeTab() === 'activity') {
|
|
11197
|
+
<div class="activity-list">
|
|
11198
|
+
@for (activity of activities; track activity.id) {
|
|
11199
|
+
<div class="activity-item">
|
|
11200
|
+
@if (activity.actor) {
|
|
11201
|
+
<!-- Avatar with badge for actor activities -->
|
|
11202
|
+
<div class="avatar-wrapper">
|
|
11203
|
+
<ds-avatar
|
|
11204
|
+
[type]="'initials'"
|
|
11205
|
+
[initials]="activity.actorInitials || ''"
|
|
11206
|
+
size="md" />
|
|
11207
|
+
|
|
11208
|
+
<div class="avatar-badge">
|
|
11209
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 32" fill="none">
|
|
11210
|
+
<path d="M33.9862 5.51709H23.1724V8.82743H26.0413C26.2841 8.82743 26.4827 9.02606 26.4827 9.26881V12.7998C26.4827 13.0426 26.2841 13.2412 26.0413 13.2412H23.1724V14.3447H26.0413C26.2841 14.3447 26.4827 14.5433 26.4827 14.7861V18.3171C26.4827 18.5598 26.2841 18.7585 26.0413 18.7585H23.1724V19.8619H26.0413C26.2841 19.8619 26.4827 20.0605 26.4827 20.3033V23.8343C26.4827 24.0771 26.2841 24.2757 26.0413 24.2757H23.1724V26.2619C23.1724 26.7496 23.0267 27.2043 22.7773 27.5861H27.5862L32 31.9999V27.5861H33.9862C34.7167 27.5861 35.3103 26.9924 35.3103 26.2619V6.84123C35.3103 6.11075 34.7167 5.51709 33.9862 5.51709ZM32 23.8343C32 24.0771 31.8013 24.2757 31.5586 24.2757H28.0276C27.7848 24.2757 27.5862 24.0771 27.5862 23.8343V20.3033C27.5862 20.0605 27.7848 19.8619 28.0276 19.8619H31.5586C31.8013 19.8619 32 20.0605 32 20.3033V23.8343ZM32 18.3171C32 18.5598 31.8013 18.7585 31.5586 18.7585H28.0276C27.7848 18.7585 27.5862 18.5598 27.5862 18.3171V14.7861C27.5862 14.5433 27.7848 14.3447 28.0276 14.3447H31.5586C31.8013 14.3447 32 14.5433 32 14.7861V18.3171ZM32 12.7998C32 13.0426 31.8013 13.2412 31.5586 13.2412H28.0276C27.7848 13.2412 27.5862 13.0426 27.5862 12.7998V9.26881C27.5862 9.02606 27.7848 8.82743 28.0276 8.82743H31.5586C31.8013 8.82743 32 9.02606 32 9.26881V12.7998Z" fill="white"/>
|
|
11211
|
+
<path d="M20.7448 0H1.32414C0.593655 0 0 0.593655 0 1.32414V26.2621C0 26.9926 0.593655 27.5862 1.32414 27.5862H3.31034V32L7.72414 27.5862H20.7448C21.4753 27.5862 22.069 26.9926 22.069 26.2621V1.32414C22.069 0.593655 21.4753 0 20.7448 0ZM7.72414 23.8345C7.72414 24.0772 7.52552 24.2759 7.28276 24.2759H3.75172C3.50897 24.2759 3.31034 24.0772 3.31034 23.8345V20.3034C3.31034 20.0607 3.50897 19.8621 3.75172 19.8621H7.28276C7.52552 19.8621 7.72414 20.0607 7.72414 20.3034V23.8345ZM7.72414 18.3172C7.72414 18.56 7.52552 18.7586 7.28276 18.7586H3.75172C3.50897 18.7586 3.31034 18.56 3.31034 18.3172V14.7862C3.31034 14.5434 3.50897 14.3448 3.75172 14.3448H7.28276C7.52552 14.3448 7.72414 14.5434 7.72414 14.7862V18.3172ZM7.72414 12.8C7.72414 13.0428 7.52552 13.2414 7.28276 13.2414H3.75172C3.50897 13.2414 3.31034 13.0428 3.31034 12.8V9.26897C3.31034 9.02621 3.50897 8.82759 3.75172 8.82759H7.28276C7.52552 8.82759 7.72414 9.02621 7.72414 9.26897V12.8ZM7.72414 7.28276C7.72414 7.52552 7.52552 7.72414 7.28276 7.72414H3.75172C3.50897 7.72414 3.31034 7.52552 3.31034 7.28276V3.75172C3.31034 3.50897 3.50897 3.31034 3.75172 3.31034H7.28276C7.52552 3.31034 7.72414 3.50897 7.72414 3.75172V7.28276ZM13.2414 23.8345C13.2414 24.0772 13.0428 24.2759 12.8 24.2759H9.26897C9.02621 24.2759 8.82759 24.0772 8.82759 23.8345V20.3034C8.82759 20.0607 9.02621 19.8621 9.26897 19.8621H12.8C13.0428 19.8621 13.2414 20.0607 13.2414 20.3034V23.8345ZM13.2414 18.3172C13.2414 18.56 13.0428 18.7586 12.8 18.7586H9.26897C9.02621 18.7586 8.82759 18.56 8.82759 18.3172V14.7862C8.82759 14.5434 9.02621 14.3448 9.26897 14.3448H12.8C13.0428 14.3448 13.2414 14.5434 13.2414 14.7862V18.3172ZM13.2414 12.8C13.2414 13.0428 13.0428 13.2414 12.8 13.2414H9.26897C9.02621 13.2414 8.82759 13.0428 8.82759 12.8V9.26897C8.82759 9.02621 9.02621 8.82759 9.26897 8.82759H12.8C13.0428 8.82759 13.2414 9.02621 13.2414 9.26897V12.8ZM13.2414 6.84138V7.28276C13.2414 7.52552 13.0428 7.72414 12.8 7.72414H9.26897C9.02621 7.72414 8.82759 7.52552 8.82759 7.28276V3.75172C8.82759 3.50897 9.02621 3.31034 9.26897 3.31034H12.8C13.0428 3.31034 13.2414 3.50897 13.2414 3.75172V6.84138ZM18.7586 23.8345C18.7586 24.0772 18.56 24.2759 18.3172 24.2759H14.7862C14.5434 24.2759 14.3448 24.0772 14.3448 23.8345V20.3034C14.3448 20.0607 14.5434 19.8621 14.7862 19.8621H18.3172C18.56 19.8621 18.7586 20.0607 18.7586 20.3034V23.8345ZM18.7586 18.3172C18.7586 18.56 18.56 18.7586 18.3172 18.7586H14.7862C14.5434 18.7586 14.3448 18.56 14.3448 18.3172V14.7862C14.3448 14.5434 14.5434 14.3448 14.7862 14.3448H18.3172C18.56 14.3448 18.7586 14.5434 18.7586 14.7862V18.3172ZM18.7586 12.8C18.7586 13.0428 18.56 13.2414 18.3172 13.2414H14.7862C14.5434 13.2414 14.3448 13.0428 14.3448 12.8V9.26897C14.3448 9.02621 14.5434 8.82759 14.7862 8.82759H18.3172C18.56 8.82759 18.7586 9.02621 18.7586 9.26897V12.8ZM18.7586 5.51724V7.28276C18.7586 7.52552 18.56 7.72414 18.3172 7.72414H14.7862C14.5434 7.72414 14.3448 7.52552 14.3448 7.28276V3.75172C14.3448 3.50897 14.5434 3.31034 14.7862 3.31034H18.3172C18.56 3.31034 18.7586 3.50897 18.7586 3.75172V5.51724Z" fill="white"/>
|
|
11212
|
+
</svg>
|
|
11213
|
+
</div>
|
|
11214
|
+
</div>
|
|
11215
|
+
} @else {
|
|
11216
|
+
<!-- Icon wrapper for non-actor activities -->
|
|
11217
|
+
<div class="activity-icon-wrapper">
|
|
11218
|
+
<ds-icon
|
|
11219
|
+
[name]="activity.iconName"
|
|
11220
|
+
size="18px"
|
|
11221
|
+
color="secondary" />
|
|
11222
|
+
</div>
|
|
11223
|
+
}
|
|
11224
|
+
|
|
11225
|
+
<div class="activity-content">
|
|
11226
|
+
<p class="activity-title">
|
|
11227
|
+
@if (activity.actor) {
|
|
11228
|
+
<span class="actor-name">{{ activity.actor }}</span>
|
|
11229
|
+
<span class="activity-text"> {{ activity.title }}</span>
|
|
11230
|
+
} @else {
|
|
11231
|
+
<span class="actor-name">{{ activity.title }}</span>
|
|
11232
|
+
}
|
|
11233
|
+
</p>
|
|
11234
|
+
@if (activity.description) {
|
|
11235
|
+
<p class="activity-description">{{ activity.description }}</p>
|
|
11236
|
+
}
|
|
11237
|
+
<div class="activity-timestamp">
|
|
11238
|
+
<ds-icon name="remixCalendarLine" size="12px" color="--color-text-tertiary" />
|
|
11239
|
+
<span>{{ activity.date }}</span>
|
|
11240
|
+
</div>
|
|
11241
|
+
</div>
|
|
11242
|
+
</div>
|
|
11243
|
+
}
|
|
11244
|
+
</div>
|
|
11245
|
+
}
|
|
11246
|
+
|
|
11247
|
+
<!-- Messages Tab Content -->
|
|
11248
|
+
@if (activeTab() === 'messages') {
|
|
11249
|
+
<div class="messages-list">
|
|
11250
|
+
@for (message of messageThreads; track message.id) {
|
|
11251
|
+
<ds-mobile-interactive-list-item-message
|
|
11252
|
+
[senderName]="message.senderName"
|
|
11253
|
+
[senderRole]="message.role"
|
|
11254
|
+
[message]="message.message"
|
|
11255
|
+
[avatarInitials]="message.senderInitials"
|
|
11256
|
+
[unread]="message.unread"
|
|
11257
|
+
(messageClick)="openMessage(message.id)">
|
|
11258
|
+
</ds-mobile-interactive-list-item-message>
|
|
11259
|
+
}
|
|
11260
|
+
</div>
|
|
11261
|
+
}
|
|
11262
|
+
|
|
11263
|
+
<!-- Details Tab Content -->
|
|
11264
|
+
@if (activeTab() === 'details') {
|
|
11265
|
+
<div class="details-list">
|
|
11266
|
+
<!-- Assignee -->
|
|
11267
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11268
|
+
<div content-leading>
|
|
11269
|
+
<ds-avatar
|
|
11270
|
+
[size]="'sm'"
|
|
11271
|
+
[type]="'initials'"
|
|
11272
|
+
[initials]="'R'" />
|
|
11273
|
+
</div>
|
|
11274
|
+
<div content-main>
|
|
11275
|
+
<div class="detail-label">Sagsbehandler</div>
|
|
11276
|
+
<div class="detail-value">Ricki Meihlen</div>
|
|
11277
|
+
</div>
|
|
11278
|
+
</ds-mobile-list-item-static>
|
|
11279
|
+
|
|
11280
|
+
<!-- Technician -->
|
|
11281
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11282
|
+
<div content-leading>
|
|
11283
|
+
<ds-avatar
|
|
11284
|
+
[size]="'sm'"
|
|
11285
|
+
[type]="'initials'"
|
|
11286
|
+
[initials]="'M'" />
|
|
11287
|
+
</div>
|
|
11288
|
+
<div content-main>
|
|
11289
|
+
<div class="detail-label">Tekniker</div>
|
|
11290
|
+
<div class="detail-value">Martin Smith</div>
|
|
11291
|
+
</div>
|
|
11292
|
+
</ds-mobile-list-item-static>
|
|
11293
|
+
|
|
11294
|
+
<!-- Title -->
|
|
11295
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11296
|
+
<div content-leading>
|
|
11297
|
+
<ds-icon name="remixTextBlock" size="20px" color="tertiary" />
|
|
11298
|
+
</div>
|
|
11299
|
+
<div content-main>
|
|
11300
|
+
<div class="detail-value">{{ inquiryTitle }}</div>
|
|
11301
|
+
</div>
|
|
11302
|
+
</ds-mobile-list-item-static>
|
|
11303
|
+
|
|
11304
|
+
<!-- Description -->
|
|
11305
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11306
|
+
<div content-leading>
|
|
11307
|
+
<ds-icon name="remixAlignLeft" size="20px" color="tertiary" />
|
|
11308
|
+
</div>
|
|
11309
|
+
<div content-main>
|
|
11310
|
+
<div class="detail-value description-text">
|
|
11311
|
+
I de sidste tre dage har vi oplevet vedvarende problemer med tørretumbleren i vores lejlighed. På trods af at vi følger betjeningsvejledningen, fejler maskinen konsekvent i at fuldføre sine tørrecyklusser.
|
|
11312
|
+
</div>
|
|
11313
|
+
<div class="detail-tag">Husholdningsapparater</div>
|
|
11314
|
+
</div>
|
|
11315
|
+
</ds-mobile-list-item-static>
|
|
11316
|
+
|
|
11317
|
+
<!-- Photos -->
|
|
11318
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11319
|
+
<div content-leading>
|
|
11320
|
+
<ds-icon name="remixCameraLine" size="20px" color="tertiary" />
|
|
11321
|
+
</div>
|
|
11322
|
+
<div content-main>
|
|
11323
|
+
<div class="photo-grid">
|
|
11324
|
+
<button class="photo-add">
|
|
11325
|
+
<ds-icon name="remixAddLine" size="20px" color="tertiary" />
|
|
11326
|
+
</button>
|
|
11327
|
+
<!-- Placeholder photos -->
|
|
11328
|
+
<div class="photo-item"></div>
|
|
11329
|
+
<div class="photo-item"></div>
|
|
11330
|
+
<div class="photo-item"></div>
|
|
11331
|
+
<div class="photo-item"></div>
|
|
11332
|
+
</div>
|
|
11333
|
+
</div>
|
|
11334
|
+
</ds-mobile-list-item-static>
|
|
11335
|
+
</div>
|
|
11336
|
+
}
|
|
11337
|
+
</div>
|
|
11338
|
+
</div>
|
|
11339
|
+
</ion-content>
|
|
11340
|
+
`, isInline: true, styles: ["ion-header{--background: var(--color-brand-secondary, #5d5fef);height:72px;min-height:72px}ion-toolbar{--background: var(--color-brand-secondary, #5d5fef);--color: white;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 72px;height:100%;min-height:72px}ion-toolbar ion-title{transition:transform .2s ease,opacity .2s ease!important}.header-detail{display:flex;align-items:center;gap:12px;padding:0 20px;height:100%}.back-button{width:36px;height:36px;border-radius:50%;background:#ffffff1a;border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .2s ease;color:#fff;padding:0;flex-shrink:0}.back-button:hover,.back-button:active{background:#ffffff26}.header-detail__title{position:absolute;left:64px;transform:translateY(-100%);font-size:var(--font-size-base);font-weight:600;color:#fff;opacity:0!important;pointer-events:none;transition:transform .2s ease,opacity .2s ease!important;margin:0;padding:0;--color: white;text-align:left!important}.header-scrolled .header-detail__title{opacity:1!important;pointer-events:auto;transform:translateY(0)}@media (min-width: 768px){.header-detail{padding:16px 24px}}ion-content{--background: var(--color-brand-secondary);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;border-radius:24px 24px 0 0;overflow:hidden}.plt-ios ion-content{--background: var(--color-background-neutral-primary)}@media (min-width: 768px){ion-content{border-radius:24px 24px 0 0}}ion-content::part(scroll){-webkit-overflow-scrolling:touch;display:flex;flex-direction:column}ion-refresher{z-index:0}ion-refresher-content{--color: white}.header-expandable{background:var(--color-brand-secondary);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}.header-expandable-inner{display:flex;flex-direction:column;gap:20px;max-width:640px}.header-expandable__text{margin-bottom:0}@media (min-width: 768px){.header-expandable{padding:40px var(--content-padding-md) 32px var(--content-padding-md)}}@media (min-width: 992px){.header-expandable{padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){.header-expandable{padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.header-expandable{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.header-expandable{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}.content-wrapper{background:var(--color-background-neutral-primary, white);border-radius:24px 24px 0 0;flex:1 1 auto;min-height:100%;position:relative;z-index:10;box-shadow:0 200vh 0 0 var(--color-background-neutral-primary)}.content-inner{padding:24px 20px 40px}@media (min-width: 768px){.content-inner{padding:32px}}.activity-list{display:flex;flex-direction:column;gap:32px}.activity-item{display:flex;gap:12px;position:relative}.activity-item:after{content:\"\";position:absolute;bottom:-16px;left:44px;right:8px;height:1px;background:var(--border-color-default, #e5e5e5)}.activity-item:last-child:after{display:none}.activity-icon-wrapper{width:32px;height:32px;border-radius:8px;background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;flex-shrink:0}.avatar-wrapper{position:relative;display:flex;align-items:start;justify-content:center;flex-shrink:0;width:32px;height:32px}.avatar-badge{position:absolute;bottom:-6px;right:-6px;width:20px;height:20px;border-radius:8px;background:var(--color-brand-secondary, #5d5fef);display:flex;align-items:center;justify-content:center;border:2px solid var(--color-background-primary, #ffffff)}.avatar-badge svg{width:10px;position:relative;top:1px;fill:#fff}.activity-content{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.activity-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0}.activity-title .actor-name{font-weight:600;color:var(--text-color-default-primary, #202227)}.activity-title .activity-text{color:var(--text-color-default-secondary, #545B66);font-weight:400}.activity-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0}.activity-timestamp{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373);display:flex;align-items:center;gap:4px;margin-top:2px}.messages-list{display:flex;flex-direction:column;gap:8px;margin:-8px}.details-list{display:flex;flex-direction:column;gap:20px}.detail-label{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-tertiary, #737373)}.detail-value{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:24px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227)}.detail-value.description-text{padding:8px 0}.detail-tag{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;background:var(--color-background-neutral-secondary, #f5f5f5);font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;color:var(--text-color-default-secondary, #525866);margin-top:4px;margin-bottom:10px;width:-moz-fit-content;width:fit-content}.photo-grid{display:flex;gap:8px;margin-top:8px;overflow-x:auto}.photo-add{width:80px;height:80px;border-radius:12px;border:1px dashed var(--border-color-default, #e5e5e5);background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;cursor:pointer;flex-shrink:0}.photo-item{width:80px;height:80px;border-radius:12px;background:var(--color-background-neutral-secondary, #e5e5e5);flex-shrink:0}\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: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }, { kind: "component", type: DsMobileInlineTabsComponent, selector: "ds-mobile-inline-tabs", inputs: ["tabs", "activeTab"], outputs: ["tabChange"] }, { kind: "component", type: DsMobileListItemStaticComponent, selector: "ds-mobile-list-item-static", inputs: ["leadingSize"] }, { kind: "component", type: DsMobileInteractiveListItemMessageComponent, selector: "ds-mobile-interactive-list-item-message", inputs: ["senderName", "senderRole", "message", "avatarInitials", "avatarType", "avatarSrc", "unread", "clickable"], outputs: ["messageClick", "longPress"] }] });
|
|
11341
|
+
}
|
|
11342
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileInquiryDetailPageComponent, decorators: [{
|
|
11343
|
+
type: Component,
|
|
11344
|
+
args: [{ selector: 'app-mobile-inquiry-detail-page', standalone: true, imports: [
|
|
11345
|
+
CommonModule,
|
|
11346
|
+
IonHeader,
|
|
11347
|
+
IonToolbar,
|
|
11348
|
+
IonTitle,
|
|
11349
|
+
IonContent,
|
|
11350
|
+
IonRefresher,
|
|
11351
|
+
IonRefresherContent,
|
|
11352
|
+
DsIconComponent,
|
|
11353
|
+
DsAvatarComponent,
|
|
11354
|
+
DsMobileInlineTabsComponent,
|
|
11355
|
+
DsMobileListItemStaticComponent,
|
|
11356
|
+
DsMobileInteractiveListItemMessageComponent
|
|
11357
|
+
], host: {
|
|
11358
|
+
class: 'ion-page'
|
|
11359
|
+
}, template: `
|
|
11360
|
+
<!-- Fixed header at top -->
|
|
11361
|
+
<ion-header>
|
|
11362
|
+
<ion-toolbar>
|
|
11363
|
+
<div class="header-detail">
|
|
11364
|
+
<!-- Back Button -->
|
|
11365
|
+
<button class="back-button" (click)="goBack()" [attr.aria-label]="'Go back'">
|
|
11366
|
+
<ds-icon name="remixArrowLeftSLine" size="24px" color="white" />
|
|
11367
|
+
</button>
|
|
11368
|
+
|
|
11369
|
+
<!-- Title - fades in on scroll -->
|
|
11370
|
+
<ion-title class="header-detail__title">{{ inquiryTitle }}</ion-title>
|
|
11371
|
+
</div>
|
|
11372
|
+
</ion-toolbar>
|
|
11373
|
+
</ion-header>
|
|
11374
|
+
|
|
11375
|
+
<!-- Content with expandable header -->
|
|
11376
|
+
<ion-content [scrollEvents]="true" (ionScroll)="handleScroll($event)">
|
|
11377
|
+
<!-- Pull to refresh (only on native iOS/Android) -->
|
|
11378
|
+
@if (isNativePlatform()) {
|
|
11379
|
+
<ion-refresher
|
|
11380
|
+
slot="fixed"
|
|
11381
|
+
(ionRefresh)="handleRefresh($event)"
|
|
11382
|
+
[pullFactor]="0.4"
|
|
11383
|
+
[pullMin]="80"
|
|
11384
|
+
[pullMax]="240"
|
|
11385
|
+
closeDuration="600ms">
|
|
11386
|
+
<ion-refresher-content
|
|
11387
|
+
pullingIcon="remixArrowDownS"
|
|
11388
|
+
refreshingSpinner="lines">
|
|
11389
|
+
</ion-refresher-content>
|
|
11390
|
+
</ion-refresher>
|
|
11391
|
+
}
|
|
11392
|
+
|
|
11393
|
+
<!-- Expandable header section (purple background) -->
|
|
11394
|
+
<div class="header-expandable">
|
|
11395
|
+
<div class="header-expandable-inner">
|
|
11396
|
+
<div class="header-expandable__text">
|
|
11397
|
+
<h1 class="header-expandable__title">{{ inquiryTitle }}</h1>
|
|
11398
|
+
</div>
|
|
11399
|
+
|
|
11400
|
+
<!-- Tabs in header -->
|
|
11401
|
+
<ds-mobile-inline-tabs
|
|
11402
|
+
[tabs]="tabItems"
|
|
11403
|
+
[activeTab]="activeTab()"
|
|
11404
|
+
(tabChange)="setActiveTab($event)">
|
|
11405
|
+
</ds-mobile-inline-tabs>
|
|
11406
|
+
</div>
|
|
11407
|
+
</div>
|
|
11408
|
+
|
|
11409
|
+
<!-- Content wrapper -->
|
|
11410
|
+
<div class="content-wrapper">
|
|
11411
|
+
<div class="content-inner">
|
|
11412
|
+
<!-- Activity Tab Content -->
|
|
11413
|
+
@if (activeTab() === 'activity') {
|
|
11414
|
+
<div class="activity-list">
|
|
11415
|
+
@for (activity of activities; track activity.id) {
|
|
11416
|
+
<div class="activity-item">
|
|
11417
|
+
@if (activity.actor) {
|
|
11418
|
+
<!-- Avatar with badge for actor activities -->
|
|
11419
|
+
<div class="avatar-wrapper">
|
|
11420
|
+
<ds-avatar
|
|
11421
|
+
[type]="'initials'"
|
|
11422
|
+
[initials]="activity.actorInitials || ''"
|
|
11423
|
+
size="md" />
|
|
11424
|
+
|
|
11425
|
+
<div class="avatar-badge">
|
|
11426
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 32" fill="none">
|
|
11427
|
+
<path d="M33.9862 5.51709H23.1724V8.82743H26.0413C26.2841 8.82743 26.4827 9.02606 26.4827 9.26881V12.7998C26.4827 13.0426 26.2841 13.2412 26.0413 13.2412H23.1724V14.3447H26.0413C26.2841 14.3447 26.4827 14.5433 26.4827 14.7861V18.3171C26.4827 18.5598 26.2841 18.7585 26.0413 18.7585H23.1724V19.8619H26.0413C26.2841 19.8619 26.4827 20.0605 26.4827 20.3033V23.8343C26.4827 24.0771 26.2841 24.2757 26.0413 24.2757H23.1724V26.2619C23.1724 26.7496 23.0267 27.2043 22.7773 27.5861H27.5862L32 31.9999V27.5861H33.9862C34.7167 27.5861 35.3103 26.9924 35.3103 26.2619V6.84123C35.3103 6.11075 34.7167 5.51709 33.9862 5.51709ZM32 23.8343C32 24.0771 31.8013 24.2757 31.5586 24.2757H28.0276C27.7848 24.2757 27.5862 24.0771 27.5862 23.8343V20.3033C27.5862 20.0605 27.7848 19.8619 28.0276 19.8619H31.5586C31.8013 19.8619 32 20.0605 32 20.3033V23.8343ZM32 18.3171C32 18.5598 31.8013 18.7585 31.5586 18.7585H28.0276C27.7848 18.7585 27.5862 18.5598 27.5862 18.3171V14.7861C27.5862 14.5433 27.7848 14.3447 28.0276 14.3447H31.5586C31.8013 14.3447 32 14.5433 32 14.7861V18.3171ZM32 12.7998C32 13.0426 31.8013 13.2412 31.5586 13.2412H28.0276C27.7848 13.2412 27.5862 13.0426 27.5862 12.7998V9.26881C27.5862 9.02606 27.7848 8.82743 28.0276 8.82743H31.5586C31.8013 8.82743 32 9.02606 32 9.26881V12.7998Z" fill="white"/>
|
|
11428
|
+
<path d="M20.7448 0H1.32414C0.593655 0 0 0.593655 0 1.32414V26.2621C0 26.9926 0.593655 27.5862 1.32414 27.5862H3.31034V32L7.72414 27.5862H20.7448C21.4753 27.5862 22.069 26.9926 22.069 26.2621V1.32414C22.069 0.593655 21.4753 0 20.7448 0ZM7.72414 23.8345C7.72414 24.0772 7.52552 24.2759 7.28276 24.2759H3.75172C3.50897 24.2759 3.31034 24.0772 3.31034 23.8345V20.3034C3.31034 20.0607 3.50897 19.8621 3.75172 19.8621H7.28276C7.52552 19.8621 7.72414 20.0607 7.72414 20.3034V23.8345ZM7.72414 18.3172C7.72414 18.56 7.52552 18.7586 7.28276 18.7586H3.75172C3.50897 18.7586 3.31034 18.56 3.31034 18.3172V14.7862C3.31034 14.5434 3.50897 14.3448 3.75172 14.3448H7.28276C7.52552 14.3448 7.72414 14.5434 7.72414 14.7862V18.3172ZM7.72414 12.8C7.72414 13.0428 7.52552 13.2414 7.28276 13.2414H3.75172C3.50897 13.2414 3.31034 13.0428 3.31034 12.8V9.26897C3.31034 9.02621 3.50897 8.82759 3.75172 8.82759H7.28276C7.52552 8.82759 7.72414 9.02621 7.72414 9.26897V12.8ZM7.72414 7.28276C7.72414 7.52552 7.52552 7.72414 7.28276 7.72414H3.75172C3.50897 7.72414 3.31034 7.52552 3.31034 7.28276V3.75172C3.31034 3.50897 3.50897 3.31034 3.75172 3.31034H7.28276C7.52552 3.31034 7.72414 3.50897 7.72414 3.75172V7.28276ZM13.2414 23.8345C13.2414 24.0772 13.0428 24.2759 12.8 24.2759H9.26897C9.02621 24.2759 8.82759 24.0772 8.82759 23.8345V20.3034C8.82759 20.0607 9.02621 19.8621 9.26897 19.8621H12.8C13.0428 19.8621 13.2414 20.0607 13.2414 20.3034V23.8345ZM13.2414 18.3172C13.2414 18.56 13.0428 18.7586 12.8 18.7586H9.26897C9.02621 18.7586 8.82759 18.56 8.82759 18.3172V14.7862C8.82759 14.5434 9.02621 14.3448 9.26897 14.3448H12.8C13.0428 14.3448 13.2414 14.5434 13.2414 14.7862V18.3172ZM13.2414 12.8C13.2414 13.0428 13.0428 13.2414 12.8 13.2414H9.26897C9.02621 13.2414 8.82759 13.0428 8.82759 12.8V9.26897C8.82759 9.02621 9.02621 8.82759 9.26897 8.82759H12.8C13.0428 8.82759 13.2414 9.02621 13.2414 9.26897V12.8ZM13.2414 6.84138V7.28276C13.2414 7.52552 13.0428 7.72414 12.8 7.72414H9.26897C9.02621 7.72414 8.82759 7.52552 8.82759 7.28276V3.75172C8.82759 3.50897 9.02621 3.31034 9.26897 3.31034H12.8C13.0428 3.31034 13.2414 3.50897 13.2414 3.75172V6.84138ZM18.7586 23.8345C18.7586 24.0772 18.56 24.2759 18.3172 24.2759H14.7862C14.5434 24.2759 14.3448 24.0772 14.3448 23.8345V20.3034C14.3448 20.0607 14.5434 19.8621 14.7862 19.8621H18.3172C18.56 19.8621 18.7586 20.0607 18.7586 20.3034V23.8345ZM18.7586 18.3172C18.7586 18.56 18.56 18.7586 18.3172 18.7586H14.7862C14.5434 18.7586 14.3448 18.56 14.3448 18.3172V14.7862C14.3448 14.5434 14.5434 14.3448 14.7862 14.3448H18.3172C18.56 14.3448 18.7586 14.5434 18.7586 14.7862V18.3172ZM18.7586 12.8C18.7586 13.0428 18.56 13.2414 18.3172 13.2414H14.7862C14.5434 13.2414 14.3448 13.0428 14.3448 12.8V9.26897C14.3448 9.02621 14.5434 8.82759 14.7862 8.82759H18.3172C18.56 8.82759 18.7586 9.02621 18.7586 9.26897V12.8ZM18.7586 5.51724V7.28276C18.7586 7.52552 18.56 7.72414 18.3172 7.72414H14.7862C14.5434 7.72414 14.3448 7.52552 14.3448 7.28276V3.75172C14.3448 3.50897 14.5434 3.31034 14.7862 3.31034H18.3172C18.56 3.31034 18.7586 3.50897 18.7586 3.75172V5.51724Z" fill="white"/>
|
|
11429
|
+
</svg>
|
|
11430
|
+
</div>
|
|
11431
|
+
</div>
|
|
11432
|
+
} @else {
|
|
11433
|
+
<!-- Icon wrapper for non-actor activities -->
|
|
11434
|
+
<div class="activity-icon-wrapper">
|
|
11435
|
+
<ds-icon
|
|
11436
|
+
[name]="activity.iconName"
|
|
11437
|
+
size="18px"
|
|
11438
|
+
color="secondary" />
|
|
11439
|
+
</div>
|
|
11440
|
+
}
|
|
11441
|
+
|
|
11442
|
+
<div class="activity-content">
|
|
11443
|
+
<p class="activity-title">
|
|
11444
|
+
@if (activity.actor) {
|
|
11445
|
+
<span class="actor-name">{{ activity.actor }}</span>
|
|
11446
|
+
<span class="activity-text"> {{ activity.title }}</span>
|
|
11447
|
+
} @else {
|
|
11448
|
+
<span class="actor-name">{{ activity.title }}</span>
|
|
11449
|
+
}
|
|
11450
|
+
</p>
|
|
11451
|
+
@if (activity.description) {
|
|
11452
|
+
<p class="activity-description">{{ activity.description }}</p>
|
|
11453
|
+
}
|
|
11454
|
+
<div class="activity-timestamp">
|
|
11455
|
+
<ds-icon name="remixCalendarLine" size="12px" color="--color-text-tertiary" />
|
|
11456
|
+
<span>{{ activity.date }}</span>
|
|
11457
|
+
</div>
|
|
11458
|
+
</div>
|
|
11459
|
+
</div>
|
|
11460
|
+
}
|
|
11461
|
+
</div>
|
|
11462
|
+
}
|
|
11463
|
+
|
|
11464
|
+
<!-- Messages Tab Content -->
|
|
11465
|
+
@if (activeTab() === 'messages') {
|
|
11466
|
+
<div class="messages-list">
|
|
11467
|
+
@for (message of messageThreads; track message.id) {
|
|
11468
|
+
<ds-mobile-interactive-list-item-message
|
|
11469
|
+
[senderName]="message.senderName"
|
|
11470
|
+
[senderRole]="message.role"
|
|
11471
|
+
[message]="message.message"
|
|
11472
|
+
[avatarInitials]="message.senderInitials"
|
|
11473
|
+
[unread]="message.unread"
|
|
11474
|
+
(messageClick)="openMessage(message.id)">
|
|
11475
|
+
</ds-mobile-interactive-list-item-message>
|
|
11476
|
+
}
|
|
11477
|
+
</div>
|
|
11478
|
+
}
|
|
11479
|
+
|
|
11480
|
+
<!-- Details Tab Content -->
|
|
11481
|
+
@if (activeTab() === 'details') {
|
|
11482
|
+
<div class="details-list">
|
|
11483
|
+
<!-- Assignee -->
|
|
11484
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11485
|
+
<div content-leading>
|
|
11486
|
+
<ds-avatar
|
|
11487
|
+
[size]="'sm'"
|
|
11488
|
+
[type]="'initials'"
|
|
11489
|
+
[initials]="'R'" />
|
|
11490
|
+
</div>
|
|
11491
|
+
<div content-main>
|
|
11492
|
+
<div class="detail-label">Sagsbehandler</div>
|
|
11493
|
+
<div class="detail-value">Ricki Meihlen</div>
|
|
11494
|
+
</div>
|
|
11495
|
+
</ds-mobile-list-item-static>
|
|
11496
|
+
|
|
11497
|
+
<!-- Technician -->
|
|
11498
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11499
|
+
<div content-leading>
|
|
11500
|
+
<ds-avatar
|
|
11501
|
+
[size]="'sm'"
|
|
11502
|
+
[type]="'initials'"
|
|
11503
|
+
[initials]="'M'" />
|
|
11504
|
+
</div>
|
|
11505
|
+
<div content-main>
|
|
11506
|
+
<div class="detail-label">Tekniker</div>
|
|
11507
|
+
<div class="detail-value">Martin Smith</div>
|
|
11508
|
+
</div>
|
|
11509
|
+
</ds-mobile-list-item-static>
|
|
11510
|
+
|
|
11511
|
+
<!-- Title -->
|
|
11512
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11513
|
+
<div content-leading>
|
|
11514
|
+
<ds-icon name="remixTextBlock" size="20px" color="tertiary" />
|
|
11515
|
+
</div>
|
|
11516
|
+
<div content-main>
|
|
11517
|
+
<div class="detail-value">{{ inquiryTitle }}</div>
|
|
11518
|
+
</div>
|
|
11519
|
+
</ds-mobile-list-item-static>
|
|
11520
|
+
|
|
11521
|
+
<!-- Description -->
|
|
11522
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11523
|
+
<div content-leading>
|
|
11524
|
+
<ds-icon name="remixAlignLeft" size="20px" color="tertiary" />
|
|
11525
|
+
</div>
|
|
11526
|
+
<div content-main>
|
|
11527
|
+
<div class="detail-value description-text">
|
|
11528
|
+
I de sidste tre dage har vi oplevet vedvarende problemer med tørretumbleren i vores lejlighed. På trods af at vi følger betjeningsvejledningen, fejler maskinen konsekvent i at fuldføre sine tørrecyklusser.
|
|
11529
|
+
</div>
|
|
11530
|
+
<div class="detail-tag">Husholdningsapparater</div>
|
|
11531
|
+
</div>
|
|
11532
|
+
</ds-mobile-list-item-static>
|
|
11533
|
+
|
|
11534
|
+
<!-- Photos -->
|
|
11535
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11536
|
+
<div content-leading>
|
|
11537
|
+
<ds-icon name="remixCameraLine" size="20px" color="tertiary" />
|
|
11538
|
+
</div>
|
|
11539
|
+
<div content-main>
|
|
11540
|
+
<div class="photo-grid">
|
|
11541
|
+
<button class="photo-add">
|
|
11542
|
+
<ds-icon name="remixAddLine" size="20px" color="tertiary" />
|
|
11543
|
+
</button>
|
|
11544
|
+
<!-- Placeholder photos -->
|
|
11545
|
+
<div class="photo-item"></div>
|
|
11546
|
+
<div class="photo-item"></div>
|
|
11547
|
+
<div class="photo-item"></div>
|
|
11548
|
+
<div class="photo-item"></div>
|
|
11549
|
+
</div>
|
|
11550
|
+
</div>
|
|
11551
|
+
</ds-mobile-list-item-static>
|
|
11552
|
+
</div>
|
|
11553
|
+
}
|
|
11554
|
+
</div>
|
|
11555
|
+
</div>
|
|
11556
|
+
</ion-content>
|
|
11557
|
+
`, styles: ["ion-header{--background: var(--color-brand-secondary, #5d5fef);height:72px;min-height:72px}ion-toolbar{--background: var(--color-brand-secondary, #5d5fef);--color: white;--padding-top: 0;--padding-bottom: 0;--padding-start: 0;--padding-end: 0;--min-height: 72px;height:100%;min-height:72px}ion-toolbar ion-title{transition:transform .2s ease,opacity .2s ease!important}.header-detail{display:flex;align-items:center;gap:12px;padding:0 20px;height:100%}.back-button{width:36px;height:36px;border-radius:50%;background:#ffffff1a;border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .2s ease;color:#fff;padding:0;flex-shrink:0}.back-button:hover,.back-button:active{background:#ffffff26}.header-detail__title{position:absolute;left:64px;transform:translateY(-100%);font-size:var(--font-size-base);font-weight:600;color:#fff;opacity:0!important;pointer-events:none;transition:transform .2s ease,opacity .2s ease!important;margin:0;padding:0;--color: white;text-align:left!important}.header-scrolled .header-detail__title{opacity:1!important;pointer-events:auto;transform:translateY(0)}@media (min-width: 768px){.header-detail{padding:16px 24px}}ion-content{--background: var(--color-brand-secondary);--padding-top: 0;--padding-start: 0;--padding-end: 0;--padding-bottom: 0;border-radius:24px 24px 0 0;overflow:hidden}.plt-ios ion-content{--background: var(--color-background-neutral-primary)}@media (min-width: 768px){ion-content{border-radius:24px 24px 0 0}}ion-content::part(scroll){-webkit-overflow-scrolling:touch;display:flex;flex-direction:column}ion-refresher{z-index:0}ion-refresher-content{--color: white}.header-expandable{background:var(--color-brand-secondary);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}.header-expandable-inner{display:flex;flex-direction:column;gap:20px;max-width:640px}.header-expandable__text{margin-bottom:0}@media (min-width: 768px){.header-expandable{padding:40px var(--content-padding-md) 32px var(--content-padding-md)}}@media (min-width: 992px){.header-expandable{padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg)}}@media (min-width: 1440px){.header-expandable{padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.header-expandable{padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.header-expandable{padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}.content-wrapper{background:var(--color-background-neutral-primary, white);border-radius:24px 24px 0 0;flex:1 1 auto;min-height:100%;position:relative;z-index:10;box-shadow:0 200vh 0 0 var(--color-background-neutral-primary)}.content-inner{padding:24px 20px 40px}@media (min-width: 768px){.content-inner{padding:32px}}.activity-list{display:flex;flex-direction:column;gap:32px}.activity-item{display:flex;gap:12px;position:relative}.activity-item:after{content:\"\";position:absolute;bottom:-16px;left:44px;right:8px;height:1px;background:var(--border-color-default, #e5e5e5)}.activity-item:last-child:after{display:none}.activity-icon-wrapper{width:32px;height:32px;border-radius:8px;background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;flex-shrink:0}.avatar-wrapper{position:relative;display:flex;align-items:start;justify-content:center;flex-shrink:0;width:32px;height:32px}.avatar-badge{position:absolute;bottom:-6px;right:-6px;width:20px;height:20px;border-radius:8px;background:var(--color-brand-secondary, #5d5fef);display:flex;align-items:center;justify-content:center;border:2px solid var(--color-background-primary, #ffffff)}.avatar-badge svg{width:10px;position:relative;top:1px;fill:#fff}.activity-content{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.activity-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0}.activity-title .actor-name{font-weight:600;color:var(--text-color-default-primary, #202227)}.activity-title .activity-text{color:var(--text-color-default-secondary, #545B66);font-weight:400}.activity-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0}.activity-timestamp{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373);display:flex;align-items:center;gap:4px;margin-top:2px}.messages-list{display:flex;flex-direction:column;gap:8px;margin:-8px}.details-list{display:flex;flex-direction:column;gap:20px}.detail-label{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-tertiary, #737373)}.detail-value{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:24px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227)}.detail-value.description-text{padding:8px 0}.detail-tag{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;background:var(--color-background-neutral-secondary, #f5f5f5);font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;color:var(--text-color-default-secondary, #525866);margin-top:4px;margin-bottom:10px;width:-moz-fit-content;width:fit-content}.photo-grid{display:flex;gap:8px;margin-top:8px;overflow-x:auto}.photo-add{width:80px;height:80px;border-radius:12px;border:1px dashed var(--border-color-default, #e5e5e5);background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;cursor:pointer;flex-shrink:0}.photo-item{width:80px;height:80px;border-radius:12px;background:var(--color-background-neutral-secondary, #e5e5e5);flex-shrink:0}\n"] }]
|
|
11558
|
+
}], ctorParameters: () => [{ type: UserService }, { type: i1.NavController }, { type: i0.ElementRef }], propDecorators: { ionContent: [{
|
|
11559
|
+
type: ViewChild,
|
|
11560
|
+
args: [IonContent]
|
|
11561
|
+
}] } });
|
|
11562
|
+
|
|
11563
|
+
/**
|
|
11564
|
+
* DsAvatarWithBadgeComponent
|
|
11565
|
+
*
|
|
11566
|
+
* Displays an avatar with a logomark badge overlay.
|
|
11567
|
+
* Useful for showing user avatars with organization branding.
|
|
11568
|
+
*
|
|
11569
|
+
* @example
|
|
11570
|
+
* ```html
|
|
11571
|
+
* <ds-avatar-with-badge
|
|
11572
|
+
* [type]="'initials'"
|
|
11573
|
+
* [initials]="'JD'"
|
|
11574
|
+
* [size]="'lg'"
|
|
11575
|
+
* [badgePosition]="'bottom-right'"
|
|
11576
|
+
* />
|
|
11577
|
+
* ```
|
|
11578
|
+
*/
|
|
11579
|
+
class DsAvatarWithBadgeComponent {
|
|
11580
|
+
whitelabelService = inject(WhitelabelService);
|
|
11581
|
+
// Avatar props
|
|
11582
|
+
type = 'initials';
|
|
11583
|
+
size = 'md';
|
|
11584
|
+
initials = '';
|
|
11585
|
+
src = '';
|
|
11586
|
+
iconName = 'remixUser3Fill';
|
|
11587
|
+
// Badge props
|
|
11588
|
+
showBadge = true;
|
|
11589
|
+
badgePosition = 'bottom-right';
|
|
11590
|
+
badgeClasses = computed(() => {
|
|
11591
|
+
return `avatar-badge avatar-badge--${this.badgePosition} avatar-badge--${this.size}`;
|
|
11592
|
+
}, ...(ngDevMode ? [{ debugName: "badgeClasses" }] : []));
|
|
11593
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsAvatarWithBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11594
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: DsAvatarWithBadgeComponent, isStandalone: true, selector: "ds-avatar-with-badge", inputs: { type: "type", size: "size", initials: "initials", src: "src", iconName: "iconName", showBadge: "showBadge", badgePosition: "badgePosition" }, ngImport: i0, template: `
|
|
11595
|
+
<div class="avatar-badge-container">
|
|
11596
|
+
<ds-avatar
|
|
11597
|
+
[type]="type"
|
|
11598
|
+
[size]="size"
|
|
11599
|
+
[initials]="initials"
|
|
11600
|
+
[src]="src"
|
|
11601
|
+
[iconName]="iconName"
|
|
11602
|
+
/>
|
|
11603
|
+
|
|
11604
|
+
@if (showBadge) {
|
|
11605
|
+
<div [class]="badgeClasses()">
|
|
11606
|
+
<img [src]="whitelabelService.logoMarkUrl()" [alt]="whitelabelService.logoAlt()" />
|
|
11607
|
+
</div>
|
|
11608
|
+
}
|
|
11609
|
+
</div>
|
|
11610
|
+
`, isInline: true, styles: [":host{display:inline-block;position:relative}.avatar-badge-container{position:relative;display:inline-block}.avatar-badge{position:absolute;background:var(--color-brand-secondary, #5d5fef);border-radius:8px;display:flex;align-items:center;justify-content:center;border:2px solid var(--color-background-primary, #ffffff)}.avatar-badge img{width:10px;height:10px;object-fit:contain}.avatar-badge--bottom-right{bottom:-6px;right:-6px}.avatar-badge--bottom-left{bottom:-6px;left:-6px}.avatar-badge--top-right{top:-6px;right:-6px}.avatar-badge--top-left{top:-6px;left:-6px}.avatar-badge--xs{width:16px;height:16px}.avatar-badge--sm{width:18px;height:18px}.avatar-badge--md{width:20px;height:20px}.avatar-badge--lg{width:24px;height:24px}.avatar-badge--xl{width:28px;height:28px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }] });
|
|
11611
|
+
}
|
|
11612
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsAvatarWithBadgeComponent, decorators: [{
|
|
11613
|
+
type: Component,
|
|
11614
|
+
args: [{ selector: 'ds-avatar-with-badge', standalone: true, imports: [CommonModule, DsAvatarComponent], encapsulation: ViewEncapsulation.Emulated, template: `
|
|
11615
|
+
<div class="avatar-badge-container">
|
|
11616
|
+
<ds-avatar
|
|
11617
|
+
[type]="type"
|
|
11618
|
+
[size]="size"
|
|
11619
|
+
[initials]="initials"
|
|
11620
|
+
[src]="src"
|
|
11621
|
+
[iconName]="iconName"
|
|
11622
|
+
/>
|
|
11623
|
+
|
|
11624
|
+
@if (showBadge) {
|
|
11625
|
+
<div [class]="badgeClasses()">
|
|
11626
|
+
<img [src]="whitelabelService.logoMarkUrl()" [alt]="whitelabelService.logoAlt()" />
|
|
11566
11627
|
</div>
|
|
11567
|
-
|
|
11568
|
-
</
|
|
11569
|
-
`, styles: ["
|
|
11570
|
-
}],
|
|
11628
|
+
}
|
|
11629
|
+
</div>
|
|
11630
|
+
`, styles: [":host{display:inline-block;position:relative}.avatar-badge-container{position:relative;display:inline-block}.avatar-badge{position:absolute;background:var(--color-brand-secondary, #5d5fef);border-radius:8px;display:flex;align-items:center;justify-content:center;border:2px solid var(--color-background-primary, #ffffff)}.avatar-badge img{width:10px;height:10px;object-fit:contain}.avatar-badge--bottom-right{bottom:-6px;right:-6px}.avatar-badge--bottom-left{bottom:-6px;left:-6px}.avatar-badge--top-right{top:-6px;right:-6px}.avatar-badge--top-left{top:-6px;left:-6px}.avatar-badge--xs{width:16px;height:16px}.avatar-badge--sm{width:18px;height:18px}.avatar-badge--md{width:20px;height:20px}.avatar-badge--lg{width:24px;height:24px}.avatar-badge--xl{width:28px;height:28px}\n"] }]
|
|
11631
|
+
}], propDecorators: { type: [{
|
|
11632
|
+
type: Input
|
|
11633
|
+
}], size: [{
|
|
11634
|
+
type: Input
|
|
11635
|
+
}], initials: [{
|
|
11636
|
+
type: Input
|
|
11637
|
+
}], src: [{
|
|
11638
|
+
type: Input
|
|
11639
|
+
}], iconName: [{
|
|
11640
|
+
type: Input
|
|
11641
|
+
}], showBadge: [{
|
|
11642
|
+
type: Input
|
|
11643
|
+
}], badgePosition: [{
|
|
11644
|
+
type: Input
|
|
11645
|
+
}] } });
|
|
11571
11646
|
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
iconName: 'remixUserAddLine'
|
|
11600
|
-
},
|
|
11601
|
-
{
|
|
11602
|
-
id: '2',
|
|
11603
|
-
type: 'assignment',
|
|
11604
|
-
actor: 'Ricki Meihlen',
|
|
11605
|
-
actorInitials: 'RM',
|
|
11606
|
-
title: 'er blevet tildelt til at håndtere din henvendelse.',
|
|
11607
|
-
timestamp: '8 dage siden',
|
|
11608
|
-
date: '22. feb 2025',
|
|
11609
|
-
iconName: 'remixUserLine'
|
|
11610
|
-
},
|
|
11611
|
-
{
|
|
11612
|
-
id: '3',
|
|
11613
|
-
type: 'creation',
|
|
11614
|
-
title: 'Henvendelse oprettet',
|
|
11615
|
-
timestamp: '8 dage siden',
|
|
11616
|
-
date: '22. feb 2025',
|
|
11617
|
-
iconName: 'remixAddCircleLine'
|
|
11647
|
+
/**
|
|
11648
|
+
* Whitelabel Demo Modal Component
|
|
11649
|
+
*
|
|
11650
|
+
* Demonstrates the whitelabeling system with theme selection, brand colors, and logo previews.
|
|
11651
|
+
* Opens as a full-screen modal similar to post details.
|
|
11652
|
+
*/
|
|
11653
|
+
class WhitelabelDemoModalComponent {
|
|
11654
|
+
whitelabelService = inject(WhitelabelService);
|
|
11655
|
+
modalController = inject(ModalController);
|
|
11656
|
+
// Current active theme
|
|
11657
|
+
currentTheme = 'default';
|
|
11658
|
+
// Custom color inputs
|
|
11659
|
+
customPrimarySurface = '#6B5FF5';
|
|
11660
|
+
customPrimaryContent = '#FFFFFF';
|
|
11661
|
+
customSecondarySurface = '#221a4c';
|
|
11662
|
+
customSecondaryContent = '#FFFFFF';
|
|
11663
|
+
ngOnInit() {
|
|
11664
|
+
this.updateCustomColorInputs();
|
|
11665
|
+
this.detectCurrentTheme();
|
|
11666
|
+
}
|
|
11667
|
+
/**
|
|
11668
|
+
* Detect the current active theme based on colors
|
|
11669
|
+
*/
|
|
11670
|
+
detectCurrentTheme() {
|
|
11671
|
+
const secondarySurface = this.whitelabelService.secondarySurface().toUpperCase();
|
|
11672
|
+
if (secondarySurface === '#A70923') {
|
|
11673
|
+
this.currentTheme = 'cej';
|
|
11618
11674
|
}
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
{
|
|
11622
|
-
id: '1',
|
|
11623
|
-
senderName: 'Ove Hindborg',
|
|
11624
|
-
senderAvatar: '',
|
|
11625
|
-
senderInitials: 'OH',
|
|
11626
|
-
message: 'Dejligt at høre! Jeg venter på din teknikerbesøg tidsplan.',
|
|
11627
|
-
role: 'Sagsbehandler',
|
|
11628
|
-
timestamp: '2t siden',
|
|
11629
|
-
unread: true
|
|
11630
|
-
},
|
|
11631
|
-
{
|
|
11632
|
-
id: '2',
|
|
11633
|
-
senderName: 'Martin Smith',
|
|
11634
|
-
senderAvatar: '',
|
|
11635
|
-
senderInitials: 'MS',
|
|
11636
|
-
message: 'Dejligt at høre! Jeg venter på din teknikerbesøg tidsplan.',
|
|
11637
|
-
role: 'Tekniker',
|
|
11638
|
-
timestamp: '4t siden',
|
|
11639
|
-
unread: true
|
|
11675
|
+
else if (secondarySurface === '#660036') {
|
|
11676
|
+
this.currentTheme = 'pka';
|
|
11640
11677
|
}
|
|
11641
|
-
|
|
11642
|
-
|
|
11643
|
-
|
|
11644
|
-
|
|
11645
|
-
|
|
11646
|
-
if (messagesTab) {
|
|
11647
|
-
messagesTab.badge = count;
|
|
11678
|
+
else if (secondarySurface === '#262424') {
|
|
11679
|
+
this.currentTheme = 'clave';
|
|
11680
|
+
}
|
|
11681
|
+
else {
|
|
11682
|
+
this.currentTheme = 'default';
|
|
11648
11683
|
}
|
|
11649
|
-
return count;
|
|
11650
|
-
}, ...(ngDevMode ? [{ debugName: "unreadMessagesCount" }] : []));
|
|
11651
|
-
constructor(userService, navCtrl, elementRef) {
|
|
11652
|
-
super();
|
|
11653
|
-
this.userService = userService;
|
|
11654
|
-
this.navCtrl = navCtrl;
|
|
11655
|
-
this.elementRef = elementRef;
|
|
11656
|
-
// Trigger initial badge update
|
|
11657
|
-
this.unreadMessagesCount();
|
|
11658
11684
|
}
|
|
11659
|
-
|
|
11660
|
-
|
|
11685
|
+
/**
|
|
11686
|
+
* Close the modal
|
|
11687
|
+
*/
|
|
11688
|
+
close() {
|
|
11689
|
+
this.modalController.dismiss();
|
|
11661
11690
|
}
|
|
11662
|
-
|
|
11663
|
-
this.
|
|
11691
|
+
applyDefaultTheme() {
|
|
11692
|
+
this.currentTheme = 'default';
|
|
11693
|
+
this.whitelabelService.updateConfig({
|
|
11694
|
+
logoUrl: '/Assets/logos/propbinder-logomark.svg',
|
|
11695
|
+
logoMarkUrl: '/Assets/logos/propbinder-logomark.svg',
|
|
11696
|
+
logoAlt: 'Propbinder',
|
|
11697
|
+
logoHeight: 28,
|
|
11698
|
+
primarySurface: '#6B5FF5',
|
|
11699
|
+
primaryContent: '#FFFFFF',
|
|
11700
|
+
secondarySurface: '#221a4c',
|
|
11701
|
+
secondaryContent: '#FFFFFF',
|
|
11702
|
+
organizationName: 'Propbinder',
|
|
11703
|
+
organizationId: 'default'
|
|
11704
|
+
});
|
|
11705
|
+
this.updateCustomColorInputs();
|
|
11664
11706
|
}
|
|
11665
|
-
|
|
11666
|
-
this.
|
|
11707
|
+
applyCejTheme() {
|
|
11708
|
+
this.currentTheme = 'cej';
|
|
11709
|
+
this.whitelabelService.updateConfig({
|
|
11710
|
+
logoUrl: '/Assets/logos/cej-logo.png',
|
|
11711
|
+
logoMarkUrl: '/Assets/logos/cej-logo.png',
|
|
11712
|
+
logoAlt: 'CEJ',
|
|
11713
|
+
logoHeight: 36,
|
|
11714
|
+
primarySurface: '#FFFFFF',
|
|
11715
|
+
primaryContent: '#A70923',
|
|
11716
|
+
secondarySurface: '#A70923',
|
|
11717
|
+
secondaryContent: '#FFFFFF',
|
|
11718
|
+
organizationName: 'CEJ',
|
|
11719
|
+
organizationId: 'cej'
|
|
11720
|
+
});
|
|
11721
|
+
this.updateCustomColorInputs();
|
|
11667
11722
|
}
|
|
11668
|
-
|
|
11669
|
-
|
|
11670
|
-
|
|
11671
|
-
|
|
11672
|
-
|
|
11673
|
-
|
|
11674
|
-
|
|
11675
|
-
|
|
11676
|
-
|
|
11677
|
-
|
|
11678
|
-
|
|
11679
|
-
|
|
11680
|
-
|
|
11681
|
-
|
|
11682
|
-
|
|
11683
|
-
const fadeProgress = Math.min(scrollTop / fadeDistance, 1);
|
|
11684
|
-
// Calculate opacity (1 to 0)
|
|
11685
|
-
const opacity = 1 - fadeProgress;
|
|
11686
|
-
// Calculate transform (0px to -20px upward)
|
|
11687
|
-
const translateY = fadeProgress * -20;
|
|
11688
|
-
// Apply styles
|
|
11689
|
-
headerExpandable.style.opacity = opacity.toString();
|
|
11690
|
-
headerExpandable.style.transform = `translateY(${translateY}px)`;
|
|
11691
|
-
}
|
|
11723
|
+
applyPkaTheme() {
|
|
11724
|
+
this.currentTheme = 'pka';
|
|
11725
|
+
this.whitelabelService.updateConfig({
|
|
11726
|
+
logoUrl: '/Assets/logos/pka-logo.svg',
|
|
11727
|
+
logoMarkUrl: '/Assets/logos/pka-logo.svg',
|
|
11728
|
+
logoAlt: 'PKA',
|
|
11729
|
+
logoHeight: 24,
|
|
11730
|
+
primarySurface: '#CC006C',
|
|
11731
|
+
primaryContent: '#FFFFFF',
|
|
11732
|
+
secondarySurface: '#660036',
|
|
11733
|
+
secondaryContent: '#FFFFFF',
|
|
11734
|
+
organizationName: 'PKA',
|
|
11735
|
+
organizationId: 'pka'
|
|
11736
|
+
});
|
|
11737
|
+
this.updateCustomColorInputs();
|
|
11692
11738
|
}
|
|
11693
|
-
|
|
11694
|
-
|
|
11695
|
-
|
|
11696
|
-
|
|
11697
|
-
|
|
11698
|
-
|
|
11739
|
+
applyClaveTheme() {
|
|
11740
|
+
this.currentTheme = 'clave';
|
|
11741
|
+
this.whitelabelService.updateConfig({
|
|
11742
|
+
logoUrl: '/Assets/logos/clave-logo.svg',
|
|
11743
|
+
logoMarkUrl: '/Assets/logos/clave-logo.svg',
|
|
11744
|
+
logoAlt: 'Clave',
|
|
11745
|
+
logoHeight: 24,
|
|
11746
|
+
primarySurface: '#868764',
|
|
11747
|
+
primaryContent: '#262424',
|
|
11748
|
+
secondarySurface: '#262424',
|
|
11749
|
+
secondaryContent: '#FFFFFF',
|
|
11750
|
+
organizationName: 'Clave',
|
|
11751
|
+
organizationId: 'clave'
|
|
11752
|
+
});
|
|
11753
|
+
this.updateCustomColorInputs();
|
|
11699
11754
|
}
|
|
11700
|
-
|
|
11701
|
-
|
|
11702
|
-
|
|
11755
|
+
applyCustomColors() {
|
|
11756
|
+
this.whitelabelService.updateColors({
|
|
11757
|
+
primarySurface: this.customPrimarySurface,
|
|
11758
|
+
primaryContent: this.customPrimaryContent,
|
|
11759
|
+
secondarySurface: this.customSecondarySurface,
|
|
11760
|
+
secondaryContent: this.customSecondaryContent
|
|
11761
|
+
});
|
|
11703
11762
|
}
|
|
11704
|
-
|
|
11705
|
-
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
|
|
11712
|
-
|
|
11713
|
-
|
|
11714
|
-
|
|
11715
|
-
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
|
|
11723
|
-
|
|
11724
|
-
@if (isNativePlatform()) {
|
|
11725
|
-
<ion-refresher
|
|
11726
|
-
slot="fixed"
|
|
11727
|
-
(ionRefresh)="handleRefresh($event)"
|
|
11728
|
-
[pullFactor]="0.4"
|
|
11729
|
-
[pullMin]="80"
|
|
11730
|
-
[pullMax]="240"
|
|
11731
|
-
closeDuration="600ms">
|
|
11732
|
-
<ion-refresher-content
|
|
11733
|
-
pullingIcon="remixArrowDownS"
|
|
11734
|
-
refreshingSpinner="lines">
|
|
11735
|
-
</ion-refresher-content>
|
|
11736
|
-
</ion-refresher>
|
|
11737
|
-
}
|
|
11738
|
-
|
|
11739
|
-
<!-- Expandable header section (purple background) -->
|
|
11740
|
-
<div class="header-expandable">
|
|
11741
|
-
<div class="header-expandable-inner">
|
|
11742
|
-
<div class="header-expandable__text">
|
|
11743
|
-
<h1 class="header-expandable__title">{{ inquiryTitle }}</h1>
|
|
11744
|
-
</div>
|
|
11745
|
-
|
|
11746
|
-
<!-- Tabs in header -->
|
|
11747
|
-
<ds-mobile-inline-tabs
|
|
11748
|
-
[tabs]="tabItems"
|
|
11749
|
-
[activeTab]="activeTab()"
|
|
11750
|
-
(tabChange)="setActiveTab($event)">
|
|
11751
|
-
</ds-mobile-inline-tabs>
|
|
11752
|
-
</div>
|
|
11763
|
+
updateCustomColorInputs() {
|
|
11764
|
+
this.customPrimarySurface = this.whitelabelService.primarySurface();
|
|
11765
|
+
this.customPrimaryContent = this.whitelabelService.primaryContent();
|
|
11766
|
+
this.customSecondarySurface = this.whitelabelService.secondarySurface();
|
|
11767
|
+
this.customSecondaryContent = this.whitelabelService.secondaryContent();
|
|
11768
|
+
}
|
|
11769
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11770
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: WhitelabelDemoModalComponent, isStandalone: true, selector: "ds-whitelabel-demo-modal", ngImport: i0, template: `
|
|
11771
|
+
<!-- Fixed Header -->
|
|
11772
|
+
<div class="modal-header">
|
|
11773
|
+
<div class="header-content">
|
|
11774
|
+
<span class="header-title">Whitelabel</span>
|
|
11775
|
+
<ds-icon-button
|
|
11776
|
+
icon="remixCloseLine"
|
|
11777
|
+
variant="secondary"
|
|
11778
|
+
size="lg"
|
|
11779
|
+
(click)="close()"
|
|
11780
|
+
class="close-button"
|
|
11781
|
+
aria-label="Close">
|
|
11782
|
+
</ds-icon-button>
|
|
11753
11783
|
</div>
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11771
|
-
|
|
11772
|
-
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
</svg>
|
|
11776
|
-
</div>
|
|
11777
|
-
</div>
|
|
11778
|
-
} @else {
|
|
11779
|
-
<!-- Icon wrapper for non-actor activities -->
|
|
11780
|
-
<div class="activity-icon-wrapper">
|
|
11781
|
-
<ds-icon
|
|
11782
|
-
[name]="activity.iconName"
|
|
11783
|
-
size="18px"
|
|
11784
|
-
color="secondary" />
|
|
11785
|
-
</div>
|
|
11786
|
-
}
|
|
11787
|
-
|
|
11788
|
-
<div class="activity-content">
|
|
11789
|
-
<p class="activity-title">
|
|
11790
|
-
@if (activity.actor) {
|
|
11791
|
-
<span class="actor-name">{{ activity.actor }}</span>
|
|
11792
|
-
<span class="activity-text"> {{ activity.title }}</span>
|
|
11793
|
-
} @else {
|
|
11794
|
-
<span class="actor-name">{{ activity.title }}</span>
|
|
11795
|
-
}
|
|
11796
|
-
</p>
|
|
11797
|
-
@if (activity.description) {
|
|
11798
|
-
<p class="activity-description">{{ activity.description }}</p>
|
|
11799
|
-
}
|
|
11800
|
-
<div class="activity-timestamp">
|
|
11801
|
-
<ds-icon name="remixCalendarLine" size="12px" color="--color-text-tertiary" />
|
|
11802
|
-
<span>{{ activity.date }}</span>
|
|
11803
|
-
</div>
|
|
11804
|
-
</div>
|
|
11805
|
-
</div>
|
|
11806
|
-
}
|
|
11807
|
-
</div>
|
|
11808
|
-
}
|
|
11809
|
-
|
|
11810
|
-
<!-- Messages Tab Content -->
|
|
11811
|
-
@if (activeTab() === 'messages') {
|
|
11812
|
-
<div class="messages-list">
|
|
11813
|
-
@for (message of messageThreads; track message.id) {
|
|
11814
|
-
<ds-mobile-interactive-list-item-message
|
|
11815
|
-
[senderName]="message.senderName"
|
|
11816
|
-
[senderRole]="message.role"
|
|
11817
|
-
[message]="message.message"
|
|
11818
|
-
[avatarInitials]="message.senderInitials"
|
|
11819
|
-
[unread]="message.unread"
|
|
11820
|
-
(messageClick)="openMessage(message.id)">
|
|
11821
|
-
</ds-mobile-interactive-list-item-message>
|
|
11822
|
-
}
|
|
11784
|
+
</div>
|
|
11785
|
+
|
|
11786
|
+
<!-- Scrollable Content -->
|
|
11787
|
+
<ion-content [scrollY]="true" class="modal-content">
|
|
11788
|
+
<div class="demo-container">
|
|
11789
|
+
<!-- Theme Selection -->
|
|
11790
|
+
<div class="demo-section">
|
|
11791
|
+
<h2>Theme</h2>
|
|
11792
|
+
<div class="theme-buttons">
|
|
11793
|
+
<button class="theme-btn" (click)="applyDefaultTheme()" [class.active]="currentTheme === 'default'">
|
|
11794
|
+
Propbinder
|
|
11795
|
+
</button>
|
|
11796
|
+
<button class="theme-btn" (click)="applyCejTheme()" [class.active]="currentTheme === 'cej'">
|
|
11797
|
+
CEJ
|
|
11798
|
+
</button>
|
|
11799
|
+
<button class="theme-btn" (click)="applyPkaTheme()" [class.active]="currentTheme === 'pka'">
|
|
11800
|
+
PKA
|
|
11801
|
+
</button>
|
|
11802
|
+
<button class="theme-btn" (click)="applyClaveTheme()" [class.active]="currentTheme === 'clave'">
|
|
11803
|
+
Clave
|
|
11804
|
+
</button>
|
|
11823
11805
|
</div>
|
|
11824
|
-
|
|
11806
|
+
</div>
|
|
11825
11807
|
|
|
11826
|
-
<!--
|
|
11827
|
-
|
|
11828
|
-
<
|
|
11829
|
-
|
|
11830
|
-
<
|
|
11831
|
-
<
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
[type]="'initials'"
|
|
11835
|
-
[initials]="'R'" />
|
|
11836
|
-
</div>
|
|
11837
|
-
<div content-main>
|
|
11838
|
-
<div class="detail-label">Sagsbehandler</div>
|
|
11839
|
-
<div class="detail-value">Ricki Meihlen</div>
|
|
11808
|
+
<!-- Logo & Logomark Preview -->
|
|
11809
|
+
<div class="demo-section">
|
|
11810
|
+
<h2>Logo Preview</h2>
|
|
11811
|
+
<div class="preview-grid">
|
|
11812
|
+
<div class="preview-tile">
|
|
11813
|
+
<h3>Logo</h3>
|
|
11814
|
+
<div class="logo-preview">
|
|
11815
|
+
<ds-logo variant="full" />
|
|
11840
11816
|
</div>
|
|
11841
|
-
</
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
<ds-avatar
|
|
11847
|
-
[size]="'sm'"
|
|
11817
|
+
</div>
|
|
11818
|
+
<div class="preview-tile">
|
|
11819
|
+
<h3>Logomark</h3>
|
|
11820
|
+
<div class="logomark-preview">
|
|
11821
|
+
<ds-avatar-with-badge
|
|
11848
11822
|
[type]="'initials'"
|
|
11849
|
-
[initials]="'
|
|
11823
|
+
[initials]="'KN'"
|
|
11824
|
+
[size]="'md'"
|
|
11825
|
+
[badgePosition]="'bottom-right'"
|
|
11826
|
+
/>
|
|
11850
11827
|
</div>
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11828
|
+
</div>
|
|
11829
|
+
</div>
|
|
11830
|
+
</div>
|
|
11831
|
+
|
|
11832
|
+
<!-- Brand Colors -->
|
|
11833
|
+
<div class="demo-section">
|
|
11834
|
+
<h2>Brand Colors</h2>
|
|
11835
|
+
<div class="color-section">
|
|
11836
|
+
<div class="color-swatches">
|
|
11837
|
+
<div class="swatch swatch--primary-surface">
|
|
11838
|
+
<div class="swatch-label">Primary Surface</div>
|
|
11839
|
+
<div class="swatch-value">{{ whitelabelService.primarySurface() }}</div>
|
|
11840
|
+
</div>
|
|
11841
|
+
<div class="swatch swatch--primary-content">
|
|
11842
|
+
<div class="swatch-label">Primary Content</div>
|
|
11843
|
+
<div class="swatch-value">{{ whitelabelService.primaryContent() }}</div>
|
|
11854
11844
|
</div>
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
11859
|
-
<div content-leading>
|
|
11860
|
-
<ds-icon name="remixTextBlock" size="20px" color="tertiary" />
|
|
11845
|
+
<div class="swatch swatch--secondary-surface">
|
|
11846
|
+
<div class="swatch-label">Secondary Surface</div>
|
|
11847
|
+
<div class="swatch-value">{{ whitelabelService.secondarySurface() }}</div>
|
|
11861
11848
|
</div>
|
|
11862
|
-
<div content
|
|
11863
|
-
<div class="
|
|
11849
|
+
<div class="swatch swatch--secondary-content">
|
|
11850
|
+
<div class="swatch-label">Secondary Content</div>
|
|
11851
|
+
<div class="swatch-value">{{ whitelabelService.secondaryContent() }}</div>
|
|
11864
11852
|
</div>
|
|
11865
|
-
</
|
|
11853
|
+
</div>
|
|
11866
11854
|
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
<div
|
|
11870
|
-
<
|
|
11855
|
+
<div class="color-inputs">
|
|
11856
|
+
<div class="color-group-label">Primary</div>
|
|
11857
|
+
<div class="color-row">
|
|
11858
|
+
<label>Surface</label>
|
|
11859
|
+
<input
|
|
11860
|
+
type="color"
|
|
11861
|
+
[(ngModel)]="customPrimarySurface"
|
|
11862
|
+
(change)="applyCustomColors()"
|
|
11863
|
+
/>
|
|
11864
|
+
<input
|
|
11865
|
+
type="text"
|
|
11866
|
+
[(ngModel)]="customPrimarySurface"
|
|
11867
|
+
(change)="applyCustomColors()"
|
|
11868
|
+
/>
|
|
11871
11869
|
</div>
|
|
11872
|
-
<div
|
|
11873
|
-
<
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11870
|
+
<div class="color-row">
|
|
11871
|
+
<label>Content</label>
|
|
11872
|
+
<input
|
|
11873
|
+
type="color"
|
|
11874
|
+
[(ngModel)]="customPrimaryContent"
|
|
11875
|
+
(change)="applyCustomColors()"
|
|
11876
|
+
/>
|
|
11877
|
+
<input
|
|
11878
|
+
type="text"
|
|
11879
|
+
[(ngModel)]="customPrimaryContent"
|
|
11880
|
+
(change)="applyCustomColors()"
|
|
11881
|
+
/>
|
|
11877
11882
|
</div>
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11883
|
+
|
|
11884
|
+
<div class="color-group-label">Secondary</div>
|
|
11885
|
+
<div class="color-row">
|
|
11886
|
+
<label>Surface</label>
|
|
11887
|
+
<input
|
|
11888
|
+
type="color"
|
|
11889
|
+
[(ngModel)]="customSecondarySurface"
|
|
11890
|
+
(change)="applyCustomColors()"
|
|
11891
|
+
/>
|
|
11892
|
+
<input
|
|
11893
|
+
type="text"
|
|
11894
|
+
[(ngModel)]="customSecondarySurface"
|
|
11895
|
+
(change)="applyCustomColors()"
|
|
11896
|
+
/>
|
|
11884
11897
|
</div>
|
|
11885
|
-
<div
|
|
11886
|
-
<
|
|
11887
|
-
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11898
|
+
<div class="color-row">
|
|
11899
|
+
<label>Content</label>
|
|
11900
|
+
<input
|
|
11901
|
+
type="color"
|
|
11902
|
+
[(ngModel)]="customSecondaryContent"
|
|
11903
|
+
(change)="applyCustomColors()"
|
|
11904
|
+
/>
|
|
11905
|
+
<input
|
|
11906
|
+
type="text"
|
|
11907
|
+
[(ngModel)]="customSecondaryContent"
|
|
11908
|
+
(change)="applyCustomColors()"
|
|
11909
|
+
/>
|
|
11896
11910
|
</div>
|
|
11897
|
-
</
|
|
11911
|
+
</div>
|
|
11898
11912
|
</div>
|
|
11899
|
-
|
|
11913
|
+
</div>
|
|
11900
11914
|
</div>
|
|
11901
|
-
</div>
|
|
11902
11915
|
</ion-content>
|
|
11903
|
-
`, isInline: true, styles: ["
|
|
11916
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%;background:var(--color-background-neutral-primary, #ffffff)}.modal-header{flex-shrink:0;background:var(--color-background-neutral-primary, #ffffff);border-bottom:1px solid var(--border-color-default, #e0e0e0);padding:0 16px}ion-content,.modal-content{--background: #ffffff;flex:1;width:100%}.header-content{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:56px}.header-title{font-family:Brockmann,sans-serif;font-size:17px;font-weight:600;color:var(--color-text-primary, #1a1a1a);flex:1}.close-button{flex-shrink:0;border-radius:50%}.close-button::ng-deep button{border-radius:50%!important;width:36px!important;height:36px!important;min-width:36px!important;min-height:36px!important;padding:0!important;display:flex!important;align-items:center!important;justify-content:center!important;background:var(--color-background-neutral-secondary, #f5f5f5)!important;color:var(--color-text-primary, #1a1a1a)!important}.demo-container{padding:20px;max-width:600px;margin:0 auto;width:100%}.demo-section{margin-bottom:32px}.demo-section h2{margin-bottom:16px;font-size:18px;font-weight:600;color:#333}.theme-buttons{display:flex;gap:12px;flex-wrap:wrap}.theme-btn{padding:8px 16px;border-radius:8px;font-size:14px;font-weight:500;border:none;cursor:pointer;transition:all .2s ease;background:#e0e0e0;color:#333}.theme-btn:active{transform:scale(.98)}.theme-btn.active{background:var(--color-secondary-surface);color:var(--color-secondary-content)}.logo-preview{display:flex;align-items:center;justify-content:center;padding:24px;background:var(--color-brand-secondary);border-radius:12px;min-height:80px}.logomark-preview{display:flex;align-items:center;justify-content:center;padding:24px;background:#fff;border:1px solid #e0e0e0;border-radius:12px;min-height:80px}.preview-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}.preview-tile{background:#fff;border-radius:12px}.preview-tile h3{font-size:13px;font-weight:600;color:#666;margin-top:0;margin-bottom:12px}.color-section{background:#fff;border-radius:12px}.color-swatches{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:24px}.swatch{padding:16px;border-radius:8px;text-align:center}.swatch-label{font-size:12px;font-weight:600;margin-bottom:4px}.swatch-value{font-size:11px;opacity:.8;font-family:monospace}.swatch--primary-surface{background:var(--color-primary-surface);color:var(--color-primary-content)}.swatch--primary-content{background:var(--color-primary-content);color:var(--color-primary-surface);border:1px solid #e0e0e0}.swatch--secondary-surface{background:var(--color-secondary-surface);color:var(--color-secondary-content)}.swatch--secondary-content{background:var(--color-secondary-content);color:var(--color-secondary-surface);border:1px solid #e0e0e0}.color-inputs{display:flex;flex-direction:column;gap:12px}.color-group-label{font-size:13px;font-weight:600;color:#333;margin-top:8px}.color-row{display:flex;align-items:center;gap:12px}.color-row label{min-width:70px;font-size:13px;color:#666}.color-row input[type=color]{width:40px;height:32px;border:none;border-radius:6px;cursor:pointer;padding:0}.color-row input[type=text]{flex:1;padding:8px 12px;border:1px solid #ddd;border-radius:6px;font-family:monospace;font-size:13px}@supports (padding: env(safe-area-inset-bottom)){.demo-container{padding-bottom:calc(20px + env(safe-area-inset-bottom))}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: DsLogoComponent, selector: "ds-logo", inputs: ["variant", "size", "customHeight", "customWidth"] }, { kind: "component", type: DsAvatarWithBadgeComponent, selector: "ds-avatar-with-badge", inputs: ["type", "size", "initials", "src", "iconName", "showBadge", "badgePosition"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }] });
|
|
11904
11917
|
}
|
|
11905
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type:
|
|
11918
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoModalComponent, decorators: [{
|
|
11906
11919
|
type: Component,
|
|
11907
|
-
args: [{ selector: '
|
|
11920
|
+
args: [{ selector: 'ds-whitelabel-demo-modal', standalone: true, imports: [
|
|
11908
11921
|
CommonModule,
|
|
11909
|
-
|
|
11910
|
-
IonToolbar,
|
|
11911
|
-
IonTitle,
|
|
11922
|
+
FormsModule,
|
|
11912
11923
|
IonContent,
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
11918
|
-
|
|
11919
|
-
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
<ds-icon name="remixArrowLeftSLine" size="24px" color="white" />
|
|
11930
|
-
</button>
|
|
11931
|
-
|
|
11932
|
-
<!-- Title - fades in on scroll -->
|
|
11933
|
-
<ion-title class="header-detail__title">{{ inquiryTitle }}</ion-title>
|
|
11934
|
-
</div>
|
|
11935
|
-
</ion-toolbar>
|
|
11936
|
-
</ion-header>
|
|
11937
|
-
|
|
11938
|
-
<!-- Content with expandable header -->
|
|
11939
|
-
<ion-content [scrollEvents]="true" (ionScroll)="handleScroll($event)">
|
|
11940
|
-
<!-- Pull to refresh (only on native iOS/Android) -->
|
|
11941
|
-
@if (isNativePlatform()) {
|
|
11942
|
-
<ion-refresher
|
|
11943
|
-
slot="fixed"
|
|
11944
|
-
(ionRefresh)="handleRefresh($event)"
|
|
11945
|
-
[pullFactor]="0.4"
|
|
11946
|
-
[pullMin]="80"
|
|
11947
|
-
[pullMax]="240"
|
|
11948
|
-
closeDuration="600ms">
|
|
11949
|
-
<ion-refresher-content
|
|
11950
|
-
pullingIcon="remixArrowDownS"
|
|
11951
|
-
refreshingSpinner="lines">
|
|
11952
|
-
</ion-refresher-content>
|
|
11953
|
-
</ion-refresher>
|
|
11954
|
-
}
|
|
11955
|
-
|
|
11956
|
-
<!-- Expandable header section (purple background) -->
|
|
11957
|
-
<div class="header-expandable">
|
|
11958
|
-
<div class="header-expandable-inner">
|
|
11959
|
-
<div class="header-expandable__text">
|
|
11960
|
-
<h1 class="header-expandable__title">{{ inquiryTitle }}</h1>
|
|
11961
|
-
</div>
|
|
11962
|
-
|
|
11963
|
-
<!-- Tabs in header -->
|
|
11964
|
-
<ds-mobile-inline-tabs
|
|
11965
|
-
[tabs]="tabItems"
|
|
11966
|
-
[activeTab]="activeTab()"
|
|
11967
|
-
(tabChange)="setActiveTab($event)">
|
|
11968
|
-
</ds-mobile-inline-tabs>
|
|
11969
|
-
</div>
|
|
11924
|
+
DsLogoComponent,
|
|
11925
|
+
DsAvatarWithBadgeComponent,
|
|
11926
|
+
DsIconButtonComponent
|
|
11927
|
+
], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: `
|
|
11928
|
+
<!-- Fixed Header -->
|
|
11929
|
+
<div class="modal-header">
|
|
11930
|
+
<div class="header-content">
|
|
11931
|
+
<span class="header-title">Whitelabel</span>
|
|
11932
|
+
<ds-icon-button
|
|
11933
|
+
icon="remixCloseLine"
|
|
11934
|
+
variant="secondary"
|
|
11935
|
+
size="lg"
|
|
11936
|
+
(click)="close()"
|
|
11937
|
+
class="close-button"
|
|
11938
|
+
aria-label="Close">
|
|
11939
|
+
</ds-icon-button>
|
|
11970
11940
|
</div>
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
|
|
11975
|
-
|
|
11976
|
-
|
|
11977
|
-
|
|
11978
|
-
|
|
11979
|
-
|
|
11980
|
-
|
|
11981
|
-
|
|
11982
|
-
|
|
11983
|
-
|
|
11984
|
-
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
|
|
11989
|
-
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
</svg>
|
|
11993
|
-
</div>
|
|
11994
|
-
</div>
|
|
11995
|
-
} @else {
|
|
11996
|
-
<!-- Icon wrapper for non-actor activities -->
|
|
11997
|
-
<div class="activity-icon-wrapper">
|
|
11998
|
-
<ds-icon
|
|
11999
|
-
[name]="activity.iconName"
|
|
12000
|
-
size="18px"
|
|
12001
|
-
color="secondary" />
|
|
12002
|
-
</div>
|
|
12003
|
-
}
|
|
12004
|
-
|
|
12005
|
-
<div class="activity-content">
|
|
12006
|
-
<p class="activity-title">
|
|
12007
|
-
@if (activity.actor) {
|
|
12008
|
-
<span class="actor-name">{{ activity.actor }}</span>
|
|
12009
|
-
<span class="activity-text"> {{ activity.title }}</span>
|
|
12010
|
-
} @else {
|
|
12011
|
-
<span class="actor-name">{{ activity.title }}</span>
|
|
12012
|
-
}
|
|
12013
|
-
</p>
|
|
12014
|
-
@if (activity.description) {
|
|
12015
|
-
<p class="activity-description">{{ activity.description }}</p>
|
|
12016
|
-
}
|
|
12017
|
-
<div class="activity-timestamp">
|
|
12018
|
-
<ds-icon name="remixCalendarLine" size="12px" color="--color-text-tertiary" />
|
|
12019
|
-
<span>{{ activity.date }}</span>
|
|
12020
|
-
</div>
|
|
12021
|
-
</div>
|
|
12022
|
-
</div>
|
|
12023
|
-
}
|
|
12024
|
-
</div>
|
|
12025
|
-
}
|
|
12026
|
-
|
|
12027
|
-
<!-- Messages Tab Content -->
|
|
12028
|
-
@if (activeTab() === 'messages') {
|
|
12029
|
-
<div class="messages-list">
|
|
12030
|
-
@for (message of messageThreads; track message.id) {
|
|
12031
|
-
<ds-mobile-interactive-list-item-message
|
|
12032
|
-
[senderName]="message.senderName"
|
|
12033
|
-
[senderRole]="message.role"
|
|
12034
|
-
[message]="message.message"
|
|
12035
|
-
[avatarInitials]="message.senderInitials"
|
|
12036
|
-
[unread]="message.unread"
|
|
12037
|
-
(messageClick)="openMessage(message.id)">
|
|
12038
|
-
</ds-mobile-interactive-list-item-message>
|
|
12039
|
-
}
|
|
11941
|
+
</div>
|
|
11942
|
+
|
|
11943
|
+
<!-- Scrollable Content -->
|
|
11944
|
+
<ion-content [scrollY]="true" class="modal-content">
|
|
11945
|
+
<div class="demo-container">
|
|
11946
|
+
<!-- Theme Selection -->
|
|
11947
|
+
<div class="demo-section">
|
|
11948
|
+
<h2>Theme</h2>
|
|
11949
|
+
<div class="theme-buttons">
|
|
11950
|
+
<button class="theme-btn" (click)="applyDefaultTheme()" [class.active]="currentTheme === 'default'">
|
|
11951
|
+
Propbinder
|
|
11952
|
+
</button>
|
|
11953
|
+
<button class="theme-btn" (click)="applyCejTheme()" [class.active]="currentTheme === 'cej'">
|
|
11954
|
+
CEJ
|
|
11955
|
+
</button>
|
|
11956
|
+
<button class="theme-btn" (click)="applyPkaTheme()" [class.active]="currentTheme === 'pka'">
|
|
11957
|
+
PKA
|
|
11958
|
+
</button>
|
|
11959
|
+
<button class="theme-btn" (click)="applyClaveTheme()" [class.active]="currentTheme === 'clave'">
|
|
11960
|
+
Clave
|
|
11961
|
+
</button>
|
|
12040
11962
|
</div>
|
|
12041
|
-
|
|
11963
|
+
</div>
|
|
12042
11964
|
|
|
12043
|
-
<!--
|
|
12044
|
-
|
|
12045
|
-
<
|
|
12046
|
-
|
|
12047
|
-
<
|
|
12048
|
-
<
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
[type]="'initials'"
|
|
12052
|
-
[initials]="'R'" />
|
|
12053
|
-
</div>
|
|
12054
|
-
<div content-main>
|
|
12055
|
-
<div class="detail-label">Sagsbehandler</div>
|
|
12056
|
-
<div class="detail-value">Ricki Meihlen</div>
|
|
11965
|
+
<!-- Logo & Logomark Preview -->
|
|
11966
|
+
<div class="demo-section">
|
|
11967
|
+
<h2>Logo Preview</h2>
|
|
11968
|
+
<div class="preview-grid">
|
|
11969
|
+
<div class="preview-tile">
|
|
11970
|
+
<h3>Logo</h3>
|
|
11971
|
+
<div class="logo-preview">
|
|
11972
|
+
<ds-logo variant="full" />
|
|
12057
11973
|
</div>
|
|
12058
|
-
</
|
|
12059
|
-
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
<ds-avatar
|
|
12064
|
-
[size]="'sm'"
|
|
11974
|
+
</div>
|
|
11975
|
+
<div class="preview-tile">
|
|
11976
|
+
<h3>Logomark</h3>
|
|
11977
|
+
<div class="logomark-preview">
|
|
11978
|
+
<ds-avatar-with-badge
|
|
12065
11979
|
[type]="'initials'"
|
|
12066
|
-
[initials]="'
|
|
11980
|
+
[initials]="'KN'"
|
|
11981
|
+
[size]="'md'"
|
|
11982
|
+
[badgePosition]="'bottom-right'"
|
|
11983
|
+
/>
|
|
12067
11984
|
</div>
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
11985
|
+
</div>
|
|
11986
|
+
</div>
|
|
11987
|
+
</div>
|
|
11988
|
+
|
|
11989
|
+
<!-- Brand Colors -->
|
|
11990
|
+
<div class="demo-section">
|
|
11991
|
+
<h2>Brand Colors</h2>
|
|
11992
|
+
<div class="color-section">
|
|
11993
|
+
<div class="color-swatches">
|
|
11994
|
+
<div class="swatch swatch--primary-surface">
|
|
11995
|
+
<div class="swatch-label">Primary Surface</div>
|
|
11996
|
+
<div class="swatch-value">{{ whitelabelService.primarySurface() }}</div>
|
|
12071
11997
|
</div>
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
12076
|
-
<div content-leading>
|
|
12077
|
-
<ds-icon name="remixTextBlock" size="20px" color="tertiary" />
|
|
11998
|
+
<div class="swatch swatch--primary-content">
|
|
11999
|
+
<div class="swatch-label">Primary Content</div>
|
|
12000
|
+
<div class="swatch-value">{{ whitelabelService.primaryContent() }}</div>
|
|
12078
12001
|
</div>
|
|
12079
|
-
<div
|
|
12080
|
-
<div class="
|
|
12002
|
+
<div class="swatch swatch--secondary-surface">
|
|
12003
|
+
<div class="swatch-label">Secondary Surface</div>
|
|
12004
|
+
<div class="swatch-value">{{ whitelabelService.secondarySurface() }}</div>
|
|
12081
12005
|
</div>
|
|
12082
|
-
|
|
12006
|
+
<div class="swatch swatch--secondary-content">
|
|
12007
|
+
<div class="swatch-label">Secondary Content</div>
|
|
12008
|
+
<div class="swatch-value">{{ whitelabelService.secondaryContent() }}</div>
|
|
12009
|
+
</div>
|
|
12010
|
+
</div>
|
|
12083
12011
|
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
<div
|
|
12087
|
-
<
|
|
12012
|
+
<div class="color-inputs">
|
|
12013
|
+
<div class="color-group-label">Primary</div>
|
|
12014
|
+
<div class="color-row">
|
|
12015
|
+
<label>Surface</label>
|
|
12016
|
+
<input
|
|
12017
|
+
type="color"
|
|
12018
|
+
[(ngModel)]="customPrimarySurface"
|
|
12019
|
+
(change)="applyCustomColors()"
|
|
12020
|
+
/>
|
|
12021
|
+
<input
|
|
12022
|
+
type="text"
|
|
12023
|
+
[(ngModel)]="customPrimarySurface"
|
|
12024
|
+
(change)="applyCustomColors()"
|
|
12025
|
+
/>
|
|
12088
12026
|
</div>
|
|
12089
|
-
<div
|
|
12090
|
-
<
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12027
|
+
<div class="color-row">
|
|
12028
|
+
<label>Content</label>
|
|
12029
|
+
<input
|
|
12030
|
+
type="color"
|
|
12031
|
+
[(ngModel)]="customPrimaryContent"
|
|
12032
|
+
(change)="applyCustomColors()"
|
|
12033
|
+
/>
|
|
12034
|
+
<input
|
|
12035
|
+
type="text"
|
|
12036
|
+
[(ngModel)]="customPrimaryContent"
|
|
12037
|
+
(change)="applyCustomColors()"
|
|
12038
|
+
/>
|
|
12094
12039
|
</div>
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
|
|
12040
|
+
|
|
12041
|
+
<div class="color-group-label">Secondary</div>
|
|
12042
|
+
<div class="color-row">
|
|
12043
|
+
<label>Surface</label>
|
|
12044
|
+
<input
|
|
12045
|
+
type="color"
|
|
12046
|
+
[(ngModel)]="customSecondarySurface"
|
|
12047
|
+
(change)="applyCustomColors()"
|
|
12048
|
+
/>
|
|
12049
|
+
<input
|
|
12050
|
+
type="text"
|
|
12051
|
+
[(ngModel)]="customSecondarySurface"
|
|
12052
|
+
(change)="applyCustomColors()"
|
|
12053
|
+
/>
|
|
12101
12054
|
</div>
|
|
12102
|
-
<div
|
|
12103
|
-
<
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
|
|
12055
|
+
<div class="color-row">
|
|
12056
|
+
<label>Content</label>
|
|
12057
|
+
<input
|
|
12058
|
+
type="color"
|
|
12059
|
+
[(ngModel)]="customSecondaryContent"
|
|
12060
|
+
(change)="applyCustomColors()"
|
|
12061
|
+
/>
|
|
12062
|
+
<input
|
|
12063
|
+
type="text"
|
|
12064
|
+
[(ngModel)]="customSecondaryContent"
|
|
12065
|
+
(change)="applyCustomColors()"
|
|
12066
|
+
/>
|
|
12113
12067
|
</div>
|
|
12114
|
-
</
|
|
12068
|
+
</div>
|
|
12115
12069
|
</div>
|
|
12116
|
-
|
|
12070
|
+
</div>
|
|
12117
12071
|
</div>
|
|
12118
|
-
</div>
|
|
12119
12072
|
</ion-content>
|
|
12120
|
-
`, styles: ["
|
|
12121
|
-
}]
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12073
|
+
`, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%;background:var(--color-background-neutral-primary, #ffffff)}.modal-header{flex-shrink:0;background:var(--color-background-neutral-primary, #ffffff);border-bottom:1px solid var(--border-color-default, #e0e0e0);padding:0 16px}ion-content,.modal-content{--background: #ffffff;flex:1;width:100%}.header-content{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:56px}.header-title{font-family:Brockmann,sans-serif;font-size:17px;font-weight:600;color:var(--color-text-primary, #1a1a1a);flex:1}.close-button{flex-shrink:0;border-radius:50%}.close-button::ng-deep button{border-radius:50%!important;width:36px!important;height:36px!important;min-width:36px!important;min-height:36px!important;padding:0!important;display:flex!important;align-items:center!important;justify-content:center!important;background:var(--color-background-neutral-secondary, #f5f5f5)!important;color:var(--color-text-primary, #1a1a1a)!important}.demo-container{padding:20px;max-width:600px;margin:0 auto;width:100%}.demo-section{margin-bottom:32px}.demo-section h2{margin-bottom:16px;font-size:18px;font-weight:600;color:#333}.theme-buttons{display:flex;gap:12px;flex-wrap:wrap}.theme-btn{padding:8px 16px;border-radius:8px;font-size:14px;font-weight:500;border:none;cursor:pointer;transition:all .2s ease;background:#e0e0e0;color:#333}.theme-btn:active{transform:scale(.98)}.theme-btn.active{background:var(--color-secondary-surface);color:var(--color-secondary-content)}.logo-preview{display:flex;align-items:center;justify-content:center;padding:24px;background:var(--color-brand-secondary);border-radius:12px;min-height:80px}.logomark-preview{display:flex;align-items:center;justify-content:center;padding:24px;background:#fff;border:1px solid #e0e0e0;border-radius:12px;min-height:80px}.preview-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}.preview-tile{background:#fff;border-radius:12px}.preview-tile h3{font-size:13px;font-weight:600;color:#666;margin-top:0;margin-bottom:12px}.color-section{background:#fff;border-radius:12px}.color-swatches{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:24px}.swatch{padding:16px;border-radius:8px;text-align:center}.swatch-label{font-size:12px;font-weight:600;margin-bottom:4px}.swatch-value{font-size:11px;opacity:.8;font-family:monospace}.swatch--primary-surface{background:var(--color-primary-surface);color:var(--color-primary-content)}.swatch--primary-content{background:var(--color-primary-content);color:var(--color-primary-surface);border:1px solid #e0e0e0}.swatch--secondary-surface{background:var(--color-secondary-surface);color:var(--color-secondary-content)}.swatch--secondary-content{background:var(--color-secondary-content);color:var(--color-secondary-surface);border:1px solid #e0e0e0}.color-inputs{display:flex;flex-direction:column;gap:12px}.color-group-label{font-size:13px;font-weight:600;color:#333;margin-top:8px}.color-row{display:flex;align-items:center;gap:12px}.color-row label{min-width:70px;font-size:13px;color:#666}.color-row input[type=color]{width:40px;height:32px;border:none;border-radius:6px;cursor:pointer;padding:0}.color-row input[type=text]{flex:1;padding:8px 12px;border:1px solid #ddd;border-radius:6px;font-family:monospace;font-size:13px}@supports (padding: env(safe-area-inset-bottom)){.demo-container{padding-bottom:calc(20px + env(safe-area-inset-bottom))}}\n"] }]
|
|
12074
|
+
}] });
|
|
12075
|
+
|
|
12076
|
+
/**
|
|
12077
|
+
* WhitelabelDemoModalService
|
|
12078
|
+
*
|
|
12079
|
+
* Service for displaying the whitelabel demo in a full-screen modal.
|
|
12080
|
+
* Built on Ionic's modal system with native gestures and animations.
|
|
12081
|
+
*
|
|
12082
|
+
* @example
|
|
12083
|
+
* ```typescript
|
|
12084
|
+
* constructor(private whitelabelModal: WhitelabelDemoModalService) {}
|
|
12085
|
+
*
|
|
12086
|
+
* async openDemo() {
|
|
12087
|
+
* await this.whitelabelModal.open();
|
|
12088
|
+
* }
|
|
12089
|
+
* ```
|
|
12090
|
+
*/
|
|
12091
|
+
class WhitelabelDemoModalService {
|
|
12092
|
+
modalController;
|
|
12093
|
+
constructor(modalController) {
|
|
12094
|
+
this.modalController = modalController;
|
|
12095
|
+
}
|
|
12096
|
+
/**
|
|
12097
|
+
* Open the whitelabel demo modal
|
|
12098
|
+
*
|
|
12099
|
+
* @returns Promise that resolves when the modal is presented
|
|
12100
|
+
*/
|
|
12101
|
+
async open() {
|
|
12102
|
+
try {
|
|
12103
|
+
console.log('[WhitelabelDemoModal] Opening...');
|
|
12104
|
+
const modal = await this.modalController.create({
|
|
12105
|
+
component: WhitelabelDemoModalComponent,
|
|
12106
|
+
cssClass: 'ds-whitelabel-demo-modal',
|
|
12107
|
+
mode: 'ios',
|
|
12108
|
+
presentingElement: document.querySelector('ion-router-outlet') || undefined,
|
|
12109
|
+
backdropDismiss: true,
|
|
12110
|
+
showBackdrop: true,
|
|
12111
|
+
animated: true,
|
|
12112
|
+
keyboardClose: true
|
|
12113
|
+
});
|
|
12114
|
+
console.log('[WhitelabelDemoModal] Modal created, presenting...');
|
|
12115
|
+
await modal.present();
|
|
12116
|
+
console.log('[WhitelabelDemoModal] Modal presented');
|
|
12117
|
+
}
|
|
12118
|
+
catch (error) {
|
|
12119
|
+
console.error('[WhitelabelDemoModal] Error opening modal:', error);
|
|
12120
|
+
throw error;
|
|
12121
|
+
}
|
|
12122
|
+
}
|
|
12123
|
+
/**
|
|
12124
|
+
* Close the currently open whitelabel demo modal
|
|
12125
|
+
*
|
|
12126
|
+
* @param data Optional data to pass back when dismissing
|
|
12127
|
+
* @returns Promise that resolves when the modal is dismissed
|
|
12128
|
+
*/
|
|
12129
|
+
async close(data) {
|
|
12130
|
+
return this.modalController.dismiss(data);
|
|
12131
|
+
}
|
|
12132
|
+
/**
|
|
12133
|
+
* Get the top-most modal if one exists
|
|
12134
|
+
*
|
|
12135
|
+
* @returns Promise that resolves to the modal element or undefined
|
|
12136
|
+
*/
|
|
12137
|
+
async getTop() {
|
|
12138
|
+
return this.modalController.getTop();
|
|
12139
|
+
}
|
|
12140
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoModalService, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
12141
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoModalService, providedIn: 'root' });
|
|
12142
|
+
}
|
|
12143
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoModalService, decorators: [{
|
|
12144
|
+
type: Injectable,
|
|
12145
|
+
args: [{
|
|
12146
|
+
providedIn: 'root'
|
|
12147
|
+
}]
|
|
12148
|
+
}], ctorParameters: () => [{ type: i1.ModalController }] });
|
|
12125
12149
|
|
|
12126
12150
|
/**
|
|
12127
12151
|
* MobileTabsExampleComponent
|
|
@@ -12146,6 +12170,8 @@ class MobileTabsExampleComponent {
|
|
|
12146
12170
|
// Configure user avatar globally - this is now the single source of truth
|
|
12147
12171
|
this.userService.setAvatarInitials('LM');
|
|
12148
12172
|
this.userService.setAvatarType('initials');
|
|
12173
|
+
// Set profile menu items globally - this will be used by both tab bar and page-main components
|
|
12174
|
+
this.userService.setProfileMenuItems(this.profileMenuItems);
|
|
12149
12175
|
}
|
|
12150
12176
|
tabs = [
|
|
12151
12177
|
{
|
|
@@ -12179,7 +12205,9 @@ class MobileTabsExampleComponent {
|
|
|
12179
12205
|
];
|
|
12180
12206
|
/**
|
|
12181
12207
|
* Profile menu items configuration.
|
|
12182
|
-
* Define once here
|
|
12208
|
+
* Define once here - this is set globally in UserService in ngOnInit(),
|
|
12209
|
+
* so it will be used by both ds-mobile-tab-bar and ds-mobile-page-main components
|
|
12210
|
+
* throughout the entire application.
|
|
12183
12211
|
*/
|
|
12184
12212
|
profileMenuItems = [
|
|
12185
12213
|
{
|