@propbinder/mobile-design 0.0.1 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, computed, Directive, EventEmitter, HostListener, Output, Input, inject, PLATFORM_ID, signal, output, Component, Injectable, ViewChild, model, ElementRef, CUSTOM_ELEMENTS_SCHEMA, createComponent } from '@angular/core';
|
|
2
|
+
import { input, computed, Directive, EventEmitter, HostListener, Output, Input, inject, PLATFORM_ID, signal, output, Component, Injectable, ViewChild, model, ElementRef, CUSTOM_ELEMENTS_SCHEMA, createComponent, effect, ViewEncapsulation } from '@angular/core';
|
|
3
3
|
import * as i1$2 from '@angular/common';
|
|
4
4
|
import { isPlatformBrowser, CommonModule } from '@angular/common';
|
|
5
5
|
import * as i1$1 from '@angular/router';
|
|
6
6
|
import { Router } from '@angular/router';
|
|
7
7
|
import * as i1 from '@ionic/angular/standalone';
|
|
8
|
-
import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, Platform, ModalController, IonRefresher, IonRefresherContent, IonTabs, IonTabBar, IonTabButton, IonLabel, IonTab, IonSpinner } from '@ionic/angular/standalone';
|
|
8
|
+
import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, Platform, ModalController, IonRefresher, IonRefresherContent, IonTabs, IonTabBar, IonTabButton, IonLabel, 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 * as i2 from '@angular/forms';
|
|
@@ -18,6 +18,7 @@ import { Share } from '@capacitor/share';
|
|
|
18
18
|
import Swiper from 'swiper';
|
|
19
19
|
import { Filesystem, Directory } from '@capacitor/filesystem';
|
|
20
20
|
import { Browser } from '@capacitor/browser';
|
|
21
|
+
import { createAnimation } from '@ionic/core';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* MobilePageBase
|
|
@@ -4419,7 +4420,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
4419
4420
|
* />
|
|
4420
4421
|
* ```
|
|
4421
4422
|
*/
|
|
4422
|
-
class DsMobileTabsComponent {
|
|
4423
|
+
let DsMobileTabsComponent$1 = class DsMobileTabsComponent {
|
|
4423
4424
|
elementRef;
|
|
4424
4425
|
// Inputs
|
|
4425
4426
|
tabs = [];
|
|
@@ -4555,8 +4556,8 @@ class DsMobileTabsComponent {
|
|
|
4555
4556
|
</ion-tab-bar>
|
|
4556
4557
|
</ion-tabs>
|
|
4557
4558
|
`, isInline: true, styles: [":host{display:block;height:100vh;height:100dvh}ion-tab-button:before,ion-tab-button:after{content:none!important;display:none!important}ion-tab-button[title]:before,ion-tab-button[title]:after{display:none!important}ion-tab-button::part(native):before,ion-tab-button::part(native):after{display:none!important}ion-tabs{height:100%;background:var(--color-brand-secondary)}.ds-tab-bar{--background: var(--color-background-neutral-primary);transition:transform .2s ease-in-out}ion-tab-bar[slot=bottom]{border-top:1px solid var(--border-color-default);padding-top:8px;padding-bottom:calc(var(--ion-safe-area-bottom, 34px) - 4px)}@media (max-width: 767px){ion-tab-bar[slot=bottom]{position:fixed;bottom:0;left:0;right:0;z-index:100}}@media (max-width: 767px){ion-tabs:has(ds-mobile-page-details) .ds-tab-bar{transform:translateY(100%);transition:transform .3s ease}}.ds-tab-bar__logo,.ds-tab-bar__actions{display:none}.ds-tab-bar__tabs{display:flex;width:100%;justify-content:space-around;align-items:center}@media (min-width: 769px){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)}}@media (display-mode: standalone){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)!important}}@media (min-width: 768px){ion-tab-bar[slot=top]{--background: var(--color-brand-secondary);position:relative;display:flex;align-items:center;padding:12px 24px;height:64px;max-width:none}.ds-tab-bar__logo{display:flex;position:absolute;left:24px;align-items:center}.ds-tab-bar__actions{display:flex;position:absolute;right:24px;align-items:center;gap:12px}.ds-tab-bar__tabs{display:flex;gap:8px;align-items:center;max-width:640px;width:100%;margin:0 auto;justify-content:center;padding-left:var(--content-padding-md);padding-right:var(--content-padding-md)}.logomark{height:28px;width:auto;flex-shrink:0}}@media (min-width: 992px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg);justify-content:center}}@media (min-width: 1440px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-tab-button{--color: var(--text-color-default-tertiary);--color-selected: var(--color-brand-base);display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:visible;pointer-events:auto}ion-tab-button[title]:before{content:attr(title);position:absolute;opacity:0;pointer-events:none}.tab-icon-ripple{position:absolute;left:50%;top:50%;width:40px;height:40px;border-radius:50%;background:var(--color-brand-base);transform:translate(-50%,-50%) scale(0);opacity:0;pointer-events:none;transition:all .6s cubic-bezier(.36,1.2,.04,1.4);z-index:0}.tab-selected .tab-icon-ripple{transform:translate(-50%,-50%) scale(2);opacity:.05;animation:ripple-fade .6s cubic-bezier(.36,.5,.04,1.8) forwards}@keyframes ripple-fade{0%{opacity:0;transform:translate(-50%,-50%) scale(0)}30%{opacity:.1}to{opacity:0;transform:translate(-50%,-50%) scale(2)}}ion-tab-button::part(native){overflow:visible}ion-tab-button ion-ripple-effect{color:var(--color-brand-base);border-radius:1000px}ion-tab-button ion-label{font-size:var(--font-size-xs);font-weight:400;letter-spacing:-.3px;margin-top:0}.tab-icon-wrapper{position:relative;width:24px;height:24px;display:flex;align-items:center;justify-content:center;z-index:1;margin-bottom:4px}.tab-icon-inactive,.tab-icon-active{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);transition:all .8s cubic-bezier(.36,1,.04,1)}.tab-icon-inactive{opacity:1;transform:translate(-50%,-50%) scale(1)}.tab-icon-active{opacity:0;transform:translate(-50%,calc(-50% - 12px)) scale(.5)}.tab-selected .tab-icon-inactive{opacity:0;transform:translate(-50%,-50%) scale(.5)}.tab-selected .tab-icon-active{opacity:1;transform:translate(-50%,-50%) scale(1)}@media (min-width: 768px){.ds-tab-button{flex-direction:row;height:40px;padding:0 16px!important;border-radius:40px;transition:all .2s ease;width:-moz-fit-content;width:fit-content;min-width:auto;flex:0 0 auto;--color: rgba(255, 255, 255, .7);--color-selected: white;background:#ffffff1a;position:relative;overflow:hidden}.tab-icon-wrapper,.tab-icon-ripple{width:20px;height:20px}.ds-tab-button::part(native){border-radius:40px}.ds-tab-button:hover{--color: white;--color-selected: white}.ds-tab-button.tab-selected{background:var(--color-background-brand);--color-selected: white}.ds-tab-button .button-native{width:auto;padding:0}.ds-tab-button ion-label{font-size:var(--font-size-sm);font-weight:500;margin:0;color:inherit}.ds-tab-button .tab-icon-wrapper{margin-right:4px;margin-bottom:0}.ds-tab-button ion-ripple-effect{color:#ffffff4d;border-radius:1000px;transform:scale(1.5)}}@media (min-width: 768px){.ds-tab-bar__actions ds-avatar{cursor:pointer;transition:transform .2s ease}.ds-tab-bar__actions ds-avatar:hover{transform:scale(1.05)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IonTabs, selector: "ion-tabs" }, { kind: "component", type: IonTab, selector: "ion-tab", inputs: ["component", "tab"] }, { kind: "component", type: IonTabBar, selector: "ion-tab-bar", inputs: ["color", "mode", "selectedTab", "translucent"] }, { kind: "component", type: IonTabButton, selector: "ion-tab-button", inputs: ["disabled", "download", "href", "layout", "mode", "rel", "selected", "tab", "target"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }] });
|
|
4558
|
-
}
|
|
4559
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobileTabsComponent, decorators: [{
|
|
4559
|
+
};
|
|
4560
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobileTabsComponent$1, decorators: [{
|
|
4560
4561
|
type: Component,
|
|
4561
4562
|
args: [{ selector: 'ds-mobile-tabs', standalone: true, imports: [
|
|
4562
4563
|
CommonModule,
|
|
@@ -8284,11 +8285,4312 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
8284
8285
|
|
|
8285
8286
|
// Mobile Page Components
|
|
8286
8287
|
|
|
8288
|
+
/**
|
|
8289
|
+
* User service for managing current user data globally
|
|
8290
|
+
*/
|
|
8291
|
+
class UserService {
|
|
8292
|
+
// User avatar configuration
|
|
8293
|
+
_avatarInitials = signal('LM', ...(ngDevMode ? [{ debugName: "_avatarInitials" }] : []));
|
|
8294
|
+
_avatarType = signal('initials', ...(ngDevMode ? [{ debugName: "_avatarType" }] : []));
|
|
8295
|
+
_avatarSrc = signal('', ...(ngDevMode ? [{ debugName: "_avatarSrc" }] : []));
|
|
8296
|
+
// Readonly computed values
|
|
8297
|
+
avatarInitials = this._avatarInitials.asReadonly();
|
|
8298
|
+
avatarType = this._avatarType.asReadonly();
|
|
8299
|
+
avatarSrc = this._avatarSrc.asReadonly();
|
|
8300
|
+
/**
|
|
8301
|
+
* Update avatar configuration
|
|
8302
|
+
*/
|
|
8303
|
+
setAvatarInitials(initials) {
|
|
8304
|
+
this._avatarInitials.set(initials);
|
|
8305
|
+
}
|
|
8306
|
+
setAvatarType(type) {
|
|
8307
|
+
this._avatarType.set(type);
|
|
8308
|
+
}
|
|
8309
|
+
setAvatarSrc(src) {
|
|
8310
|
+
this._avatarSrc.set(src);
|
|
8311
|
+
}
|
|
8312
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: UserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
8313
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: UserService, providedIn: 'root' });
|
|
8314
|
+
}
|
|
8315
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: UserService, decorators: [{
|
|
8316
|
+
type: Injectable,
|
|
8317
|
+
args: [{
|
|
8318
|
+
providedIn: 'root'
|
|
8319
|
+
}]
|
|
8320
|
+
}] });
|
|
8321
|
+
|
|
8322
|
+
class MobileCommunityPageComponent {
|
|
8323
|
+
router;
|
|
8324
|
+
route;
|
|
8325
|
+
bottomSheet;
|
|
8326
|
+
lightbox;
|
|
8327
|
+
postModal;
|
|
8328
|
+
userService;
|
|
8329
|
+
// Store user-created posts
|
|
8330
|
+
userPosts = signal([
|
|
8331
|
+
{
|
|
8332
|
+
id: 'user-post-1',
|
|
8333
|
+
authorName: 'Lars Mikkelsen',
|
|
8334
|
+
authorRole: 'Dig',
|
|
8335
|
+
timestamp: '5m siden',
|
|
8336
|
+
avatarType: 'initials',
|
|
8337
|
+
avatarInitials: 'LM',
|
|
8338
|
+
content: 'Dette er mit første opslag! Ser frem til at forbinde med alle i bygningen. 🏠',
|
|
8339
|
+
isLiked: false,
|
|
8340
|
+
likeCount: 3,
|
|
8341
|
+
commentCount: 1
|
|
8342
|
+
}
|
|
8343
|
+
], ...(ngDevMode ? [{ debugName: "userPosts" }] : []));
|
|
8344
|
+
// Flag to control whether static demo posts are shown
|
|
8345
|
+
// Set to false to see the empty state
|
|
8346
|
+
showStaticPosts = signal(true, ...(ngDevMode ? [{ debugName: "showStaticPosts" }] : []));
|
|
8347
|
+
// Computed to check if there are any posts to display
|
|
8348
|
+
hasAnyPosts = computed(() => {
|
|
8349
|
+
return this.userPosts().length > 0 || this.showStaticPosts();
|
|
8350
|
+
}, ...(ngDevMode ? [{ debugName: "hasAnyPosts" }] : []));
|
|
8351
|
+
constructor(router, route, bottomSheet, lightbox, postModal, userService) {
|
|
8352
|
+
this.router = router;
|
|
8353
|
+
this.route = route;
|
|
8354
|
+
this.bottomSheet = bottomSheet;
|
|
8355
|
+
this.lightbox = lightbox;
|
|
8356
|
+
this.postModal = postModal;
|
|
8357
|
+
this.userService = userService;
|
|
8358
|
+
}
|
|
8359
|
+
handleRefresh(event) {
|
|
8360
|
+
console.log('Pull-to-refresh triggered');
|
|
8361
|
+
setTimeout(() => {
|
|
8362
|
+
console.log('Refresh complete');
|
|
8363
|
+
event.target.complete();
|
|
8364
|
+
}, 1000);
|
|
8365
|
+
}
|
|
8366
|
+
/**
|
|
8367
|
+
* Open post detail modal
|
|
8368
|
+
* This provides a better UX than route navigation:
|
|
8369
|
+
* - Maintains scroll position
|
|
8370
|
+
* - Native iOS-style modal feel
|
|
8371
|
+
* - Proper close button that works
|
|
8372
|
+
*/
|
|
8373
|
+
async openPost(postId, focusComment = false) {
|
|
8374
|
+
console.log('[Community] ===== openPost called =====', postId, 'Focus comment:', focusComment);
|
|
8375
|
+
// Map post ID to post data (in real app, fetch from service)
|
|
8376
|
+
const postDataMap = {
|
|
8377
|
+
'1': {
|
|
8378
|
+
postId: '1',
|
|
8379
|
+
authorName: 'Anders Jensen',
|
|
8380
|
+
authorRole: 'Lejer',
|
|
8381
|
+
timestamp: '2t siden',
|
|
8382
|
+
avatarType: 'photo',
|
|
8383
|
+
avatarSrc: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop&crop=face',
|
|
8384
|
+
content: 'Lige flyttet ind i min nye lejlighed! Udlejeren var super hjælpsom gennem hele processen. Virkelig begejstret for at være en del af dette fællesskab! 🏠',
|
|
8385
|
+
isLiked: false,
|
|
8386
|
+
likeCount: 42,
|
|
8387
|
+
commentCount: 12,
|
|
8388
|
+
comments: [
|
|
8389
|
+
{
|
|
8390
|
+
authorName: 'Mette Larsen',
|
|
8391
|
+
authorRole: 'Lejer',
|
|
8392
|
+
timestamp: '1t siden',
|
|
8393
|
+
avatarInitials: 'ML',
|
|
8394
|
+
content: 'Velkommen til fællesskabet!',
|
|
8395
|
+
likeCount: 5,
|
|
8396
|
+
isOwnComment: false
|
|
8397
|
+
},
|
|
8398
|
+
{
|
|
8399
|
+
authorName: 'Lars Mikkelsen',
|
|
8400
|
+
authorRole: 'Dig',
|
|
8401
|
+
timestamp: 'Lige nu',
|
|
8402
|
+
avatarInitials: 'LM',
|
|
8403
|
+
content: 'Vxhknbh',
|
|
8404
|
+
likeCount: 0,
|
|
8405
|
+
isOwnComment: true
|
|
8406
|
+
}
|
|
8407
|
+
]
|
|
8408
|
+
},
|
|
8409
|
+
'2': {
|
|
8410
|
+
postId: '2',
|
|
8411
|
+
authorName: 'Sophie Andersen',
|
|
8412
|
+
authorRole: 'Lejer',
|
|
8413
|
+
timestamp: '4t siden',
|
|
8414
|
+
avatarInitials: 'SA',
|
|
8415
|
+
content: 'Se denne smukke udsigt fra min altan! Morgenkaffe har aldrig smagt så godt ☕️',
|
|
8416
|
+
imageSrc: '/Assets/Dummy-photos/balcony-view.jpg',
|
|
8417
|
+
imageAlt: 'Altanudsigt',
|
|
8418
|
+
isLiked: true,
|
|
8419
|
+
likeCount: 156,
|
|
8420
|
+
commentCount: 34,
|
|
8421
|
+
comments: [
|
|
8422
|
+
{
|
|
8423
|
+
authorName: 'Anders Jensen',
|
|
8424
|
+
authorRole: 'Lejer',
|
|
8425
|
+
timestamp: '3t siden',
|
|
8426
|
+
avatarInitials: 'AJ',
|
|
8427
|
+
content: 'Wow, den udsigt er fantastisk! Hvilken etage er du på?',
|
|
8428
|
+
likeCount: 12,
|
|
8429
|
+
isOwnComment: false
|
|
8430
|
+
},
|
|
8431
|
+
{
|
|
8432
|
+
authorName: 'Thomas Hansen',
|
|
8433
|
+
authorRole: 'Lejer',
|
|
8434
|
+
timestamp: '3t siden',
|
|
8435
|
+
avatarInitials: 'TH',
|
|
8436
|
+
content: 'Smuk! Jeg kan også se byens silhuet fra min lejlighed 🌆',
|
|
8437
|
+
isLiked: true,
|
|
8438
|
+
likeCount: 8,
|
|
8439
|
+
isOwnComment: false
|
|
8440
|
+
},
|
|
8441
|
+
{
|
|
8442
|
+
authorName: 'Lars Mikkelsen',
|
|
8443
|
+
authorRole: 'Dig',
|
|
8444
|
+
timestamp: 'Lige nu',
|
|
8445
|
+
avatarInitials: 'LM',
|
|
8446
|
+
content: 'Vxhknbh',
|
|
8447
|
+
likeCount: 0,
|
|
8448
|
+
isOwnComment: true
|
|
8449
|
+
}
|
|
8450
|
+
]
|
|
8451
|
+
},
|
|
8452
|
+
'3': {
|
|
8453
|
+
postId: '3',
|
|
8454
|
+
authorName: 'Thomas Hansen',
|
|
8455
|
+
authorRole: 'Lejer',
|
|
8456
|
+
timestamp: '1d siden',
|
|
8457
|
+
avatarType: 'photo',
|
|
8458
|
+
avatarSrc: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face',
|
|
8459
|
+
content: 'Kender nogen et fælles fitnesscenter i nærheden? Leder efter anbefalinger til gode træningscentre i området. 🏋️',
|
|
8460
|
+
isLiked: false,
|
|
8461
|
+
likeCount: 23,
|
|
8462
|
+
commentCount: 45,
|
|
8463
|
+
comments: []
|
|
8464
|
+
},
|
|
8465
|
+
'4': {
|
|
8466
|
+
postId: '4',
|
|
8467
|
+
authorName: 'Karen Nielsen',
|
|
8468
|
+
authorRole: 'Ejendomsadministrator',
|
|
8469
|
+
timestamp: '2d siden',
|
|
8470
|
+
avatarInitials: 'KN',
|
|
8471
|
+
content: '📢 Påmindelse: Bygningsvedligeholdelse planlagt til denne lørdag fra kl. 9 til 14. Vandet vil være midlertidigt lukket. Vær venlig at planlægge derefter!',
|
|
8472
|
+
isLiked: false,
|
|
8473
|
+
likeCount: 89,
|
|
8474
|
+
commentCount: 67,
|
|
8475
|
+
comments: []
|
|
8476
|
+
},
|
|
8477
|
+
'5': {
|
|
8478
|
+
postId: '5',
|
|
8479
|
+
authorName: 'Emma Petersen',
|
|
8480
|
+
authorRole: 'Lejer',
|
|
8481
|
+
timestamp: '3d siden',
|
|
8482
|
+
avatarType: 'photo',
|
|
8483
|
+
avatarSrc: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face',
|
|
8484
|
+
content: 'Arrangerer en fælles BBQ næste weekend! Alle er inviteret. Tag din yndlingsret med til at dele. Lad os lære hinanden bedre at kende! 🍔🌭',
|
|
8485
|
+
isLiked: true,
|
|
8486
|
+
likeCount: 124,
|
|
8487
|
+
commentCount: 89,
|
|
8488
|
+
comments: []
|
|
8489
|
+
}
|
|
8490
|
+
};
|
|
8491
|
+
const postData = postDataMap[postId];
|
|
8492
|
+
if (postData) {
|
|
8493
|
+
// Add focusComment flag to postData
|
|
8494
|
+
await this.postModal.open({ ...postData, focusComment });
|
|
8495
|
+
}
|
|
8496
|
+
}
|
|
8497
|
+
/**
|
|
8498
|
+
* Open user-created post detail modal
|
|
8499
|
+
*/
|
|
8500
|
+
async openUserPost(index, focusComment = false) {
|
|
8501
|
+
const posts = this.userPosts();
|
|
8502
|
+
const post = posts[index];
|
|
8503
|
+
if (post) {
|
|
8504
|
+
console.log('[Community] Opening user post modal:', index, 'Focus comment:', focusComment);
|
|
8505
|
+
// Convert user post to modal format with empty comments array
|
|
8506
|
+
const postData = {
|
|
8507
|
+
...post,
|
|
8508
|
+
postId: `user-${index}`,
|
|
8509
|
+
comments: [] // User posts don't have comments yet
|
|
8510
|
+
};
|
|
8511
|
+
await this.postModal.open({ ...postData, focusComment });
|
|
8512
|
+
}
|
|
8513
|
+
}
|
|
8514
|
+
async openPostCreator() {
|
|
8515
|
+
// Open the post creator as a bottom sheet modal
|
|
8516
|
+
// Using 95% initial height to maximize keyboard auto-open chances
|
|
8517
|
+
const sheet = await this.bottomSheet.create({
|
|
8518
|
+
component: DsMobilePostCreateBottomSheetComponent,
|
|
8519
|
+
componentProps: {
|
|
8520
|
+
// This helps the component know it should auto-focus
|
|
8521
|
+
autoFocus: true
|
|
8522
|
+
},
|
|
8523
|
+
breakpoints: [0, 0.95, 1],
|
|
8524
|
+
initialBreakpoint: 0.95,
|
|
8525
|
+
handle: true
|
|
8526
|
+
});
|
|
8527
|
+
// Handle the result when the sheet is dismissed
|
|
8528
|
+
const result = await sheet.onWillDismiss();
|
|
8529
|
+
if (result.role === 'post' && result.data) {
|
|
8530
|
+
console.log('New post created:', result.data);
|
|
8531
|
+
// Create a new post object
|
|
8532
|
+
const newPost = {
|
|
8533
|
+
id: `user-post-${Date.now()}`, // Generate unique ID
|
|
8534
|
+
authorName: 'Lars Mikkelsen', // Current user name
|
|
8535
|
+
authorRole: 'Dig',
|
|
8536
|
+
timestamp: 'Lige nu',
|
|
8537
|
+
avatarType: this.userService.avatarType(),
|
|
8538
|
+
avatarSrc: this.userService.avatarSrc(),
|
|
8539
|
+
avatarInitials: this.userService.avatarInitials(),
|
|
8540
|
+
content: result.data.content,
|
|
8541
|
+
imageSrc: result.data.images && result.data.images.length > 0 ? result.data.images[0] : undefined,
|
|
8542
|
+
imageAlt: result.data.images && result.data.images.length > 0 ? 'Slået billede op' : undefined,
|
|
8543
|
+
isLiked: false,
|
|
8544
|
+
likeCount: 0,
|
|
8545
|
+
commentCount: 0
|
|
8546
|
+
};
|
|
8547
|
+
// Add to the beginning of the posts array
|
|
8548
|
+
this.userPosts.update(posts => [newPost, ...posts]);
|
|
8549
|
+
}
|
|
8550
|
+
}
|
|
8551
|
+
/**
|
|
8552
|
+
* Open an image in the lightbox viewer
|
|
8553
|
+
* Prevents the post click event from firing
|
|
8554
|
+
*/
|
|
8555
|
+
async openImageLightbox(imageSrc, title, description, event) {
|
|
8556
|
+
console.log('[Community] Opening lightbox for image:', imageSrc);
|
|
8557
|
+
// Prevent the post card click event from firing
|
|
8558
|
+
event.stopPropagation();
|
|
8559
|
+
const authorMeta = {
|
|
8560
|
+
name: 'Sophie Andersen',
|
|
8561
|
+
role: 'Lejer',
|
|
8562
|
+
avatarInitials: 'SA',
|
|
8563
|
+
timestamp: '4t siden'
|
|
8564
|
+
};
|
|
8565
|
+
// Open the lightbox with the image
|
|
8566
|
+
await this.lightbox.open({
|
|
8567
|
+
images: [
|
|
8568
|
+
{
|
|
8569
|
+
type: 'image',
|
|
8570
|
+
src: imageSrc,
|
|
8571
|
+
alt: title,
|
|
8572
|
+
title: title,
|
|
8573
|
+
description: description,
|
|
8574
|
+
isLiked: true,
|
|
8575
|
+
likeCount: 156,
|
|
8576
|
+
commentCount: 34
|
|
8577
|
+
}
|
|
8578
|
+
],
|
|
8579
|
+
author: authorMeta,
|
|
8580
|
+
enableZoom: true,
|
|
8581
|
+
showControls: false, // Single image, no need for controls
|
|
8582
|
+
showInfo: true
|
|
8583
|
+
});
|
|
8584
|
+
}
|
|
8585
|
+
async openHouseRulesPdf() {
|
|
8586
|
+
console.log('[Community] Opening House Rules PDF');
|
|
8587
|
+
// Author metadata
|
|
8588
|
+
const authorMeta = {
|
|
8589
|
+
name: 'Karen Nielsen',
|
|
8590
|
+
role: 'Ejendomsadministrator',
|
|
8591
|
+
avatarInitials: 'KN',
|
|
8592
|
+
timestamp: '2d siden'
|
|
8593
|
+
};
|
|
8594
|
+
// Open the PDF lightbox
|
|
8595
|
+
// Use absolute path for production deployment (Vercel, etc.)
|
|
8596
|
+
await this.lightbox.openPdf({
|
|
8597
|
+
pdf: {
|
|
8598
|
+
type: 'pdf',
|
|
8599
|
+
src: '/Assets/House_Rules.pdf', // Capital A to match public/Assets folder structure
|
|
8600
|
+
title: 'House Rules',
|
|
8601
|
+
description: 'Building regulations and community guidelines',
|
|
8602
|
+
fileSize: 250880, // 245 KB in bytes
|
|
8603
|
+
pageCount: 8
|
|
8604
|
+
},
|
|
8605
|
+
author: authorMeta
|
|
8606
|
+
});
|
|
8607
|
+
}
|
|
8608
|
+
/**
|
|
8609
|
+
* Handle long press on a post to show action sheet
|
|
8610
|
+
*/
|
|
8611
|
+
async handlePostLongPress(postIdOrIndex, isOwnPost) {
|
|
8612
|
+
console.log('[Community] Post long pressed:', postIdOrIndex, 'isOwn:', isOwnPost);
|
|
8613
|
+
const sheet = await this.bottomSheet.create({
|
|
8614
|
+
component: DsMobileActionsBottomSheetComponent,
|
|
8615
|
+
componentProps: {
|
|
8616
|
+
isOwnContent: isOwnPost
|
|
8617
|
+
},
|
|
8618
|
+
breakpoints: [0, 1],
|
|
8619
|
+
initialBreakpoint: 1,
|
|
8620
|
+
handle: true,
|
|
8621
|
+
backdropDismiss: true,
|
|
8622
|
+
cssClass: 'auto-height'
|
|
8623
|
+
});
|
|
8624
|
+
const result = await sheet.onWillDismiss();
|
|
8625
|
+
if (result.role === 'select' && result.data) {
|
|
8626
|
+
const action = result.data.action;
|
|
8627
|
+
switch (action) {
|
|
8628
|
+
case 'edit':
|
|
8629
|
+
console.log('Edit post:', postIdOrIndex);
|
|
8630
|
+
// Open the post create bottom sheet in edit mode
|
|
8631
|
+
let postContent = '';
|
|
8632
|
+
let postId = '';
|
|
8633
|
+
// Get post content based on postIdOrIndex
|
|
8634
|
+
if (typeof postIdOrIndex === 'number') {
|
|
8635
|
+
const post = this.userPosts()[postIdOrIndex];
|
|
8636
|
+
if (post) {
|
|
8637
|
+
postContent = post.content || '';
|
|
8638
|
+
postId = post.id || postIdOrIndex.toString();
|
|
8639
|
+
}
|
|
8640
|
+
}
|
|
8641
|
+
else {
|
|
8642
|
+
// For static posts, we'll need to determine content
|
|
8643
|
+
// For now, use a placeholder
|
|
8644
|
+
postId = postIdOrIndex.toString();
|
|
8645
|
+
postContent = 'Edit this post...';
|
|
8646
|
+
}
|
|
8647
|
+
// Open the bottom sheet in edit mode
|
|
8648
|
+
const editSheet = await this.bottomSheet.create({
|
|
8649
|
+
component: DsMobilePostCreateBottomSheetComponent,
|
|
8650
|
+
componentProps: {
|
|
8651
|
+
autoFocus: true,
|
|
8652
|
+
isEditMode: true,
|
|
8653
|
+
postId: postId,
|
|
8654
|
+
initialContent: postContent
|
|
8655
|
+
},
|
|
8656
|
+
breakpoints: [0, 0.95, 1],
|
|
8657
|
+
initialBreakpoint: 0.95,
|
|
8658
|
+
handle: true,
|
|
8659
|
+
backdropBlur: true,
|
|
8660
|
+
backdropOpacity: 0.6
|
|
8661
|
+
});
|
|
8662
|
+
// Handle the result when the sheet is dismissed
|
|
8663
|
+
const editResult = await editSheet.onWillDismiss();
|
|
8664
|
+
if (editResult.role === 'post' && editResult.data) {
|
|
8665
|
+
console.log('Post updated:', editResult.data);
|
|
8666
|
+
// Update the post in the array
|
|
8667
|
+
if (typeof postIdOrIndex === 'number') {
|
|
8668
|
+
const currentPosts = this.userPosts();
|
|
8669
|
+
const updatedPosts = currentPosts.map((post, index) => index === postIdOrIndex
|
|
8670
|
+
? { ...post, content: editResult.data.content, timestamp: 'Just now' }
|
|
8671
|
+
: post);
|
|
8672
|
+
this.userPosts.set(updatedPosts);
|
|
8673
|
+
}
|
|
8674
|
+
}
|
|
8675
|
+
break;
|
|
8676
|
+
case 'delete':
|
|
8677
|
+
console.log('Delete post:', postIdOrIndex);
|
|
8678
|
+
if (confirm('Er du sikker på, at du vil slette dette opslag?')) {
|
|
8679
|
+
// If it's a user post (number index), remove it from the array
|
|
8680
|
+
if (typeof postIdOrIndex === 'number') {
|
|
8681
|
+
const currentPosts = this.userPosts();
|
|
8682
|
+
const updatedPosts = currentPosts.filter((_, index) => index !== postIdOrIndex);
|
|
8683
|
+
this.userPosts.set(updatedPosts);
|
|
8684
|
+
}
|
|
8685
|
+
// Otherwise it's a static post, just show confirmation
|
|
8686
|
+
else {
|
|
8687
|
+
alert('Opslag slettet!');
|
|
8688
|
+
}
|
|
8689
|
+
}
|
|
8690
|
+
break;
|
|
8691
|
+
case 'like':
|
|
8692
|
+
console.log('Like post:', postIdOrIndex);
|
|
8693
|
+
// Toggle like - in a real app, this would call an API
|
|
8694
|
+
alert('Opslag liket!');
|
|
8695
|
+
break;
|
|
8696
|
+
case 'reply':
|
|
8697
|
+
console.log('Reply to post:', postIdOrIndex);
|
|
8698
|
+
// Open the post detail modal with comment input focused
|
|
8699
|
+
if (typeof postIdOrIndex === 'number') {
|
|
8700
|
+
await this.openUserPost(postIdOrIndex, true);
|
|
8701
|
+
}
|
|
8702
|
+
else {
|
|
8703
|
+
await this.openPost(postIdOrIndex, true);
|
|
8704
|
+
}
|
|
8705
|
+
break;
|
|
8706
|
+
}
|
|
8707
|
+
}
|
|
8708
|
+
}
|
|
8709
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileCommunityPageComponent, deps: [{ token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: DsMobileBottomSheetService }, { token: DsMobileLightboxService }, { token: DsMobilePostDetailModalService }, { token: UserService }], target: i0.ɵɵFactoryTarget.Component });
|
|
8710
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: MobileCommunityPageComponent, isStandalone: true, selector: "app-mobile-community-page", ngImport: i0, template: `
|
|
8711
|
+
<ds-mobile-page-main
|
|
8712
|
+
title="Fællesskab"
|
|
8713
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
8714
|
+
[avatarType]="userService.avatarType()"
|
|
8715
|
+
(refresh)="handleRefresh($event)">
|
|
8716
|
+
|
|
8717
|
+
<!-- Post Composer in header-expandable -->
|
|
8718
|
+
<ds-mobile-post-composer
|
|
8719
|
+
header-content
|
|
8720
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
8721
|
+
[avatarType]="userService.avatarType()"
|
|
8722
|
+
[avatarSrc]="userService.avatarSrc()"
|
|
8723
|
+
(composerClick)="openPostCreator()"
|
|
8724
|
+
/>
|
|
8725
|
+
|
|
8726
|
+
<ds-mobile-content>
|
|
8727
|
+
<div class="post-feed">
|
|
8728
|
+
<!-- Pinned Posts Section -->
|
|
8729
|
+
<div class="pinned-posts-section">
|
|
8730
|
+
<h2 class="section-headline">
|
|
8731
|
+
<ds-icon name="remixPushpinFill" size="16px" color="primary" />
|
|
8732
|
+
Fastgjorte opslag
|
|
8733
|
+
</h2>
|
|
8734
|
+
|
|
8735
|
+
<!-- Pinned: Maintenance Announcement -->
|
|
8736
|
+
<ds-mobile-interactive-list-item-post
|
|
8737
|
+
[authorName]="'Karen Nielsen'"
|
|
8738
|
+
[authorRole]="'Ejendomsadministrator'"
|
|
8739
|
+
[timestamp]="'2d siden'"
|
|
8740
|
+
[avatarInitials]="'KN'"
|
|
8741
|
+
[showBadge]="true"
|
|
8742
|
+
[clickable]="true"
|
|
8743
|
+
(postClick)="openPost('4')"
|
|
8744
|
+
(commentClick)="openPost('4', true)"
|
|
8745
|
+
(longPress)="handlePostLongPress('4', false)">
|
|
8746
|
+
|
|
8747
|
+
<post-content>
|
|
8748
|
+
<post-text>📢 Påmindelse: Bygningsvedligeholdelse planlagt til denne lørdag fra kl. 9 til 14. Vandet vil være midlertidigt lukket. Vær venlig at planlægge derefter!</post-text>
|
|
8749
|
+
|
|
8750
|
+
<post-attachments>
|
|
8751
|
+
<post-pdf-attachment
|
|
8752
|
+
[fileName]="'Husregler.pdf'"
|
|
8753
|
+
[fileSize]="'245 KB'"
|
|
8754
|
+
(pdfClick)="openHouseRulesPdf()">
|
|
8755
|
+
</post-pdf-attachment>
|
|
8756
|
+
</post-attachments>
|
|
8757
|
+
</post-content>
|
|
8758
|
+
|
|
8759
|
+
<post-actions>
|
|
8760
|
+
<action-like [count]="89" />
|
|
8761
|
+
<action-comment [count]="67" (commentClick)="openPost('4', true)" />
|
|
8762
|
+
</post-actions>
|
|
8763
|
+
</ds-mobile-interactive-list-item-post>
|
|
8764
|
+
</div>
|
|
8765
|
+
|
|
8766
|
+
<!-- All Posts Section -->
|
|
8767
|
+
<h2 class="section-headline">Alle opslag</h2>
|
|
8768
|
+
|
|
8769
|
+
@if (hasAnyPosts()) {
|
|
8770
|
+
<div class="post-list-wrapper">
|
|
8771
|
+
<!-- User Created Posts -->
|
|
8772
|
+
@for (post of userPosts(); track $index) {
|
|
8773
|
+
<ds-mobile-interactive-list-item-post
|
|
8774
|
+
[authorName]="post.authorName"
|
|
8775
|
+
[authorRole]="post.authorRole"
|
|
8776
|
+
[timestamp]="post.timestamp"
|
|
8777
|
+
[avatarType]="post.avatarType"
|
|
8778
|
+
[avatarSrc]="post.avatarSrc"
|
|
8779
|
+
[avatarInitials]="post.avatarInitials"
|
|
8780
|
+
[clickable]="true"
|
|
8781
|
+
(postClick)="openUserPost($index)"
|
|
8782
|
+
(commentClick)="openUserPost($index, true)"
|
|
8783
|
+
(longPress)="handlePostLongPress($index, post.authorRole === 'Dig')">
|
|
8784
|
+
|
|
8785
|
+
<post-content>
|
|
8786
|
+
@if (post.content) {
|
|
8787
|
+
<post-text>{{ post.content }}</post-text>
|
|
8788
|
+
}
|
|
8789
|
+
@if (post.imageSrc) {
|
|
8790
|
+
<post-media>
|
|
8791
|
+
<img
|
|
8792
|
+
[src]="post.imageSrc"
|
|
8793
|
+
[alt]="post.imageAlt || 'Posted image'"
|
|
8794
|
+
class="clickable-image"
|
|
8795
|
+
(click)="openImageLightbox(post.imageSrc, post.imageAlt || 'Posted image', post.content, $event)"
|
|
8796
|
+
/>
|
|
8797
|
+
</post-media>
|
|
8798
|
+
}
|
|
8799
|
+
</post-content>
|
|
8800
|
+
|
|
8801
|
+
<post-actions>
|
|
8802
|
+
<action-like [count]="post.likeCount" [active]="post.isLiked" />
|
|
8803
|
+
<action-comment [count]="post.commentCount" (commentClick)="openUserPost($index, true)" />
|
|
8804
|
+
</post-actions>
|
|
8805
|
+
</ds-mobile-interactive-list-item-post>
|
|
8806
|
+
}
|
|
8807
|
+
|
|
8808
|
+
<!-- Post 1: Text only -->
|
|
8809
|
+
<ds-mobile-interactive-list-item-post
|
|
8810
|
+
[authorName]="'Anders Jensen'"
|
|
8811
|
+
[authorRole]="'Lejer'"
|
|
8812
|
+
[timestamp]="'2t siden'"
|
|
8813
|
+
[avatarType]="'photo'"
|
|
8814
|
+
[avatarSrc]="'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop&crop=face'"
|
|
8815
|
+
[clickable]="true"
|
|
8816
|
+
(postClick)="openPost('1')"
|
|
8817
|
+
(commentClick)="openPost('1', true)"
|
|
8818
|
+
(longPress)="handlePostLongPress('1', false)">
|
|
8819
|
+
|
|
8820
|
+
<post-content>
|
|
8821
|
+
<post-text>Lige flyttet ind i min nye lejlighed! Udlejeren var super hjælpsom gennem hele processen. Virkelig begejstret for at være en del af dette fællesskab! 🏠</post-text>
|
|
8822
|
+
</post-content>
|
|
8823
|
+
|
|
8824
|
+
<post-actions>
|
|
8825
|
+
<action-like [count]="42" />
|
|
8826
|
+
<action-comment [count]="12" (commentClick)="openPost('1', true)" />
|
|
8827
|
+
</post-actions>
|
|
8828
|
+
</ds-mobile-interactive-list-item-post>
|
|
8829
|
+
|
|
8830
|
+
<!-- Post 2: With multiple images (grid layout) -->
|
|
8831
|
+
<ds-mobile-interactive-list-item-post
|
|
8832
|
+
[authorName]="'Sophie Andersen'"
|
|
8833
|
+
[authorRole]="'Lejer'"
|
|
8834
|
+
[timestamp]="'4t siden'"
|
|
8835
|
+
[avatarInitials]="'SA'"
|
|
8836
|
+
[clickable]="true"
|
|
8837
|
+
(postClick)="openPost('2')"
|
|
8838
|
+
(commentClick)="openPost('2', true)"
|
|
8839
|
+
(longPress)="handlePostLongPress('2', false)">
|
|
8840
|
+
|
|
8841
|
+
<post-content>
|
|
8842
|
+
<post-text>Jeg har taget nogle billeder af vores smukke ejendom i løbet af det sidste par måneder. Fra altanudsigten om morgenen til den nye trappe og fællesområderne. Elsker virkelig at bo her! 🏡✨</post-text>
|
|
8843
|
+
<ds-mobile-inline-photo
|
|
8844
|
+
[images]="[
|
|
8845
|
+
'/Assets/Dummy-photos/balcony-view.jpg',
|
|
8846
|
+
'/Assets/Dummy-photos/staircase.jpg',
|
|
8847
|
+
'/Assets/Dummy-photos/park.jpg',
|
|
8848
|
+
'/Assets/Dummy-photos/yard.jpg'
|
|
8849
|
+
]"
|
|
8850
|
+
[author]="{
|
|
8851
|
+
name: 'Sophie Andersen',
|
|
8852
|
+
role: 'Lejer',
|
|
8853
|
+
avatarInitials: 'SA',
|
|
8854
|
+
avatarType: 'initials',
|
|
8855
|
+
timestamp: '4t siden'
|
|
8856
|
+
}"
|
|
8857
|
+
/>
|
|
8858
|
+
</post-content>
|
|
8859
|
+
|
|
8860
|
+
<post-actions>
|
|
8861
|
+
<action-like [active]="true" [count]="156" />
|
|
8862
|
+
<action-comment [count]="34" (commentClick)="openPost('2', true)" />
|
|
8863
|
+
</post-actions>
|
|
8864
|
+
</ds-mobile-interactive-list-item-post>
|
|
8865
|
+
|
|
8866
|
+
<!-- Post 3: Question -->
|
|
8867
|
+
<ds-mobile-interactive-list-item-post
|
|
8868
|
+
[authorName]="'Thomas Hansen'"
|
|
8869
|
+
[authorRole]="'Lejer'"
|
|
8870
|
+
[timestamp]="'1d siden'"
|
|
8871
|
+
[avatarType]="'photo'"
|
|
8872
|
+
[avatarSrc]="'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face'"
|
|
8873
|
+
[clickable]="true"
|
|
8874
|
+
(postClick)="openPost('3')"
|
|
8875
|
+
(commentClick)="openPost('3', true)"
|
|
8876
|
+
(longPress)="handlePostLongPress('3', false)">
|
|
8877
|
+
|
|
8878
|
+
<post-content>
|
|
8879
|
+
<post-text>Kender nogen et fælles fitnesscenter i nærheden? Leder efter anbefalinger til gode træningscentre i området. 🏋️</post-text>
|
|
8880
|
+
</post-content>
|
|
8881
|
+
|
|
8882
|
+
<post-actions>
|
|
8883
|
+
<action-like [count]="23" />
|
|
8884
|
+
<action-comment [count]="45" (commentClick)="openPost('3', true)" />
|
|
8885
|
+
</post-actions>
|
|
8886
|
+
</ds-mobile-interactive-list-item-post>
|
|
8887
|
+
|
|
8888
|
+
<!-- Post 3.5: Property Manager showcase with 6+ photos -->
|
|
8889
|
+
<ds-mobile-interactive-list-item-post
|
|
8890
|
+
[authorName]="'Karen Nielsen'"
|
|
8891
|
+
[authorRole]="'Ejendomsadministrator'"
|
|
8892
|
+
[timestamp]="'2d siden'"
|
|
8893
|
+
[avatarInitials]="'KN'"
|
|
8894
|
+
[showBadge]="true"
|
|
8895
|
+
[clickable]="true"
|
|
8896
|
+
(postClick)="openPost('3.5')"
|
|
8897
|
+
(commentClick)="openPost('3.5', true)"
|
|
8898
|
+
(longPress)="handlePostLongPress('3.5', false)">
|
|
8899
|
+
|
|
8900
|
+
<post-content>
|
|
8901
|
+
<post-text>Her er et kig på vores nyligt renoverede fællesområder! Vi har opgraderet postkasserne, trappeafsatsen og gårdområdet. Der er også blevet ansat en ny vicevært. Glæd dig over forbedringerne! 🏢✨</post-text>
|
|
8902
|
+
<ds-mobile-inline-photo
|
|
8903
|
+
[images]="[
|
|
8904
|
+
'/Assets/Dummy-photos/mailboxes.jpg',
|
|
8905
|
+
'/Assets/Dummy-photos/staircase.jpg',
|
|
8906
|
+
'/Assets/Dummy-photos/yard.jpg',
|
|
8907
|
+
'/Assets/Dummy-photos/park.jpg',
|
|
8908
|
+
'/Assets/Dummy-photos/balcony-view.jpg',
|
|
8909
|
+
'/Assets/Dummy-photos/handyman.jpg'
|
|
8910
|
+
]"
|
|
8911
|
+
[author]="{
|
|
8912
|
+
name: 'Karen Nielsen',
|
|
8913
|
+
role: 'Ejendomsadministrator',
|
|
8914
|
+
avatarInitials: 'KN',
|
|
8915
|
+
avatarType: 'initials',
|
|
8916
|
+
timestamp: '2d siden'
|
|
8917
|
+
}"
|
|
8918
|
+
[maxVisible]="5"
|
|
8919
|
+
/>
|
|
8920
|
+
</post-content>
|
|
8921
|
+
|
|
8922
|
+
<post-actions>
|
|
8923
|
+
<action-like [count]="234" />
|
|
8924
|
+
<action-comment [count]="89" (commentClick)="openPost('3.5', true)" />
|
|
8925
|
+
</post-actions>
|
|
8926
|
+
</ds-mobile-interactive-list-item-post>
|
|
8927
|
+
|
|
8928
|
+
<!-- Post 5: Event -->
|
|
8929
|
+
<ds-mobile-interactive-list-item-post
|
|
8930
|
+
[authorName]="'Emma Petersen'"
|
|
8931
|
+
[authorRole]="'Lejer'"
|
|
8932
|
+
[timestamp]="'3d siden'"
|
|
8933
|
+
[avatarType]="'photo'"
|
|
8934
|
+
[avatarSrc]="'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face'"
|
|
8935
|
+
[clickable]="true"
|
|
8936
|
+
(postClick)="openPost('5')"
|
|
8937
|
+
(commentClick)="openPost('5', true)"
|
|
8938
|
+
(longPress)="handlePostLongPress('5', false)">
|
|
8939
|
+
|
|
8940
|
+
<post-content>
|
|
8941
|
+
<post-text>Arrangerer en fælles BBQ næste weekend! Alle er inviteret. Tag din yndlingsret med til at dele. Lad os lære hinanden bedre at kende! 🍔🌭</post-text>
|
|
8942
|
+
</post-content>
|
|
8943
|
+
|
|
8944
|
+
<post-actions>
|
|
8945
|
+
<action-like [active]="true" [count]="124" />
|
|
8946
|
+
<action-comment [count]="89" (commentClick)="openPost('5', true)" />
|
|
8947
|
+
</post-actions>
|
|
8948
|
+
</ds-mobile-interactive-list-item-post>
|
|
8949
|
+
</div>
|
|
8950
|
+
} @else {
|
|
8951
|
+
<!-- Empty State -->
|
|
8952
|
+
<div class="community-empty-state">
|
|
8953
|
+
<img
|
|
8954
|
+
src="/Assets/Empty state-chat.png"
|
|
8955
|
+
alt="Ingen opslag endnu"
|
|
8956
|
+
class="empty-state-image"
|
|
8957
|
+
/>
|
|
8958
|
+
<h3 class="empty-state-title">Ingen opslag endnu</h3>
|
|
8959
|
+
<p class="empty-state-description">Vær den første til at dele noget med dit fællesskab</p>
|
|
8960
|
+
</div>
|
|
8961
|
+
}
|
|
8962
|
+
</div>
|
|
8963
|
+
</ds-mobile-content>
|
|
8964
|
+
</ds-mobile-page-main>
|
|
8965
|
+
`, 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: PostPdfAttachmentComponent, selector: "post-pdf-attachment", inputs: ["fileName", "fileSize"], outputs: ["pdfClick"] }, { 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"] }] });
|
|
8966
|
+
}
|
|
8967
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileCommunityPageComponent, decorators: [{
|
|
8968
|
+
type: Component,
|
|
8969
|
+
args: [{ selector: 'app-mobile-community-page', standalone: true, imports: [
|
|
8970
|
+
DsMobilePageMainComponent,
|
|
8971
|
+
DsMobileContentComponent,
|
|
8972
|
+
DsMobileInteractiveListItemPostComponent,
|
|
8973
|
+
DsMobilePostComposerComponent,
|
|
8974
|
+
PostContentComponent,
|
|
8975
|
+
PostTextComponent,
|
|
8976
|
+
PostMediaComponent,
|
|
8977
|
+
PostAttachmentsComponent,
|
|
8978
|
+
PostActionsComponent,
|
|
8979
|
+
ActionLikeComponent,
|
|
8980
|
+
ActionCommentComponent,
|
|
8981
|
+
PostPdfAttachmentComponent,
|
|
8982
|
+
DsIconComponent,
|
|
8983
|
+
DsMobileInlinePhotoComponent
|
|
8984
|
+
], template: `
|
|
8985
|
+
<ds-mobile-page-main
|
|
8986
|
+
title="Fællesskab"
|
|
8987
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
8988
|
+
[avatarType]="userService.avatarType()"
|
|
8989
|
+
(refresh)="handleRefresh($event)">
|
|
8990
|
+
|
|
8991
|
+
<!-- Post Composer in header-expandable -->
|
|
8992
|
+
<ds-mobile-post-composer
|
|
8993
|
+
header-content
|
|
8994
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
8995
|
+
[avatarType]="userService.avatarType()"
|
|
8996
|
+
[avatarSrc]="userService.avatarSrc()"
|
|
8997
|
+
(composerClick)="openPostCreator()"
|
|
8998
|
+
/>
|
|
8999
|
+
|
|
9000
|
+
<ds-mobile-content>
|
|
9001
|
+
<div class="post-feed">
|
|
9002
|
+
<!-- Pinned Posts Section -->
|
|
9003
|
+
<div class="pinned-posts-section">
|
|
9004
|
+
<h2 class="section-headline">
|
|
9005
|
+
<ds-icon name="remixPushpinFill" size="16px" color="primary" />
|
|
9006
|
+
Fastgjorte opslag
|
|
9007
|
+
</h2>
|
|
9008
|
+
|
|
9009
|
+
<!-- Pinned: Maintenance Announcement -->
|
|
9010
|
+
<ds-mobile-interactive-list-item-post
|
|
9011
|
+
[authorName]="'Karen Nielsen'"
|
|
9012
|
+
[authorRole]="'Ejendomsadministrator'"
|
|
9013
|
+
[timestamp]="'2d siden'"
|
|
9014
|
+
[avatarInitials]="'KN'"
|
|
9015
|
+
[showBadge]="true"
|
|
9016
|
+
[clickable]="true"
|
|
9017
|
+
(postClick)="openPost('4')"
|
|
9018
|
+
(commentClick)="openPost('4', true)"
|
|
9019
|
+
(longPress)="handlePostLongPress('4', false)">
|
|
9020
|
+
|
|
9021
|
+
<post-content>
|
|
9022
|
+
<post-text>📢 Påmindelse: Bygningsvedligeholdelse planlagt til denne lørdag fra kl. 9 til 14. Vandet vil være midlertidigt lukket. Vær venlig at planlægge derefter!</post-text>
|
|
9023
|
+
|
|
9024
|
+
<post-attachments>
|
|
9025
|
+
<post-pdf-attachment
|
|
9026
|
+
[fileName]="'Husregler.pdf'"
|
|
9027
|
+
[fileSize]="'245 KB'"
|
|
9028
|
+
(pdfClick)="openHouseRulesPdf()">
|
|
9029
|
+
</post-pdf-attachment>
|
|
9030
|
+
</post-attachments>
|
|
9031
|
+
</post-content>
|
|
9032
|
+
|
|
9033
|
+
<post-actions>
|
|
9034
|
+
<action-like [count]="89" />
|
|
9035
|
+
<action-comment [count]="67" (commentClick)="openPost('4', true)" />
|
|
9036
|
+
</post-actions>
|
|
9037
|
+
</ds-mobile-interactive-list-item-post>
|
|
9038
|
+
</div>
|
|
9039
|
+
|
|
9040
|
+
<!-- All Posts Section -->
|
|
9041
|
+
<h2 class="section-headline">Alle opslag</h2>
|
|
9042
|
+
|
|
9043
|
+
@if (hasAnyPosts()) {
|
|
9044
|
+
<div class="post-list-wrapper">
|
|
9045
|
+
<!-- User Created Posts -->
|
|
9046
|
+
@for (post of userPosts(); track $index) {
|
|
9047
|
+
<ds-mobile-interactive-list-item-post
|
|
9048
|
+
[authorName]="post.authorName"
|
|
9049
|
+
[authorRole]="post.authorRole"
|
|
9050
|
+
[timestamp]="post.timestamp"
|
|
9051
|
+
[avatarType]="post.avatarType"
|
|
9052
|
+
[avatarSrc]="post.avatarSrc"
|
|
9053
|
+
[avatarInitials]="post.avatarInitials"
|
|
9054
|
+
[clickable]="true"
|
|
9055
|
+
(postClick)="openUserPost($index)"
|
|
9056
|
+
(commentClick)="openUserPost($index, true)"
|
|
9057
|
+
(longPress)="handlePostLongPress($index, post.authorRole === 'Dig')">
|
|
9058
|
+
|
|
9059
|
+
<post-content>
|
|
9060
|
+
@if (post.content) {
|
|
9061
|
+
<post-text>{{ post.content }}</post-text>
|
|
9062
|
+
}
|
|
9063
|
+
@if (post.imageSrc) {
|
|
9064
|
+
<post-media>
|
|
9065
|
+
<img
|
|
9066
|
+
[src]="post.imageSrc"
|
|
9067
|
+
[alt]="post.imageAlt || 'Posted image'"
|
|
9068
|
+
class="clickable-image"
|
|
9069
|
+
(click)="openImageLightbox(post.imageSrc, post.imageAlt || 'Posted image', post.content, $event)"
|
|
9070
|
+
/>
|
|
9071
|
+
</post-media>
|
|
9072
|
+
}
|
|
9073
|
+
</post-content>
|
|
9074
|
+
|
|
9075
|
+
<post-actions>
|
|
9076
|
+
<action-like [count]="post.likeCount" [active]="post.isLiked" />
|
|
9077
|
+
<action-comment [count]="post.commentCount" (commentClick)="openUserPost($index, true)" />
|
|
9078
|
+
</post-actions>
|
|
9079
|
+
</ds-mobile-interactive-list-item-post>
|
|
9080
|
+
}
|
|
9081
|
+
|
|
9082
|
+
<!-- Post 1: Text only -->
|
|
9083
|
+
<ds-mobile-interactive-list-item-post
|
|
9084
|
+
[authorName]="'Anders Jensen'"
|
|
9085
|
+
[authorRole]="'Lejer'"
|
|
9086
|
+
[timestamp]="'2t siden'"
|
|
9087
|
+
[avatarType]="'photo'"
|
|
9088
|
+
[avatarSrc]="'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop&crop=face'"
|
|
9089
|
+
[clickable]="true"
|
|
9090
|
+
(postClick)="openPost('1')"
|
|
9091
|
+
(commentClick)="openPost('1', true)"
|
|
9092
|
+
(longPress)="handlePostLongPress('1', false)">
|
|
9093
|
+
|
|
9094
|
+
<post-content>
|
|
9095
|
+
<post-text>Lige flyttet ind i min nye lejlighed! Udlejeren var super hjælpsom gennem hele processen. Virkelig begejstret for at være en del af dette fællesskab! 🏠</post-text>
|
|
9096
|
+
</post-content>
|
|
9097
|
+
|
|
9098
|
+
<post-actions>
|
|
9099
|
+
<action-like [count]="42" />
|
|
9100
|
+
<action-comment [count]="12" (commentClick)="openPost('1', true)" />
|
|
9101
|
+
</post-actions>
|
|
9102
|
+
</ds-mobile-interactive-list-item-post>
|
|
9103
|
+
|
|
9104
|
+
<!-- Post 2: With multiple images (grid layout) -->
|
|
9105
|
+
<ds-mobile-interactive-list-item-post
|
|
9106
|
+
[authorName]="'Sophie Andersen'"
|
|
9107
|
+
[authorRole]="'Lejer'"
|
|
9108
|
+
[timestamp]="'4t siden'"
|
|
9109
|
+
[avatarInitials]="'SA'"
|
|
9110
|
+
[clickable]="true"
|
|
9111
|
+
(postClick)="openPost('2')"
|
|
9112
|
+
(commentClick)="openPost('2', true)"
|
|
9113
|
+
(longPress)="handlePostLongPress('2', false)">
|
|
9114
|
+
|
|
9115
|
+
<post-content>
|
|
9116
|
+
<post-text>Jeg har taget nogle billeder af vores smukke ejendom i løbet af det sidste par måneder. Fra altanudsigten om morgenen til den nye trappe og fællesområderne. Elsker virkelig at bo her! 🏡✨</post-text>
|
|
9117
|
+
<ds-mobile-inline-photo
|
|
9118
|
+
[images]="[
|
|
9119
|
+
'/Assets/Dummy-photos/balcony-view.jpg',
|
|
9120
|
+
'/Assets/Dummy-photos/staircase.jpg',
|
|
9121
|
+
'/Assets/Dummy-photos/park.jpg',
|
|
9122
|
+
'/Assets/Dummy-photos/yard.jpg'
|
|
9123
|
+
]"
|
|
9124
|
+
[author]="{
|
|
9125
|
+
name: 'Sophie Andersen',
|
|
9126
|
+
role: 'Lejer',
|
|
9127
|
+
avatarInitials: 'SA',
|
|
9128
|
+
avatarType: 'initials',
|
|
9129
|
+
timestamp: '4t siden'
|
|
9130
|
+
}"
|
|
9131
|
+
/>
|
|
9132
|
+
</post-content>
|
|
9133
|
+
|
|
9134
|
+
<post-actions>
|
|
9135
|
+
<action-like [active]="true" [count]="156" />
|
|
9136
|
+
<action-comment [count]="34" (commentClick)="openPost('2', true)" />
|
|
9137
|
+
</post-actions>
|
|
9138
|
+
</ds-mobile-interactive-list-item-post>
|
|
9139
|
+
|
|
9140
|
+
<!-- Post 3: Question -->
|
|
9141
|
+
<ds-mobile-interactive-list-item-post
|
|
9142
|
+
[authorName]="'Thomas Hansen'"
|
|
9143
|
+
[authorRole]="'Lejer'"
|
|
9144
|
+
[timestamp]="'1d siden'"
|
|
9145
|
+
[avatarType]="'photo'"
|
|
9146
|
+
[avatarSrc]="'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face'"
|
|
9147
|
+
[clickable]="true"
|
|
9148
|
+
(postClick)="openPost('3')"
|
|
9149
|
+
(commentClick)="openPost('3', true)"
|
|
9150
|
+
(longPress)="handlePostLongPress('3', false)">
|
|
9151
|
+
|
|
9152
|
+
<post-content>
|
|
9153
|
+
<post-text>Kender nogen et fælles fitnesscenter i nærheden? Leder efter anbefalinger til gode træningscentre i området. 🏋️</post-text>
|
|
9154
|
+
</post-content>
|
|
9155
|
+
|
|
9156
|
+
<post-actions>
|
|
9157
|
+
<action-like [count]="23" />
|
|
9158
|
+
<action-comment [count]="45" (commentClick)="openPost('3', true)" />
|
|
9159
|
+
</post-actions>
|
|
9160
|
+
</ds-mobile-interactive-list-item-post>
|
|
9161
|
+
|
|
9162
|
+
<!-- Post 3.5: Property Manager showcase with 6+ photos -->
|
|
9163
|
+
<ds-mobile-interactive-list-item-post
|
|
9164
|
+
[authorName]="'Karen Nielsen'"
|
|
9165
|
+
[authorRole]="'Ejendomsadministrator'"
|
|
9166
|
+
[timestamp]="'2d siden'"
|
|
9167
|
+
[avatarInitials]="'KN'"
|
|
9168
|
+
[showBadge]="true"
|
|
9169
|
+
[clickable]="true"
|
|
9170
|
+
(postClick)="openPost('3.5')"
|
|
9171
|
+
(commentClick)="openPost('3.5', true)"
|
|
9172
|
+
(longPress)="handlePostLongPress('3.5', false)">
|
|
9173
|
+
|
|
9174
|
+
<post-content>
|
|
9175
|
+
<post-text>Her er et kig på vores nyligt renoverede fællesområder! Vi har opgraderet postkasserne, trappeafsatsen og gårdområdet. Der er også blevet ansat en ny vicevært. Glæd dig over forbedringerne! 🏢✨</post-text>
|
|
9176
|
+
<ds-mobile-inline-photo
|
|
9177
|
+
[images]="[
|
|
9178
|
+
'/Assets/Dummy-photos/mailboxes.jpg',
|
|
9179
|
+
'/Assets/Dummy-photos/staircase.jpg',
|
|
9180
|
+
'/Assets/Dummy-photos/yard.jpg',
|
|
9181
|
+
'/Assets/Dummy-photos/park.jpg',
|
|
9182
|
+
'/Assets/Dummy-photos/balcony-view.jpg',
|
|
9183
|
+
'/Assets/Dummy-photos/handyman.jpg'
|
|
9184
|
+
]"
|
|
9185
|
+
[author]="{
|
|
9186
|
+
name: 'Karen Nielsen',
|
|
9187
|
+
role: 'Ejendomsadministrator',
|
|
9188
|
+
avatarInitials: 'KN',
|
|
9189
|
+
avatarType: 'initials',
|
|
9190
|
+
timestamp: '2d siden'
|
|
9191
|
+
}"
|
|
9192
|
+
[maxVisible]="5"
|
|
9193
|
+
/>
|
|
9194
|
+
</post-content>
|
|
9195
|
+
|
|
9196
|
+
<post-actions>
|
|
9197
|
+
<action-like [count]="234" />
|
|
9198
|
+
<action-comment [count]="89" (commentClick)="openPost('3.5', true)" />
|
|
9199
|
+
</post-actions>
|
|
9200
|
+
</ds-mobile-interactive-list-item-post>
|
|
9201
|
+
|
|
9202
|
+
<!-- Post 5: Event -->
|
|
9203
|
+
<ds-mobile-interactive-list-item-post
|
|
9204
|
+
[authorName]="'Emma Petersen'"
|
|
9205
|
+
[authorRole]="'Lejer'"
|
|
9206
|
+
[timestamp]="'3d siden'"
|
|
9207
|
+
[avatarType]="'photo'"
|
|
9208
|
+
[avatarSrc]="'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face'"
|
|
9209
|
+
[clickable]="true"
|
|
9210
|
+
(postClick)="openPost('5')"
|
|
9211
|
+
(commentClick)="openPost('5', true)"
|
|
9212
|
+
(longPress)="handlePostLongPress('5', false)">
|
|
9213
|
+
|
|
9214
|
+
<post-content>
|
|
9215
|
+
<post-text>Arrangerer en fælles BBQ næste weekend! Alle er inviteret. Tag din yndlingsret med til at dele. Lad os lære hinanden bedre at kende! 🍔🌭</post-text>
|
|
9216
|
+
</post-content>
|
|
9217
|
+
|
|
9218
|
+
<post-actions>
|
|
9219
|
+
<action-like [active]="true" [count]="124" />
|
|
9220
|
+
<action-comment [count]="89" (commentClick)="openPost('5', true)" />
|
|
9221
|
+
</post-actions>
|
|
9222
|
+
</ds-mobile-interactive-list-item-post>
|
|
9223
|
+
</div>
|
|
9224
|
+
} @else {
|
|
9225
|
+
<!-- Empty State -->
|
|
9226
|
+
<div class="community-empty-state">
|
|
9227
|
+
<img
|
|
9228
|
+
src="/Assets/Empty state-chat.png"
|
|
9229
|
+
alt="Ingen opslag endnu"
|
|
9230
|
+
class="empty-state-image"
|
|
9231
|
+
/>
|
|
9232
|
+
<h3 class="empty-state-title">Ingen opslag endnu</h3>
|
|
9233
|
+
<p class="empty-state-description">Vær den første til at dele noget med dit fællesskab</p>
|
|
9234
|
+
</div>
|
|
9235
|
+
}
|
|
9236
|
+
</div>
|
|
9237
|
+
</ds-mobile-content>
|
|
9238
|
+
</ds-mobile-page-main>
|
|
9239
|
+
`, 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"] }]
|
|
9240
|
+
}], ctorParameters: () => [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: DsMobileBottomSheetService }, { type: DsMobileLightboxService }, { type: DsMobilePostDetailModalService }, { type: UserService }] });
|
|
9241
|
+
|
|
9242
|
+
class MobileHandbookPageComponent {
|
|
9243
|
+
userService;
|
|
9244
|
+
// Utilities folder data
|
|
9245
|
+
utilitiesItems = [
|
|
9246
|
+
{
|
|
9247
|
+
title: 'El',
|
|
9248
|
+
description: 'Hovedeltavle placeret i kælderrum B-12. Nødafbryderknap er ved hovedindgangen. Alle kredsløb er mærket.',
|
|
9249
|
+
contacts: [
|
|
9250
|
+
{ name: 'ElektroTek ApS', initials: 'E', contactPerson: 'Lars Nielsen', phoneNumber: '+45 23 45 67 89' }
|
|
9251
|
+
]
|
|
9252
|
+
},
|
|
9253
|
+
{
|
|
9254
|
+
title: 'Elektrisk diagram',
|
|
9255
|
+
description: 'Komplet diagram over bygningens elektriske installation med alle kredsløb og afbrydere.',
|
|
9256
|
+
attachments: [
|
|
9257
|
+
{ name: 'Elektrisk_Diagram.pdf', type: 'pdf' }
|
|
9258
|
+
]
|
|
9259
|
+
},
|
|
9260
|
+
{
|
|
9261
|
+
title: 'Vandforsyning',
|
|
9262
|
+
description: 'Hovedvandhane er placeret i kælderens tekniske rum. Individuelle lejlighedsafspærringer er i gangpanelerne. Vandtryk overvåges automatisk.',
|
|
9263
|
+
contacts: [
|
|
9264
|
+
{ name: 'VVS Hansen', initials: 'V', contactPerson: 'Peter Hansen', phoneNumber: '+45 34 56 78 90' }
|
|
9265
|
+
]
|
|
9266
|
+
},
|
|
9267
|
+
{
|
|
9268
|
+
title: 'Varmesystem',
|
|
9269
|
+
description: 'Fjernvarmetilslutning i kælder. Termostater i hver enhed kan justeres individuelt. Systemet vedligeholdes kvartalsvis af certificerede teknikere.',
|
|
9270
|
+
contacts: [
|
|
9271
|
+
{ name: 'Varme Service A/S', initials: 'V', contactPerson: 'Maria Jensen', phoneNumber: '+45 45 67 89 01' }
|
|
9272
|
+
]
|
|
9273
|
+
},
|
|
9274
|
+
{
|
|
9275
|
+
title: 'Varmeanlæg dokumentation',
|
|
9276
|
+
description: 'Teknisk dokumentation og vedligeholdelseshistorik for bygningens varmesystem.',
|
|
9277
|
+
attachments: [
|
|
9278
|
+
{ name: 'Varmeplan.pdf', type: 'pdf' },
|
|
9279
|
+
{ name: 'Vedligeholdelseslog.pdf', type: 'pdf' }
|
|
9280
|
+
]
|
|
9281
|
+
},
|
|
9282
|
+
{
|
|
9283
|
+
title: 'Internet & TV',
|
|
9284
|
+
description: 'Fiberforbindelse i bygningen. Distributionspanel er i stueetageteknisk rum. Hver lejlighed har ethernet-stik i stue og soveværelser.',
|
|
9285
|
+
contacts: [
|
|
9286
|
+
{ name: 'TeleCom Solutions', initials: 'T', contactPerson: 'Anders Petersen', phoneNumber: '+45 56 78 90 12' }
|
|
9287
|
+
]
|
|
9288
|
+
},
|
|
9289
|
+
{
|
|
9290
|
+
title: 'Netværksopsætning guide',
|
|
9291
|
+
attachments: [
|
|
9292
|
+
{ name: 'Netværksopsætning.pdf', type: 'pdf' }
|
|
9293
|
+
]
|
|
9294
|
+
},
|
|
9295
|
+
{
|
|
9296
|
+
title: 'Affaldshåndtering',
|
|
9297
|
+
description: 'Affaldssorteringsstation placeret i gården. Afhentninger: Dagrenovation (man/tor), Genbrug (ons), Organisk (tir/fre). Storskrald kræver booking.',
|
|
9298
|
+
attachments: [
|
|
9299
|
+
{ name: 'Affaldsretningslinjer.pdf', type: 'pdf' }
|
|
9300
|
+
]
|
|
9301
|
+
}
|
|
9302
|
+
];
|
|
9303
|
+
// Safety Equipment folder data
|
|
9304
|
+
sikkerhedsudstyrItems = [
|
|
9305
|
+
{
|
|
9306
|
+
title: 'Fælles områder og sikkerhed',
|
|
9307
|
+
description: 'Trappeopgange med nødbelysning og brandsikre døre. Postkasser placeret i indgangspartiet. Hold altid flugtveje fri.',
|
|
9308
|
+
images: [
|
|
9309
|
+
'/Assets/Dummy-photos/staircase.jpg',
|
|
9310
|
+
'/Assets/Dummy-photos/mailboxes.jpg'
|
|
9311
|
+
]
|
|
9312
|
+
},
|
|
9313
|
+
{
|
|
9314
|
+
title: 'Hjertestarter (AED)',
|
|
9315
|
+
description: 'Automatisk hjertestarter placeret i stueetagen ved hovedindgangen. Tilgængelig 24/7. Ingen særlig uddannelse kræves - enheden guider dig gennem processen.',
|
|
9316
|
+
contacts: [
|
|
9317
|
+
{ name: 'MediTech Service', initials: 'M', contactPerson: 'John Mortensen', phoneNumber: '+45 12 34 56 78' }
|
|
9318
|
+
]
|
|
9319
|
+
},
|
|
9320
|
+
{
|
|
9321
|
+
title: 'Brandslukningsudstyr',
|
|
9322
|
+
description: 'Brandslukkere placeret på hver etage. Eftersyn udføres årligt. Brandalarm aktiveres automatisk ved røg.',
|
|
9323
|
+
attachments: [
|
|
9324
|
+
{ name: 'Brandplan.pdf', type: 'pdf' }
|
|
9325
|
+
]
|
|
9326
|
+
},
|
|
9327
|
+
{
|
|
9328
|
+
title: 'Alarmsystem',
|
|
9329
|
+
description: 'Adgangskontrol med kodesystem ved alle indgange. Kode ændres kvartalsvis. Ved indbrud kontakt straks politiet og ejendomsadministrationen.',
|
|
9330
|
+
contacts: [
|
|
9331
|
+
{ name: 'SecureHome A/S', initials: 'S', contactPerson: 'Henrik Johansen', phoneNumber: '+45 98 76 54 32' }
|
|
9332
|
+
]
|
|
9333
|
+
}
|
|
9334
|
+
];
|
|
9335
|
+
// Service Contracts folder data
|
|
9336
|
+
serviceContractsItems = [
|
|
9337
|
+
{
|
|
9338
|
+
title: 'Rengøringsservice',
|
|
9339
|
+
description: 'Ugentlig rengøring af fællesarealer inklusiv indgangshal, trapper og elevatorer. Hovedrengøring kvartalsvis. Service leveres mandag-fredag, 6:00-9:00.',
|
|
9340
|
+
contacts: [
|
|
9341
|
+
{ name: 'CleanCo Denmark', initials: 'C', contactPerson: 'Anne Kristensen', phoneNumber: '+45 89 01 23 45' }
|
|
9342
|
+
]
|
|
9343
|
+
},
|
|
9344
|
+
{
|
|
9345
|
+
title: 'Rengøringskontrakt',
|
|
9346
|
+
attachments: [
|
|
9347
|
+
{ name: 'Rengøringskontrakt_2024.pdf', type: 'pdf' },
|
|
9348
|
+
{ name: 'Rengøringsplan.pdf', type: 'pdf' }
|
|
9349
|
+
]
|
|
9350
|
+
},
|
|
9351
|
+
{
|
|
9352
|
+
title: 'Udendørs arealer',
|
|
9353
|
+
description: 'Fælles grønne områder med bede, siddepladser og terrasse. Beboere må frit benytte området. Respektér planterne og hold området pænt.',
|
|
9354
|
+
images: [
|
|
9355
|
+
'/Assets/Dummy-photos/park.jpg',
|
|
9356
|
+
'/Assets/Dummy-photos/yard.jpg'
|
|
9357
|
+
]
|
|
9358
|
+
},
|
|
9359
|
+
{
|
|
9360
|
+
title: 'Havevedligeholdelse',
|
|
9361
|
+
description: 'Professionel havepleje inklusiv plæneklipning, hækklipning og blomsterbedvedligeholdelse. Vintersnefjerning inkluderet.',
|
|
9362
|
+
contacts: [
|
|
9363
|
+
{ name: 'Green Gardens ApS', initials: 'G', contactPerson: 'Michael Olsen', phoneNumber: '+45 90 12 34 56' }
|
|
9364
|
+
]
|
|
9365
|
+
},
|
|
9366
|
+
{
|
|
9367
|
+
title: 'Haveserviceaftale',
|
|
9368
|
+
attachments: [
|
|
9369
|
+
{ name: 'Haveserviceaftale.pdf', type: 'pdf' }
|
|
9370
|
+
]
|
|
9371
|
+
},
|
|
9372
|
+
{
|
|
9373
|
+
title: 'Vinduespolering',
|
|
9374
|
+
description: 'Professionel vinduespoleringsservice for alle udvendige vinduer to gange årligt - forår og efterår.',
|
|
9375
|
+
contacts: [
|
|
9376
|
+
{ name: 'Crystal Clear Windows', initials: 'C', contactPerson: 'Lene Schmidt', phoneNumber: '+45 01 23 45 67' }
|
|
9377
|
+
]
|
|
9378
|
+
},
|
|
9379
|
+
{
|
|
9380
|
+
title: 'Sikkerhedsservice',
|
|
9381
|
+
description: '24/7 overvågningsservice med alarmrespons. Direkte forbindelse til politi og brandvæsen.',
|
|
9382
|
+
contacts: [
|
|
9383
|
+
{ name: 'SecureHome A/S', initials: 'S', contactPerson: 'Henrik Johansen', phoneNumber: '+45 12 34 56 78' }
|
|
9384
|
+
]
|
|
9385
|
+
},
|
|
9386
|
+
{
|
|
9387
|
+
title: 'Sikkerhedskontrakt og procedurer',
|
|
9388
|
+
attachments: [
|
|
9389
|
+
{ name: 'Sikkerhedskontrakt.pdf', type: 'pdf' },
|
|
9390
|
+
{ name: 'Nødprocedurer.pdf', type: 'pdf' }
|
|
9391
|
+
]
|
|
9392
|
+
}
|
|
9393
|
+
];
|
|
9394
|
+
// Equipment folder data
|
|
9395
|
+
equipmentItems = [
|
|
9396
|
+
{
|
|
9397
|
+
title: 'Balkon udsigt',
|
|
9398
|
+
description: 'Eksempel på udsigt fra øverste etagers balkoner. Flere lejligheder har privat altan med fantastisk udsyn.',
|
|
9399
|
+
images: [
|
|
9400
|
+
'/Assets/Dummy-photos/balcony-view.jpg'
|
|
9401
|
+
]
|
|
9402
|
+
},
|
|
9403
|
+
{
|
|
9404
|
+
title: 'Vaskerum',
|
|
9405
|
+
description: 'Fælles vaskerum med 4 vaskemaskiner og 4 tørretumblere. Bookingsystem tilgængeligt via beboerportal. Maskiner accepterer betalingskort. Åbningstider: 7:00-22:00.',
|
|
9406
|
+
contacts: [
|
|
9407
|
+
{ name: 'WashTech Service', initials: 'W', contactPerson: 'Kirsten Berg', phoneNumber: '+45 34 56 78 90' }
|
|
9408
|
+
]
|
|
9409
|
+
},
|
|
9410
|
+
{
|
|
9411
|
+
title: 'Vaskeri instruktioner',
|
|
9412
|
+
attachments: [
|
|
9413
|
+
{ name: 'Vaskeinstruktioner.pdf', type: 'pdf' },
|
|
9414
|
+
{ name: 'Bookingguide.pdf', type: 'pdf' }
|
|
9415
|
+
]
|
|
9416
|
+
},
|
|
9417
|
+
{
|
|
9418
|
+
title: 'Vedligeholdelse og reparationer',
|
|
9419
|
+
description: 'Ved behov for reparationer eller vedligeholdelse i din lejlighed, kontakt vores hausmeister. Akutte problemer håndteres samme dag.',
|
|
9420
|
+
images: [
|
|
9421
|
+
'/Assets/Dummy-photos/handyman.jpg'
|
|
9422
|
+
],
|
|
9423
|
+
contacts: [
|
|
9424
|
+
{ name: 'Hausmeister Service', initials: 'H', contactPerson: 'Erik Sørensen', phoneNumber: '+45 56 78 90 12' }
|
|
9425
|
+
]
|
|
9426
|
+
},
|
|
9427
|
+
{
|
|
9428
|
+
title: 'Værktøjsudlån',
|
|
9429
|
+
description: 'Basis håndværktøj tilgængeligt til beboerbrug. Kvittér for værktøj ved receptionen. Returnér inden for 48 timer.',
|
|
9430
|
+
attachments: [
|
|
9431
|
+
{ name: 'Værktøjsliste.pdf', type: 'pdf' },
|
|
9432
|
+
{ name: 'Udlånspolitik.pdf', type: 'pdf' }
|
|
9433
|
+
]
|
|
9434
|
+
}
|
|
9435
|
+
];
|
|
9436
|
+
constructor(userService) {
|
|
9437
|
+
this.userService = userService;
|
|
9438
|
+
}
|
|
9439
|
+
handleRefresh(event) {
|
|
9440
|
+
console.log('Pull-to-refresh triggered');
|
|
9441
|
+
setTimeout(() => {
|
|
9442
|
+
console.log('Refresh complete');
|
|
9443
|
+
event.target.complete();
|
|
9444
|
+
}, 1000);
|
|
9445
|
+
}
|
|
9446
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileHandbookPageComponent, deps: [{ token: UserService }], target: i0.ɵɵFactoryTarget.Component });
|
|
9447
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: MobileHandbookPageComponent, isStandalone: true, selector: "app-mobile-handbook-page", ngImport: i0, template: `
|
|
9448
|
+
<ds-mobile-page-main
|
|
9449
|
+
title="Håndbog"
|
|
9450
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
9451
|
+
[avatarType]="userService.avatarType()"
|
|
9452
|
+
(refresh)="handleRefresh($event)">
|
|
9453
|
+
|
|
9454
|
+
<ds-mobile-content>
|
|
9455
|
+
<ds-mobile-content-section>
|
|
9456
|
+
<div class="folders-grid">
|
|
9457
|
+
<ds-mobile-handbook-folder
|
|
9458
|
+
[variant]="'pink'"
|
|
9459
|
+
[iconName]="'remixLightbulbLine'"
|
|
9460
|
+
[itemCount]="8"
|
|
9461
|
+
[label]="'Forsyninger'"
|
|
9462
|
+
[items]="utilitiesItems">
|
|
9463
|
+
</ds-mobile-handbook-folder>
|
|
9464
|
+
|
|
9465
|
+
<ds-mobile-handbook-folder
|
|
9466
|
+
[variant]="'success'"
|
|
9467
|
+
[iconName]="'remixKey2Line'"
|
|
9468
|
+
[itemCount]="4"
|
|
9469
|
+
[label]="'Sikkerhedsudstyr'"
|
|
9470
|
+
[items]="sikkerhedsudstyrItems">
|
|
9471
|
+
</ds-mobile-handbook-folder>
|
|
9472
|
+
|
|
9473
|
+
<ds-mobile-handbook-folder
|
|
9474
|
+
[variant]="'blue'"
|
|
9475
|
+
[iconName]="'remixFileList3Line'"
|
|
9476
|
+
[itemCount]="8"
|
|
9477
|
+
[label]="'Servicekontrakter'"
|
|
9478
|
+
[items]="serviceContractsItems">
|
|
9479
|
+
</ds-mobile-handbook-folder>
|
|
9480
|
+
|
|
9481
|
+
<ds-mobile-handbook-folder
|
|
9482
|
+
[variant]="'warning'"
|
|
9483
|
+
[iconName]="'remixToolsLine'"
|
|
9484
|
+
[itemCount]="5"
|
|
9485
|
+
[label]="'Udstyr'"
|
|
9486
|
+
[items]="equipmentItems">
|
|
9487
|
+
</ds-mobile-handbook-folder>
|
|
9488
|
+
</div>
|
|
9489
|
+
</ds-mobile-content-section>
|
|
9490
|
+
</ds-mobile-content>
|
|
9491
|
+
</ds-mobile-page-main>
|
|
9492
|
+
`, 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"] }] });
|
|
9493
|
+
}
|
|
9494
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileHandbookPageComponent, decorators: [{
|
|
9495
|
+
type: Component,
|
|
9496
|
+
args: [{ selector: 'app-mobile-handbook-page', standalone: true, imports: [
|
|
9497
|
+
DsMobilePageMainComponent,
|
|
9498
|
+
DsMobileContentComponent,
|
|
9499
|
+
DsMobileContentSectionComponent,
|
|
9500
|
+
SectionHeaderComponent,
|
|
9501
|
+
ContentRowComponent,
|
|
9502
|
+
DsMobileHandbookFolderComponent
|
|
9503
|
+
], template: `
|
|
9504
|
+
<ds-mobile-page-main
|
|
9505
|
+
title="Håndbog"
|
|
9506
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
9507
|
+
[avatarType]="userService.avatarType()"
|
|
9508
|
+
(refresh)="handleRefresh($event)">
|
|
9509
|
+
|
|
9510
|
+
<ds-mobile-content>
|
|
9511
|
+
<ds-mobile-content-section>
|
|
9512
|
+
<div class="folders-grid">
|
|
9513
|
+
<ds-mobile-handbook-folder
|
|
9514
|
+
[variant]="'pink'"
|
|
9515
|
+
[iconName]="'remixLightbulbLine'"
|
|
9516
|
+
[itemCount]="8"
|
|
9517
|
+
[label]="'Forsyninger'"
|
|
9518
|
+
[items]="utilitiesItems">
|
|
9519
|
+
</ds-mobile-handbook-folder>
|
|
9520
|
+
|
|
9521
|
+
<ds-mobile-handbook-folder
|
|
9522
|
+
[variant]="'success'"
|
|
9523
|
+
[iconName]="'remixKey2Line'"
|
|
9524
|
+
[itemCount]="4"
|
|
9525
|
+
[label]="'Sikkerhedsudstyr'"
|
|
9526
|
+
[items]="sikkerhedsudstyrItems">
|
|
9527
|
+
</ds-mobile-handbook-folder>
|
|
9528
|
+
|
|
9529
|
+
<ds-mobile-handbook-folder
|
|
9530
|
+
[variant]="'blue'"
|
|
9531
|
+
[iconName]="'remixFileList3Line'"
|
|
9532
|
+
[itemCount]="8"
|
|
9533
|
+
[label]="'Servicekontrakter'"
|
|
9534
|
+
[items]="serviceContractsItems">
|
|
9535
|
+
</ds-mobile-handbook-folder>
|
|
9536
|
+
|
|
9537
|
+
<ds-mobile-handbook-folder
|
|
9538
|
+
[variant]="'warning'"
|
|
9539
|
+
[iconName]="'remixToolsLine'"
|
|
9540
|
+
[itemCount]="5"
|
|
9541
|
+
[label]="'Udstyr'"
|
|
9542
|
+
[items]="equipmentItems">
|
|
9543
|
+
</ds-mobile-handbook-folder>
|
|
9544
|
+
</div>
|
|
9545
|
+
</ds-mobile-content-section>
|
|
9546
|
+
</ds-mobile-content>
|
|
9547
|
+
</ds-mobile-page-main>
|
|
9548
|
+
`, 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"] }]
|
|
9549
|
+
}], ctorParameters: () => [{ type: UserService }] });
|
|
9550
|
+
|
|
9551
|
+
class MobileHomePageComponent {
|
|
9552
|
+
navCtrl;
|
|
9553
|
+
userService;
|
|
9554
|
+
constructor(navCtrl, userService) {
|
|
9555
|
+
this.navCtrl = navCtrl;
|
|
9556
|
+
this.userService = userService;
|
|
9557
|
+
console.log('MobileHomePageComponent constructor');
|
|
9558
|
+
}
|
|
9559
|
+
handleRefresh(event) {
|
|
9560
|
+
console.log('Pull-to-refresh triggered');
|
|
9561
|
+
setTimeout(() => {
|
|
9562
|
+
console.log('Refresh complete');
|
|
9563
|
+
event.target.complete();
|
|
9564
|
+
}, 1000);
|
|
9565
|
+
}
|
|
9566
|
+
navigateToDetail() {
|
|
9567
|
+
// Navigation removed - home/detail page was deleted
|
|
9568
|
+
console.log('Navigate to detail (page removed)');
|
|
9569
|
+
}
|
|
9570
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileHomePageComponent, deps: [{ token: i1.NavController }, { token: UserService }], target: i0.ɵɵFactoryTarget.Component });
|
|
9571
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: MobileHomePageComponent, isStandalone: true, selector: "app-home-page", ngImport: i0, template: `
|
|
9572
|
+
<ds-mobile-page-main
|
|
9573
|
+
title="Hjem"
|
|
9574
|
+
headerTitle="Velkommen, Lars"
|
|
9575
|
+
headerSubtitle="Din lejebolig på et øjeblik."
|
|
9576
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
9577
|
+
[avatarType]="userService.avatarType()"
|
|
9578
|
+
(refresh)="handleRefresh($event)">
|
|
9579
|
+
|
|
9580
|
+
<!-- Property info tiles in header -->
|
|
9581
|
+
<ds-mobile-header-content header-content>
|
|
9582
|
+
<ds-mobile-header-content-tile>
|
|
9583
|
+
<tile-icon>
|
|
9584
|
+
<ds-icon name="remixHome4Line" size="20px" color="#DFE4FF" />
|
|
9585
|
+
</tile-icon>
|
|
9586
|
+
<tile-content>
|
|
9587
|
+
<tile-label>Areal</tile-label>
|
|
9588
|
+
<tile-value>120 m²</tile-value>
|
|
9589
|
+
</tile-content>
|
|
9590
|
+
</ds-mobile-header-content-tile>
|
|
9591
|
+
|
|
9592
|
+
<ds-mobile-header-content-tile>
|
|
9593
|
+
<tile-icon>
|
|
9594
|
+
<ds-icon name="remixCollageLine" size="20px" color="#DFE4FF" />
|
|
9595
|
+
</tile-icon>
|
|
9596
|
+
<tile-content>
|
|
9597
|
+
<tile-label>Værelser</tile-label>
|
|
9598
|
+
<tile-value>3 værelser</tile-value>
|
|
9599
|
+
</tile-content>
|
|
9600
|
+
</ds-mobile-header-content-tile>
|
|
9601
|
+
</ds-mobile-header-content>
|
|
9602
|
+
|
|
9603
|
+
<!-- Main page content -->
|
|
9604
|
+
<ds-mobile-content>
|
|
9605
|
+
<ds-mobile-content-section>
|
|
9606
|
+
<section-header width="third"></section-header>
|
|
9607
|
+
<content-row>
|
|
9608
|
+
<div class="grey-box"></div>
|
|
9609
|
+
<div class="grey-box"></div>
|
|
9610
|
+
</content-row>
|
|
9611
|
+
<content-row>
|
|
9612
|
+
<div class="grey-box"></div>
|
|
9613
|
+
</content-row>
|
|
9614
|
+
</ds-mobile-content-section>
|
|
9615
|
+
|
|
9616
|
+
<!-- Purple box - clickable with brand background -->
|
|
9617
|
+
<content-row>
|
|
9618
|
+
<div class="grey-box clickable" (click)="navigateToDetail()"></div>
|
|
9619
|
+
</content-row>
|
|
9620
|
+
|
|
9621
|
+
<ds-mobile-content-section>
|
|
9622
|
+
<section-header width="half"></section-header>
|
|
9623
|
+
<content-row>
|
|
9624
|
+
<div class="grey-box"></div>
|
|
9625
|
+
<div class="grey-box"></div>
|
|
9626
|
+
<div class="grey-box"></div>
|
|
9627
|
+
</content-row>
|
|
9628
|
+
<content-row>
|
|
9629
|
+
<div class="grey-box"></div>
|
|
9630
|
+
<div class="grey-box"></div>
|
|
9631
|
+
</content-row>
|
|
9632
|
+
</ds-mobile-content-section>
|
|
9633
|
+
|
|
9634
|
+
<ds-mobile-content-section>
|
|
9635
|
+
<section-header width="third"></section-header>
|
|
9636
|
+
<content-row>
|
|
9637
|
+
<div class="grey-box"></div>
|
|
9638
|
+
</content-row>
|
|
9639
|
+
</ds-mobile-content-section>
|
|
9640
|
+
|
|
9641
|
+
<ds-mobile-content-section>
|
|
9642
|
+
<section-header width="half"></section-header>
|
|
9643
|
+
<content-row>
|
|
9644
|
+
<div class="grey-box"></div>
|
|
9645
|
+
<div class="grey-box"></div>
|
|
9646
|
+
</content-row>
|
|
9647
|
+
<content-row>
|
|
9648
|
+
<div class="grey-box"></div>
|
|
9649
|
+
<div class="grey-box"></div>
|
|
9650
|
+
<div class="grey-box"></div>
|
|
9651
|
+
</content-row>
|
|
9652
|
+
</ds-mobile-content-section>
|
|
9653
|
+
|
|
9654
|
+
<ds-mobile-content-section>
|
|
9655
|
+
<section-header width="third"></section-header>
|
|
9656
|
+
<content-row>
|
|
9657
|
+
<div class="grey-box"></div>
|
|
9658
|
+
<div class="grey-box"></div>
|
|
9659
|
+
</content-row>
|
|
9660
|
+
</ds-mobile-content-section>
|
|
9661
|
+
|
|
9662
|
+
<ds-mobile-content-section>
|
|
9663
|
+
<section-header width="half"></section-header>
|
|
9664
|
+
<content-row>
|
|
9665
|
+
<div class="grey-box"></div>
|
|
9666
|
+
</content-row>
|
|
9667
|
+
<content-row>
|
|
9668
|
+
<div class="grey-box"></div>
|
|
9669
|
+
<div class="grey-box"></div>
|
|
9670
|
+
</content-row>
|
|
9671
|
+
</ds-mobile-content-section>
|
|
9672
|
+
|
|
9673
|
+
<ds-mobile-content-section>
|
|
9674
|
+
<section-header width="third"></section-header>
|
|
9675
|
+
<content-row>
|
|
9676
|
+
<div class="grey-box"></div>
|
|
9677
|
+
<div class="grey-box"></div>
|
|
9678
|
+
<div class="grey-box"></div>
|
|
9679
|
+
</content-row>
|
|
9680
|
+
</ds-mobile-content-section>
|
|
9681
|
+
</ds-mobile-content>
|
|
9682
|
+
</ds-mobile-page-main>
|
|
9683
|
+
`, 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" }] });
|
|
9684
|
+
}
|
|
9685
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileHomePageComponent, decorators: [{
|
|
9686
|
+
type: Component,
|
|
9687
|
+
args: [{ selector: 'app-home-page', standalone: true, imports: [
|
|
9688
|
+
DsIconComponent,
|
|
9689
|
+
DsMobilePageMainComponent,
|
|
9690
|
+
DsMobileHeaderContentComponent,
|
|
9691
|
+
DsMobileHeaderContentTileComponent,
|
|
9692
|
+
TileIconComponent,
|
|
9693
|
+
TileContentComponent,
|
|
9694
|
+
TileLabelComponent,
|
|
9695
|
+
TileValueComponent,
|
|
9696
|
+
DsMobileContentComponent,
|
|
9697
|
+
DsMobileContentSectionComponent,
|
|
9698
|
+
SectionHeaderComponent,
|
|
9699
|
+
ContentRowComponent
|
|
9700
|
+
], template: `
|
|
9701
|
+
<ds-mobile-page-main
|
|
9702
|
+
title="Hjem"
|
|
9703
|
+
headerTitle="Velkommen, Lars"
|
|
9704
|
+
headerSubtitle="Din lejebolig på et øjeblik."
|
|
9705
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
9706
|
+
[avatarType]="userService.avatarType()"
|
|
9707
|
+
(refresh)="handleRefresh($event)">
|
|
9708
|
+
|
|
9709
|
+
<!-- Property info tiles in header -->
|
|
9710
|
+
<ds-mobile-header-content header-content>
|
|
9711
|
+
<ds-mobile-header-content-tile>
|
|
9712
|
+
<tile-icon>
|
|
9713
|
+
<ds-icon name="remixHome4Line" size="20px" color="#DFE4FF" />
|
|
9714
|
+
</tile-icon>
|
|
9715
|
+
<tile-content>
|
|
9716
|
+
<tile-label>Areal</tile-label>
|
|
9717
|
+
<tile-value>120 m²</tile-value>
|
|
9718
|
+
</tile-content>
|
|
9719
|
+
</ds-mobile-header-content-tile>
|
|
9720
|
+
|
|
9721
|
+
<ds-mobile-header-content-tile>
|
|
9722
|
+
<tile-icon>
|
|
9723
|
+
<ds-icon name="remixCollageLine" size="20px" color="#DFE4FF" />
|
|
9724
|
+
</tile-icon>
|
|
9725
|
+
<tile-content>
|
|
9726
|
+
<tile-label>Værelser</tile-label>
|
|
9727
|
+
<tile-value>3 værelser</tile-value>
|
|
9728
|
+
</tile-content>
|
|
9729
|
+
</ds-mobile-header-content-tile>
|
|
9730
|
+
</ds-mobile-header-content>
|
|
9731
|
+
|
|
9732
|
+
<!-- Main page content -->
|
|
9733
|
+
<ds-mobile-content>
|
|
9734
|
+
<ds-mobile-content-section>
|
|
9735
|
+
<section-header width="third"></section-header>
|
|
9736
|
+
<content-row>
|
|
9737
|
+
<div class="grey-box"></div>
|
|
9738
|
+
<div class="grey-box"></div>
|
|
9739
|
+
</content-row>
|
|
9740
|
+
<content-row>
|
|
9741
|
+
<div class="grey-box"></div>
|
|
9742
|
+
</content-row>
|
|
9743
|
+
</ds-mobile-content-section>
|
|
9744
|
+
|
|
9745
|
+
<!-- Purple box - clickable with brand background -->
|
|
9746
|
+
<content-row>
|
|
9747
|
+
<div class="grey-box clickable" (click)="navigateToDetail()"></div>
|
|
9748
|
+
</content-row>
|
|
9749
|
+
|
|
9750
|
+
<ds-mobile-content-section>
|
|
9751
|
+
<section-header width="half"></section-header>
|
|
9752
|
+
<content-row>
|
|
9753
|
+
<div class="grey-box"></div>
|
|
9754
|
+
<div class="grey-box"></div>
|
|
9755
|
+
<div class="grey-box"></div>
|
|
9756
|
+
</content-row>
|
|
9757
|
+
<content-row>
|
|
9758
|
+
<div class="grey-box"></div>
|
|
9759
|
+
<div class="grey-box"></div>
|
|
9760
|
+
</content-row>
|
|
9761
|
+
</ds-mobile-content-section>
|
|
9762
|
+
|
|
9763
|
+
<ds-mobile-content-section>
|
|
9764
|
+
<section-header width="third"></section-header>
|
|
9765
|
+
<content-row>
|
|
9766
|
+
<div class="grey-box"></div>
|
|
9767
|
+
</content-row>
|
|
9768
|
+
</ds-mobile-content-section>
|
|
9769
|
+
|
|
9770
|
+
<ds-mobile-content-section>
|
|
9771
|
+
<section-header width="half"></section-header>
|
|
9772
|
+
<content-row>
|
|
9773
|
+
<div class="grey-box"></div>
|
|
9774
|
+
<div class="grey-box"></div>
|
|
9775
|
+
</content-row>
|
|
9776
|
+
<content-row>
|
|
9777
|
+
<div class="grey-box"></div>
|
|
9778
|
+
<div class="grey-box"></div>
|
|
9779
|
+
<div class="grey-box"></div>
|
|
9780
|
+
</content-row>
|
|
9781
|
+
</ds-mobile-content-section>
|
|
9782
|
+
|
|
9783
|
+
<ds-mobile-content-section>
|
|
9784
|
+
<section-header width="third"></section-header>
|
|
9785
|
+
<content-row>
|
|
9786
|
+
<div class="grey-box"></div>
|
|
9787
|
+
<div class="grey-box"></div>
|
|
9788
|
+
</content-row>
|
|
9789
|
+
</ds-mobile-content-section>
|
|
9790
|
+
|
|
9791
|
+
<ds-mobile-content-section>
|
|
9792
|
+
<section-header width="half"></section-header>
|
|
9793
|
+
<content-row>
|
|
9794
|
+
<div class="grey-box"></div>
|
|
9795
|
+
</content-row>
|
|
9796
|
+
<content-row>
|
|
9797
|
+
<div class="grey-box"></div>
|
|
9798
|
+
<div class="grey-box"></div>
|
|
9799
|
+
</content-row>
|
|
9800
|
+
</ds-mobile-content-section>
|
|
9801
|
+
|
|
9802
|
+
<ds-mobile-content-section>
|
|
9803
|
+
<section-header width="third"></section-header>
|
|
9804
|
+
<content-row>
|
|
9805
|
+
<div class="grey-box"></div>
|
|
9806
|
+
<div class="grey-box"></div>
|
|
9807
|
+
<div class="grey-box"></div>
|
|
9808
|
+
</content-row>
|
|
9809
|
+
</ds-mobile-content-section>
|
|
9810
|
+
</ds-mobile-content>
|
|
9811
|
+
</ds-mobile-page-main>
|
|
9812
|
+
`, 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"] }]
|
|
9813
|
+
}], ctorParameters: () => [{ type: i1.NavController }, { type: UserService }] });
|
|
9814
|
+
|
|
9815
|
+
/**
|
|
9816
|
+
* Custom page transition - iOS-style push/pop
|
|
9817
|
+
*
|
|
9818
|
+
* FORWARD (navigating TO detail):
|
|
9819
|
+
* - Entering page (detail): slides in from RIGHT, z-index 10 (on top)
|
|
9820
|
+
* - Leaving page (list): slides LEFT slightly, z-index 9 (underneath)
|
|
9821
|
+
*
|
|
9822
|
+
* REVERSE (swipe back FROM detail):
|
|
9823
|
+
* - Entering page (list): slides in from LEFT, z-index 9 (underneath)
|
|
9824
|
+
* - Leaving page (detail): slides out to RIGHT, z-index 10 (on top)
|
|
9825
|
+
*/
|
|
9826
|
+
const customPageTransition = (_, opts) => {
|
|
9827
|
+
const DURATION = 400;
|
|
9828
|
+
const isBackDirection = opts.direction === 'back';
|
|
9829
|
+
const rootTransition = createAnimation()
|
|
9830
|
+
.duration(opts.duration || DURATION)
|
|
9831
|
+
.easing('cubic-bezier(0.32,0.72,0,1)');
|
|
9832
|
+
// Entering page animation
|
|
9833
|
+
const enteringPage = createAnimation()
|
|
9834
|
+
.addElement(opts.enteringEl)
|
|
9835
|
+
.beforeRemoveClass('ion-page-invisible')
|
|
9836
|
+
.beforeStyles({
|
|
9837
|
+
'z-index': isBackDirection ? '9' : '10',
|
|
9838
|
+
'opacity': '1'
|
|
9839
|
+
})
|
|
9840
|
+
.fromTo('transform', isBackDirection ? 'translateX(-20%)' : 'translateX(100%)', 'translateX(0)');
|
|
9841
|
+
// Leaving page animation
|
|
9842
|
+
const leavingPage = createAnimation()
|
|
9843
|
+
.addElement(opts.leavingEl)
|
|
9844
|
+
.beforeStyles({
|
|
9845
|
+
'z-index': isBackDirection ? '10' : '9'
|
|
9846
|
+
})
|
|
9847
|
+
.fromTo('transform', 'translateX(0)', isBackDirection ? 'translateX(100%)' : 'translateX(-20%)');
|
|
9848
|
+
rootTransition.addAnimation([enteringPage, leavingPage]);
|
|
9849
|
+
return rootTransition;
|
|
9850
|
+
};
|
|
9851
|
+
/**
|
|
9852
|
+
* Custom back transition - iOS style where page slides out to reveal page underneath
|
|
9853
|
+
* The entering page (inquiries) slides in from the LEFT underneath
|
|
9854
|
+
* The leaving page (detail) slides out to the RIGHT on top
|
|
9855
|
+
*/
|
|
9856
|
+
const customBackTransition = (_, opts) => {
|
|
9857
|
+
const DURATION = 400;
|
|
9858
|
+
const rootTransition = createAnimation()
|
|
9859
|
+
.duration(opts.duration || DURATION)
|
|
9860
|
+
.easing('cubic-bezier(0.32,0.72,0,1)');
|
|
9861
|
+
// Entering page: underneath, sliding in from LEFT (-20% to 0)
|
|
9862
|
+
const enteringPage = createAnimation()
|
|
9863
|
+
.addElement(opts.enteringEl)
|
|
9864
|
+
.beforeRemoveClass('ion-page-invisible')
|
|
9865
|
+
.beforeStyles({
|
|
9866
|
+
'z-index': '9',
|
|
9867
|
+
'opacity': '1'
|
|
9868
|
+
})
|
|
9869
|
+
.fromTo('transform', 'translateX(-20%)', 'translateX(0)');
|
|
9870
|
+
// Leaving page: on top, sliding out to the RIGHT (0 to 100%)
|
|
9871
|
+
const leavingPage = createAnimation()
|
|
9872
|
+
.addElement(opts.leavingEl)
|
|
9873
|
+
.beforeStyles({
|
|
9874
|
+
'z-index': '10',
|
|
9875
|
+
})
|
|
9876
|
+
.fromTo('transform', 'translateX(0)', 'translateX(100%)');
|
|
9877
|
+
rootTransition.addAnimation([enteringPage, leavingPage]);
|
|
9878
|
+
return rootTransition;
|
|
9879
|
+
};
|
|
9880
|
+
|
|
9881
|
+
/**
|
|
9882
|
+
* DsMobileTabBarComponent
|
|
9883
|
+
*
|
|
9884
|
+
* Pill-style tab bar for filtering/switching views
|
|
9885
|
+
* Used in the purple header section of pages
|
|
9886
|
+
*
|
|
9887
|
+
* @example
|
|
9888
|
+
* ```html
|
|
9889
|
+
* <ds-mobile-tab-bar
|
|
9890
|
+
* [tabs]="[
|
|
9891
|
+
* { id: 'all', label: 'All' },
|
|
9892
|
+
* { id: 'open', label: 'Open' },
|
|
9893
|
+
* { id: 'closed', label: 'Closed' }
|
|
9894
|
+
* ]"
|
|
9895
|
+
* [activeTab]="'all'"
|
|
9896
|
+
* (tabChange)="handleTabChange($event)">
|
|
9897
|
+
* </ds-mobile-tab-bar>
|
|
9898
|
+
* ```
|
|
9899
|
+
*/
|
|
9900
|
+
class DsMobileTabBarComponent {
|
|
9901
|
+
/**
|
|
9902
|
+
* Array of tab items to display
|
|
9903
|
+
*/
|
|
9904
|
+
tabs = input.required(...(ngDevMode ? [{ debugName: "tabs" }] : []));
|
|
9905
|
+
/**
|
|
9906
|
+
* Currently active tab ID
|
|
9907
|
+
*/
|
|
9908
|
+
activeTab = input.required(...(ngDevMode ? [{ debugName: "activeTab" }] : []));
|
|
9909
|
+
/**
|
|
9910
|
+
* Emitted when a tab is clicked
|
|
9911
|
+
*/
|
|
9912
|
+
tabChange = output();
|
|
9913
|
+
handleTabClick(tabId) {
|
|
9914
|
+
this.tabChange.emit(tabId);
|
|
9915
|
+
}
|
|
9916
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobileTabBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9917
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: DsMobileTabBarComponent, isStandalone: true, selector: "ds-mobile-tab-bar", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: true, transformFunction: null }, activeTab: { classPropertyName: "activeTab", publicName: "activeTab", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { tabChange: "tabChange" }, ngImport: i0, template: `
|
|
9918
|
+
<div class="filter-tabs">
|
|
9919
|
+
@for (tab of tabs(); track tab.id) {
|
|
9920
|
+
<button
|
|
9921
|
+
class="filter-tab"
|
|
9922
|
+
[class.active]="activeTab() === tab.id"
|
|
9923
|
+
(click)="handleTabClick(tab.id)"
|
|
9924
|
+
[attr.aria-label]="tab.label"
|
|
9925
|
+
[attr.aria-selected]="activeTab() === tab.id">
|
|
9926
|
+
{{ tab.label }}
|
|
9927
|
+
@if (tab.badge && tab.badge > 0) {
|
|
9928
|
+
<span class="tab-badge">{{ tab.badge }}</span>
|
|
9929
|
+
}
|
|
9930
|
+
</button>
|
|
9931
|
+
}
|
|
9932
|
+
</div>
|
|
9933
|
+
`, isInline: true, styles: [".filter-tabs{display:flex;align-items:center;gap:8px;flex-wrap:wrap;height:40px}.filter-tab{min-width:48px;justify-content:center;padding:0 12px;height:32px;border-radius:20px;background:transparent;border:none;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;color:#fff9;cursor:pointer;transition:all .2s ease;display:flex;align-items:center;gap:6px;white-space:nowrap}.filter-tab.active{background:var(--color-background-brand, #5d5fef);color:#fff}.filter-tab:hover:not(.active){background:#ffffff1a}.tab-badge{min-width:24px;height:16px;padding:0 6px;border-radius:10px;background:#fff3;color:#fff;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:600;display:flex;align-items:center;justify-content:center;line-height:1}.filter-tab.active .tab-badge{background:#ffffff4d;color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
9934
|
+
}
|
|
9935
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobileTabBarComponent, decorators: [{
|
|
9936
|
+
type: Component,
|
|
9937
|
+
args: [{ selector: 'ds-mobile-tab-bar', standalone: true, imports: [CommonModule], template: `
|
|
9938
|
+
<div class="filter-tabs">
|
|
9939
|
+
@for (tab of tabs(); track tab.id) {
|
|
9940
|
+
<button
|
|
9941
|
+
class="filter-tab"
|
|
9942
|
+
[class.active]="activeTab() === tab.id"
|
|
9943
|
+
(click)="handleTabClick(tab.id)"
|
|
9944
|
+
[attr.aria-label]="tab.label"
|
|
9945
|
+
[attr.aria-selected]="activeTab() === tab.id">
|
|
9946
|
+
{{ tab.label }}
|
|
9947
|
+
@if (tab.badge && tab.badge > 0) {
|
|
9948
|
+
<span class="tab-badge">{{ tab.badge }}</span>
|
|
9949
|
+
}
|
|
9950
|
+
</button>
|
|
9951
|
+
}
|
|
9952
|
+
</div>
|
|
9953
|
+
`, styles: [".filter-tabs{display:flex;align-items:center;gap:8px;flex-wrap:wrap;height:40px}.filter-tab{min-width:48px;justify-content:center;padding:0 12px;height:32px;border-radius:20px;background:transparent;border:none;font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;color:#fff9;cursor:pointer;transition:all .2s ease;display:flex;align-items:center;gap:6px;white-space:nowrap}.filter-tab.active{background:var(--color-background-brand, #5d5fef);color:#fff}.filter-tab:hover:not(.active){background:#ffffff1a}.tab-badge{min-width:24px;height:16px;padding:0 6px;border-radius:10px;background:#fff3;color:#fff;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:600;display:flex;align-items:center;justify-content:center;line-height:1}.filter-tab.active .tab-badge{background:#ffffff4d;color:#fff}\n"] }]
|
|
9954
|
+
}], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: true }] }], activeTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTab", required: true }] }], tabChange: [{ type: i0.Output, args: ["tabChange"] }] } });
|
|
9955
|
+
|
|
9956
|
+
class MobileInquiriesPageComponent {
|
|
9957
|
+
userService;
|
|
9958
|
+
navCtrl;
|
|
9959
|
+
constructor(userService, navCtrl) {
|
|
9960
|
+
this.userService = userService;
|
|
9961
|
+
this.navCtrl = navCtrl;
|
|
9962
|
+
}
|
|
9963
|
+
filterStatus = signal('all', ...(ngDevMode ? [{ debugName: "filterStatus" }] : []));
|
|
9964
|
+
tabItems = [
|
|
9965
|
+
{ id: 'all', label: 'Alle' },
|
|
9966
|
+
{ id: 'open', label: 'Åben' },
|
|
9967
|
+
{ id: 'closed', label: 'Lukket' }
|
|
9968
|
+
];
|
|
9969
|
+
inquiries = signal([
|
|
9970
|
+
{
|
|
9971
|
+
id: '1',
|
|
9972
|
+
title: 'Tørretumbler virker ikke',
|
|
9973
|
+
description: 'I de sidste tre dage har jeg oplevet vedvarende problemer med tørretumbleren. Den starter, men stopper efter få minutter.',
|
|
9974
|
+
status: 'open',
|
|
9975
|
+
timestamp: '12 dage siden',
|
|
9976
|
+
category: 'appliance'
|
|
9977
|
+
},
|
|
9978
|
+
{
|
|
9979
|
+
id: '2',
|
|
9980
|
+
title: 'Problem med vandtryk',
|
|
9981
|
+
description: 'Lavt vandtryk i badeværelseshåndvasken. Det er blevet gradvist værre i løbet af den sidste uge.',
|
|
9982
|
+
status: 'open',
|
|
9983
|
+
timestamp: '5 dage siden',
|
|
9984
|
+
category: 'plumbing'
|
|
9985
|
+
},
|
|
9986
|
+
{
|
|
9987
|
+
id: '3',
|
|
9988
|
+
title: 'Varme virker ikke ordentligt',
|
|
9989
|
+
description: 'Varmesystemet holder ikke den indstillede temperatur. Lejligheden er meget koldere, end den burde være.',
|
|
9990
|
+
status: 'closed',
|
|
9991
|
+
timestamp: '2 måneder siden',
|
|
9992
|
+
category: 'heating'
|
|
9993
|
+
}
|
|
9994
|
+
], ...(ngDevMode ? [{ debugName: "inquiries" }] : []));
|
|
9995
|
+
// Computed signals that automatically update when dependencies change
|
|
9996
|
+
filteredInquiries = computed(() => {
|
|
9997
|
+
const all = this.inquiries();
|
|
9998
|
+
const status = this.filterStatus();
|
|
9999
|
+
if (status === 'all') {
|
|
10000
|
+
return all;
|
|
10001
|
+
}
|
|
10002
|
+
else if (status === 'open') {
|
|
10003
|
+
return all.filter(i => i.status === 'open');
|
|
10004
|
+
}
|
|
10005
|
+
else {
|
|
10006
|
+
return all.filter(i => i.status === 'closed');
|
|
10007
|
+
}
|
|
10008
|
+
}, ...(ngDevMode ? [{ debugName: "filteredInquiries" }] : []));
|
|
10009
|
+
openInquiries = computed(() => {
|
|
10010
|
+
return this.inquiries().filter(i => i.status === 'open');
|
|
10011
|
+
}, ...(ngDevMode ? [{ debugName: "openInquiries" }] : []));
|
|
10012
|
+
closedInquiries = computed(() => {
|
|
10013
|
+
return this.inquiries().filter(i => i.status === 'closed');
|
|
10014
|
+
}, ...(ngDevMode ? [{ debugName: "closedInquiries" }] : []));
|
|
10015
|
+
setFilter(status) {
|
|
10016
|
+
this.filterStatus.set(status);
|
|
10017
|
+
}
|
|
10018
|
+
getInquiryIcon(category) {
|
|
10019
|
+
return 'remixTodoLine';
|
|
10020
|
+
}
|
|
10021
|
+
openInquiryDetail(inquiryId) {
|
|
10022
|
+
console.log('Opening inquiry:', inquiryId);
|
|
10023
|
+
// Navigate to inquiry detail page with custom transition (absolute path outside tabs for animations)
|
|
10024
|
+
this.navCtrl.navigateForward([`/inquiry-detail/${inquiryId}`], {
|
|
10025
|
+
animation: customPageTransition
|
|
10026
|
+
});
|
|
10027
|
+
}
|
|
10028
|
+
showInquiryActions(inquiryId) {
|
|
10029
|
+
console.log('Showing actions for inquiry:', inquiryId);
|
|
10030
|
+
// Show bottom sheet with actions (edit, delete, etc.)
|
|
10031
|
+
}
|
|
10032
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileInquiriesPageComponent, deps: [{ token: UserService }, { token: i1.NavController }], target: i0.ɵɵFactoryTarget.Component });
|
|
10033
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: MobileInquiriesPageComponent, isStandalone: true, selector: "app-mobile-inquiries-page", host: { classAttribute: "ion-page" }, ngImport: i0, template: `
|
|
10034
|
+
<ds-mobile-page-main
|
|
10035
|
+
title="Henvendelser"
|
|
10036
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
10037
|
+
[avatarType]="userService.avatarType()">
|
|
10038
|
+
|
|
10039
|
+
<!-- Filter tabs in header -->
|
|
10040
|
+
<div header-content>
|
|
10041
|
+
<ds-mobile-tab-bar
|
|
10042
|
+
[tabs]="tabItems"
|
|
10043
|
+
[activeTab]="filterStatus()"
|
|
10044
|
+
(tabChange)="setFilter($any($event))">
|
|
10045
|
+
</ds-mobile-tab-bar>
|
|
10046
|
+
</div>
|
|
10047
|
+
|
|
10048
|
+
<ds-mobile-content>
|
|
10049
|
+
<div class="inquiries-container">
|
|
10050
|
+
@if (filteredInquiries().length > 0) {
|
|
10051
|
+
<div class="inquiry-list-wrapper">
|
|
10052
|
+
@for (inquiry of filteredInquiries(); track inquiry.id; let idx = $index) {
|
|
10053
|
+
<ds-mobile-interactive-list-item-inquiry
|
|
10054
|
+
[title]="inquiry.title"
|
|
10055
|
+
[description]="inquiry.description"
|
|
10056
|
+
[status]="inquiry.status"
|
|
10057
|
+
[timestamp]="inquiry.timestamp"
|
|
10058
|
+
[iconName]="getInquiryIcon(inquiry.category)"
|
|
10059
|
+
[clickable]="true"
|
|
10060
|
+
[showChevron]="false"
|
|
10061
|
+
(inquiryClick)="openInquiryDetail(inquiry.id)"
|
|
10062
|
+
(longPress)="showInquiryActions(inquiry.id)">
|
|
10063
|
+
</ds-mobile-interactive-list-item-inquiry>
|
|
10064
|
+
|
|
10065
|
+
}
|
|
10066
|
+
</div>
|
|
10067
|
+
} @else {
|
|
10068
|
+
<!-- Empty state -->
|
|
10069
|
+
<div class="empty-state">
|
|
10070
|
+
<ds-icon name="remixInboxLine" size="48px" color="tertiary" />
|
|
10071
|
+
<h3 class="empty-state-title">Ingen henvendelser endnu</h3>
|
|
10072
|
+
<p class="empty-state-description">
|
|
10073
|
+
@if (filterStatus() === 'open') {
|
|
10074
|
+
Du har ingen åbne henvendelser
|
|
10075
|
+
} @else if (filterStatus() === 'closed') {
|
|
10076
|
+
Du har ingen lukkede henvendelser
|
|
10077
|
+
} @else {
|
|
10078
|
+
Du har ikke oprettet nogen henvendelser endnu
|
|
10079
|
+
}
|
|
10080
|
+
</p>
|
|
10081
|
+
</div>
|
|
10082
|
+
}
|
|
10083
|
+
</div>
|
|
10084
|
+
</ds-mobile-content>
|
|
10085
|
+
</ds-mobile-page-main>
|
|
10086
|
+
`, 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: DsMobileTabBarComponent, selector: "ds-mobile-tab-bar", inputs: ["tabs", "activeTab"], outputs: ["tabChange"] }] });
|
|
10087
|
+
}
|
|
10088
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileInquiriesPageComponent, decorators: [{
|
|
10089
|
+
type: Component,
|
|
10090
|
+
args: [{ selector: 'app-mobile-inquiries-page', standalone: true, imports: [
|
|
10091
|
+
DsMobilePageMainComponent,
|
|
10092
|
+
DsMobileContentComponent,
|
|
10093
|
+
DsMobileInteractiveListItemInquiryComponent,
|
|
10094
|
+
DsIconComponent,
|
|
10095
|
+
DsMobileTabBarComponent
|
|
10096
|
+
], host: {
|
|
10097
|
+
class: 'ion-page'
|
|
10098
|
+
}, template: `
|
|
10099
|
+
<ds-mobile-page-main
|
|
10100
|
+
title="Henvendelser"
|
|
10101
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
10102
|
+
[avatarType]="userService.avatarType()">
|
|
10103
|
+
|
|
10104
|
+
<!-- Filter tabs in header -->
|
|
10105
|
+
<div header-content>
|
|
10106
|
+
<ds-mobile-tab-bar
|
|
10107
|
+
[tabs]="tabItems"
|
|
10108
|
+
[activeTab]="filterStatus()"
|
|
10109
|
+
(tabChange)="setFilter($any($event))">
|
|
10110
|
+
</ds-mobile-tab-bar>
|
|
10111
|
+
</div>
|
|
10112
|
+
|
|
10113
|
+
<ds-mobile-content>
|
|
10114
|
+
<div class="inquiries-container">
|
|
10115
|
+
@if (filteredInquiries().length > 0) {
|
|
10116
|
+
<div class="inquiry-list-wrapper">
|
|
10117
|
+
@for (inquiry of filteredInquiries(); track inquiry.id; let idx = $index) {
|
|
10118
|
+
<ds-mobile-interactive-list-item-inquiry
|
|
10119
|
+
[title]="inquiry.title"
|
|
10120
|
+
[description]="inquiry.description"
|
|
10121
|
+
[status]="inquiry.status"
|
|
10122
|
+
[timestamp]="inquiry.timestamp"
|
|
10123
|
+
[iconName]="getInquiryIcon(inquiry.category)"
|
|
10124
|
+
[clickable]="true"
|
|
10125
|
+
[showChevron]="false"
|
|
10126
|
+
(inquiryClick)="openInquiryDetail(inquiry.id)"
|
|
10127
|
+
(longPress)="showInquiryActions(inquiry.id)">
|
|
10128
|
+
</ds-mobile-interactive-list-item-inquiry>
|
|
10129
|
+
|
|
10130
|
+
}
|
|
10131
|
+
</div>
|
|
10132
|
+
} @else {
|
|
10133
|
+
<!-- Empty state -->
|
|
10134
|
+
<div class="empty-state">
|
|
10135
|
+
<ds-icon name="remixInboxLine" size="48px" color="tertiary" />
|
|
10136
|
+
<h3 class="empty-state-title">Ingen henvendelser endnu</h3>
|
|
10137
|
+
<p class="empty-state-description">
|
|
10138
|
+
@if (filterStatus() === 'open') {
|
|
10139
|
+
Du har ingen åbne henvendelser
|
|
10140
|
+
} @else if (filterStatus() === 'closed') {
|
|
10141
|
+
Du har ingen lukkede henvendelser
|
|
10142
|
+
} @else {
|
|
10143
|
+
Du har ikke oprettet nogen henvendelser endnu
|
|
10144
|
+
}
|
|
10145
|
+
</p>
|
|
10146
|
+
</div>
|
|
10147
|
+
}
|
|
10148
|
+
</div>
|
|
10149
|
+
</ds-mobile-content>
|
|
10150
|
+
</ds-mobile-page-main>
|
|
10151
|
+
`, 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"] }]
|
|
10152
|
+
}], ctorParameters: () => [{ type: UserService }, { type: i1.NavController }] });
|
|
10153
|
+
|
|
10154
|
+
/**
|
|
10155
|
+
* DsMobileListItemStaticComponent
|
|
10156
|
+
*
|
|
10157
|
+
* A read-only version of the interactive list item component.
|
|
10158
|
+
* Used for displaying static information without interaction.
|
|
10159
|
+
*
|
|
10160
|
+
* This component has the same structure as the interactive list item but without:
|
|
10161
|
+
* - Padding
|
|
10162
|
+
* - Rounded corners
|
|
10163
|
+
* - Hover states
|
|
10164
|
+
* - Click interactions
|
|
10165
|
+
* - Background fill (transparent)
|
|
10166
|
+
*
|
|
10167
|
+
* @example
|
|
10168
|
+
* ```html
|
|
10169
|
+
* <ds-mobile-list-item-static
|
|
10170
|
+
* [leadingSize]="'40px'">
|
|
10171
|
+
*
|
|
10172
|
+
* <div content-leading>
|
|
10173
|
+
* <ds-avatar initials="JD" />
|
|
10174
|
+
* </div>
|
|
10175
|
+
*
|
|
10176
|
+
* <div content-main>
|
|
10177
|
+
* <h3>Main Content</h3>
|
|
10178
|
+
* <p>Supporting text goes here...</p>
|
|
10179
|
+
* </div>
|
|
10180
|
+
*
|
|
10181
|
+
* <div content-trailing>
|
|
10182
|
+
* <span>Info</span>
|
|
10183
|
+
* </div>
|
|
10184
|
+
* </ds-mobile-list-item-static>
|
|
10185
|
+
* ```
|
|
10186
|
+
*/
|
|
10187
|
+
class DsMobileListItemStaticComponent {
|
|
10188
|
+
/**
|
|
10189
|
+
* CSS size value for the leading content area (e.g., '32px', '40px', '48px')
|
|
10190
|
+
* Defaults to '32px' for standard list item avatars
|
|
10191
|
+
*/
|
|
10192
|
+
leadingSize = input('32px', ...(ngDevMode ? [{ debugName: "leadingSize" }] : []));
|
|
10193
|
+
/**
|
|
10194
|
+
* Check if leading content slot has content
|
|
10195
|
+
*/
|
|
10196
|
+
hasLeadingContent = computed(() => true, ...(ngDevMode ? [{ debugName: "hasLeadingContent" }] : [])); // Always render slot container for consistency
|
|
10197
|
+
/**
|
|
10198
|
+
* Check if trailing content slot has content
|
|
10199
|
+
*/
|
|
10200
|
+
hasTrailingContent = computed(() => true, ...(ngDevMode ? [{ debugName: "hasTrailingContent" }] : [])); // Always render slot container for consistency
|
|
10201
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobileListItemStaticComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10202
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: DsMobileListItemStaticComponent, isStandalone: true, selector: "ds-mobile-list-item-static", inputs: { leadingSize: { classPropertyName: "leadingSize", publicName: "leadingSize", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.--leading-size": "leadingSize()" } }, ngImport: i0, template: `
|
|
10203
|
+
@if (hasLeadingContent()) {
|
|
10204
|
+
<div class="content-leading">
|
|
10205
|
+
<ng-content select="[content-leading]" />
|
|
10206
|
+
</div>
|
|
10207
|
+
}
|
|
10208
|
+
|
|
10209
|
+
<div class="content-main">
|
|
10210
|
+
<ng-content select="[content-main]" />
|
|
10211
|
+
<ng-content />
|
|
10212
|
+
</div>
|
|
10213
|
+
|
|
10214
|
+
@if (hasTrailingContent()) {
|
|
10215
|
+
<div class="content-trailing">
|
|
10216
|
+
<ng-content select="[content-trailing]" />
|
|
10217
|
+
</div>
|
|
10218
|
+
}
|
|
10219
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:row;align-items:flex-start;background:transparent;padding:0;gap:12px;position:relative;--leading-size: 32px}:host:after{content:\"\";position:absolute;bottom:-10px;left:calc(var(--leading-size) + 12px);right:0;height:1px;background:var(--border-color-default)}:host:last-child:after{display:none}.content-leading{flex-shrink:0;width:var(--leading-size);min-height:var(--leading-size);height:auto;display:flex;align-items:center;justify-content:center}.content-main{flex:1;min-width:0;min-height:var(--leading-size);display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:8px}.content-trailing{flex-shrink:0;display:flex;align-items:flex-start}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
10220
|
+
}
|
|
10221
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobileListItemStaticComponent, decorators: [{
|
|
10222
|
+
type: Component,
|
|
10223
|
+
args: [{ selector: 'ds-mobile-list-item-static', standalone: true, imports: [CommonModule], host: {
|
|
10224
|
+
'[style.--leading-size]': 'leadingSize()'
|
|
10225
|
+
}, template: `
|
|
10226
|
+
@if (hasLeadingContent()) {
|
|
10227
|
+
<div class="content-leading">
|
|
10228
|
+
<ng-content select="[content-leading]" />
|
|
10229
|
+
</div>
|
|
10230
|
+
}
|
|
10231
|
+
|
|
10232
|
+
<div class="content-main">
|
|
10233
|
+
<ng-content select="[content-main]" />
|
|
10234
|
+
<ng-content />
|
|
10235
|
+
</div>
|
|
10236
|
+
|
|
10237
|
+
@if (hasTrailingContent()) {
|
|
10238
|
+
<div class="content-trailing">
|
|
10239
|
+
<ng-content select="[content-trailing]" />
|
|
10240
|
+
</div>
|
|
10241
|
+
}
|
|
10242
|
+
`, styles: [":host{display:flex;flex-direction:row;align-items:flex-start;background:transparent;padding:0;gap:12px;position:relative;--leading-size: 32px}:host:after{content:\"\";position:absolute;bottom:-10px;left:calc(var(--leading-size) + 12px);right:0;height:1px;background:var(--border-color-default)}:host:last-child:after{display:none}.content-leading{flex-shrink:0;width:var(--leading-size);min-height:var(--leading-size);height:auto;display:flex;align-items:center;justify-content:center}.content-main{flex:1;min-width:0;min-height:var(--leading-size);display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:8px}.content-trailing{flex-shrink:0;display:flex;align-items:flex-start}\n"] }]
|
|
10243
|
+
}], propDecorators: { leadingSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "leadingSize", required: false }] }] } });
|
|
10244
|
+
|
|
10245
|
+
class MobileInquiryDetailPageComponent extends MobilePageBase {
|
|
10246
|
+
userService;
|
|
10247
|
+
navCtrl;
|
|
10248
|
+
elementRef;
|
|
10249
|
+
ionContent;
|
|
10250
|
+
// Platform detection
|
|
10251
|
+
platform = inject(Platform);
|
|
10252
|
+
// Computed property to check if running on native platform
|
|
10253
|
+
isNativePlatform = computed(() => this.platform.is('ios') ||
|
|
10254
|
+
this.platform.is('android') ||
|
|
10255
|
+
this.platform.is('capacitor'), ...(ngDevMode ? [{ debugName: "isNativePlatform" }] : []));
|
|
10256
|
+
inquiryTitle = 'Tørretumbler virker ikke';
|
|
10257
|
+
activeTab = signal('activity', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
|
|
10258
|
+
tabItems = [
|
|
10259
|
+
{ id: 'activity', label: 'Aktivitet' },
|
|
10260
|
+
{ id: 'messages', label: 'Beskeder', badge: 0 },
|
|
10261
|
+
{ id: 'details', label: 'Detaljer' }
|
|
10262
|
+
];
|
|
10263
|
+
activities = [
|
|
10264
|
+
{
|
|
10265
|
+
id: '1',
|
|
10266
|
+
type: 'assignment',
|
|
10267
|
+
actor: 'Martin Smith',
|
|
10268
|
+
actorInitials: 'MS',
|
|
10269
|
+
title: 'er blevet tildelt som din dedikerede tekniker.',
|
|
10270
|
+
timestamp: '2 dage siden',
|
|
10271
|
+
date: '28. feb 2025',
|
|
10272
|
+
iconName: 'remixUserAddLine'
|
|
10273
|
+
},
|
|
10274
|
+
{
|
|
10275
|
+
id: '2',
|
|
10276
|
+
type: 'assignment',
|
|
10277
|
+
actor: 'Ricki Meihlen',
|
|
10278
|
+
actorInitials: 'RM',
|
|
10279
|
+
title: 'er blevet tildelt til at håndtere din henvendelse.',
|
|
10280
|
+
timestamp: '8 dage siden',
|
|
10281
|
+
date: '22. feb 2025',
|
|
10282
|
+
iconName: 'remixUserLine'
|
|
10283
|
+
},
|
|
10284
|
+
{
|
|
10285
|
+
id: '3',
|
|
10286
|
+
type: 'creation',
|
|
10287
|
+
title: 'Henvendelse oprettet',
|
|
10288
|
+
timestamp: '8 dage siden',
|
|
10289
|
+
date: '22. feb 2025',
|
|
10290
|
+
iconName: 'remixAddCircleLine'
|
|
10291
|
+
}
|
|
10292
|
+
];
|
|
10293
|
+
messageThreads = [
|
|
10294
|
+
{
|
|
10295
|
+
id: '1',
|
|
10296
|
+
senderName: 'Ove Hindborg',
|
|
10297
|
+
senderAvatar: '',
|
|
10298
|
+
senderInitials: 'OH',
|
|
10299
|
+
message: 'Dejligt at høre! Jeg venter på din teknikerbesøg tidsplan.',
|
|
10300
|
+
role: 'Sagsbehandler',
|
|
10301
|
+
timestamp: '2t siden',
|
|
10302
|
+
unread: true
|
|
10303
|
+
},
|
|
10304
|
+
{
|
|
10305
|
+
id: '2',
|
|
10306
|
+
senderName: 'Martin Smith',
|
|
10307
|
+
senderAvatar: '',
|
|
10308
|
+
senderInitials: 'MS',
|
|
10309
|
+
message: 'Dejligt at høre! Jeg venter på din teknikerbesøg tidsplan.',
|
|
10310
|
+
role: 'Tekniker',
|
|
10311
|
+
timestamp: '4t siden',
|
|
10312
|
+
unread: true
|
|
10313
|
+
}
|
|
10314
|
+
];
|
|
10315
|
+
unreadMessagesCount = computed(() => {
|
|
10316
|
+
const count = this.messageThreads.filter(m => m.unread).length;
|
|
10317
|
+
// Update badge in tab items
|
|
10318
|
+
const messagesTab = this.tabItems.find(t => t.id === 'messages');
|
|
10319
|
+
if (messagesTab) {
|
|
10320
|
+
messagesTab.badge = count;
|
|
10321
|
+
}
|
|
10322
|
+
return count;
|
|
10323
|
+
}, ...(ngDevMode ? [{ debugName: "unreadMessagesCount" }] : []));
|
|
10324
|
+
constructor(userService, navCtrl, elementRef) {
|
|
10325
|
+
super();
|
|
10326
|
+
this.userService = userService;
|
|
10327
|
+
this.navCtrl = navCtrl;
|
|
10328
|
+
this.elementRef = elementRef;
|
|
10329
|
+
// Trigger initial badge update
|
|
10330
|
+
this.unreadMessagesCount();
|
|
10331
|
+
}
|
|
10332
|
+
ngAfterViewInit() {
|
|
10333
|
+
// Initial setup if needed
|
|
10334
|
+
}
|
|
10335
|
+
setActiveTab(tabId) {
|
|
10336
|
+
this.activeTab.set(tabId);
|
|
10337
|
+
}
|
|
10338
|
+
goBack() {
|
|
10339
|
+
this.navCtrl.back({ animation: customBackTransition });
|
|
10340
|
+
}
|
|
10341
|
+
handleScroll(event) {
|
|
10342
|
+
const scrollTop = event.detail.scrollTop;
|
|
10343
|
+
const threshold = 160;
|
|
10344
|
+
const fadeDistance = 200;
|
|
10345
|
+
const header = this.elementRef.nativeElement.querySelector('ion-header:not([collapse])');
|
|
10346
|
+
const headerExpandable = this.elementRef.nativeElement.querySelector('.header-expandable');
|
|
10347
|
+
// Show title in fixed header when scrolled past threshold
|
|
10348
|
+
if (scrollTop > threshold) {
|
|
10349
|
+
header?.classList.add('header-scrolled');
|
|
10350
|
+
}
|
|
10351
|
+
else {
|
|
10352
|
+
header?.classList.remove('header-scrolled');
|
|
10353
|
+
}
|
|
10354
|
+
// Fade out header-expandable content based on scroll
|
|
10355
|
+
if (headerExpandable) {
|
|
10356
|
+
const fadeProgress = Math.min(scrollTop / fadeDistance, 1);
|
|
10357
|
+
// Calculate opacity (1 to 0)
|
|
10358
|
+
const opacity = 1 - fadeProgress;
|
|
10359
|
+
// Calculate transform (0px to -20px upward)
|
|
10360
|
+
const translateY = fadeProgress * -20;
|
|
10361
|
+
// Apply styles
|
|
10362
|
+
headerExpandable.style.opacity = opacity.toString();
|
|
10363
|
+
headerExpandable.style.transform = `translateY(${translateY}px)`;
|
|
10364
|
+
}
|
|
10365
|
+
}
|
|
10366
|
+
handleRefresh(event) {
|
|
10367
|
+
console.log('Pull-to-refresh triggered');
|
|
10368
|
+
setTimeout(() => {
|
|
10369
|
+
console.log('Refresh complete');
|
|
10370
|
+
event.target.complete();
|
|
10371
|
+
}, 1000);
|
|
10372
|
+
}
|
|
10373
|
+
openMessage(messageId) {
|
|
10374
|
+
console.log('Opening message:', messageId);
|
|
10375
|
+
// Navigate to message thread detail
|
|
10376
|
+
}
|
|
10377
|
+
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 });
|
|
10378
|
+
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: `
|
|
10379
|
+
<!-- Fixed header at top -->
|
|
10380
|
+
<ion-header>
|
|
10381
|
+
<ion-toolbar>
|
|
10382
|
+
<div class="header-detail">
|
|
10383
|
+
<!-- Back Button -->
|
|
10384
|
+
<button class="back-button" (click)="goBack()" [attr.aria-label]="'Go back'">
|
|
10385
|
+
<ds-icon name="remixArrowLeftSLine" size="24px" color="white" />
|
|
10386
|
+
</button>
|
|
10387
|
+
|
|
10388
|
+
<!-- Title - fades in on scroll -->
|
|
10389
|
+
<ion-title class="header-detail__title">{{ inquiryTitle }}</ion-title>
|
|
10390
|
+
</div>
|
|
10391
|
+
</ion-toolbar>
|
|
10392
|
+
</ion-header>
|
|
10393
|
+
|
|
10394
|
+
<!-- Content with expandable header -->
|
|
10395
|
+
<ion-content [scrollEvents]="true" (ionScroll)="handleScroll($event)">
|
|
10396
|
+
<!-- Pull to refresh (only on native iOS/Android) -->
|
|
10397
|
+
@if (isNativePlatform()) {
|
|
10398
|
+
<ion-refresher
|
|
10399
|
+
slot="fixed"
|
|
10400
|
+
(ionRefresh)="handleRefresh($event)"
|
|
10401
|
+
[pullFactor]="0.4"
|
|
10402
|
+
[pullMin]="80"
|
|
10403
|
+
[pullMax]="240"
|
|
10404
|
+
closeDuration="600ms">
|
|
10405
|
+
<ion-refresher-content
|
|
10406
|
+
pullingIcon="chevron-down-circle-outline"
|
|
10407
|
+
refreshingSpinner="lines">
|
|
10408
|
+
</ion-refresher-content>
|
|
10409
|
+
</ion-refresher>
|
|
10410
|
+
}
|
|
10411
|
+
|
|
10412
|
+
<!-- Expandable header section (purple background) -->
|
|
10413
|
+
<div class="header-expandable">
|
|
10414
|
+
<div class="header-expandable-inner">
|
|
10415
|
+
<div class="header-expandable__text">
|
|
10416
|
+
<h1 class="header-expandable__title">{{ inquiryTitle }}</h1>
|
|
10417
|
+
</div>
|
|
10418
|
+
|
|
10419
|
+
<!-- Tabs in header -->
|
|
10420
|
+
<ds-mobile-tab-bar
|
|
10421
|
+
[tabs]="tabItems"
|
|
10422
|
+
[activeTab]="activeTab()"
|
|
10423
|
+
(tabChange)="setActiveTab($event)">
|
|
10424
|
+
</ds-mobile-tab-bar>
|
|
10425
|
+
</div>
|
|
10426
|
+
</div>
|
|
10427
|
+
|
|
10428
|
+
<!-- Content wrapper -->
|
|
10429
|
+
<div class="content-wrapper">
|
|
10430
|
+
<div class="content-inner">
|
|
10431
|
+
<!-- Activity Tab Content -->
|
|
10432
|
+
@if (activeTab() === 'activity') {
|
|
10433
|
+
<div class="activity-list">
|
|
10434
|
+
@for (activity of activities; track activity.id) {
|
|
10435
|
+
<div class="activity-item">
|
|
10436
|
+
@if (activity.actor) {
|
|
10437
|
+
<!-- Avatar with badge for actor activities -->
|
|
10438
|
+
<div class="avatar-wrapper">
|
|
10439
|
+
<ds-avatar
|
|
10440
|
+
[type]="'initials'"
|
|
10441
|
+
[initials]="activity.actorInitials || ''"
|
|
10442
|
+
size="md" />
|
|
10443
|
+
|
|
10444
|
+
<div class="avatar-badge">
|
|
10445
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 32" fill="none">
|
|
10446
|
+
<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"/>
|
|
10447
|
+
<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"/>
|
|
10448
|
+
</svg>
|
|
10449
|
+
</div>
|
|
10450
|
+
</div>
|
|
10451
|
+
} @else {
|
|
10452
|
+
<!-- Icon wrapper for non-actor activities -->
|
|
10453
|
+
<div class="activity-icon-wrapper">
|
|
10454
|
+
<ds-icon
|
|
10455
|
+
[name]="activity.iconName"
|
|
10456
|
+
size="18px"
|
|
10457
|
+
color="secondary" />
|
|
10458
|
+
</div>
|
|
10459
|
+
}
|
|
10460
|
+
|
|
10461
|
+
<div class="activity-content">
|
|
10462
|
+
<p class="activity-title">
|
|
10463
|
+
@if (activity.actor) {
|
|
10464
|
+
<span class="actor-name">{{ activity.actor }}</span>
|
|
10465
|
+
<span class="activity-text"> {{ activity.title }}</span>
|
|
10466
|
+
} @else {
|
|
10467
|
+
<span class="actor-name">{{ activity.title }}</span>
|
|
10468
|
+
}
|
|
10469
|
+
</p>
|
|
10470
|
+
@if (activity.description) {
|
|
10471
|
+
<p class="activity-description">{{ activity.description }}</p>
|
|
10472
|
+
}
|
|
10473
|
+
<div class="activity-timestamp">
|
|
10474
|
+
<ds-icon name="remixCalendarLine" size="12px" color="--color-text-tertiary" />
|
|
10475
|
+
<span>{{ activity.date }}</span>
|
|
10476
|
+
</div>
|
|
10477
|
+
</div>
|
|
10478
|
+
</div>
|
|
10479
|
+
}
|
|
10480
|
+
</div>
|
|
10481
|
+
}
|
|
10482
|
+
|
|
10483
|
+
<!-- Messages Tab Content -->
|
|
10484
|
+
@if (activeTab() === 'messages') {
|
|
10485
|
+
<div class="messages-list">
|
|
10486
|
+
@for (message of messageThreads; track message.id) {
|
|
10487
|
+
<ds-mobile-interactive-list-item-message
|
|
10488
|
+
[senderName]="message.senderName"
|
|
10489
|
+
[senderRole]="message.role"
|
|
10490
|
+
[message]="message.message"
|
|
10491
|
+
[avatarInitials]="message.senderInitials"
|
|
10492
|
+
[unread]="message.unread"
|
|
10493
|
+
(messageClick)="openMessage(message.id)">
|
|
10494
|
+
</ds-mobile-interactive-list-item-message>
|
|
10495
|
+
}
|
|
10496
|
+
</div>
|
|
10497
|
+
}
|
|
10498
|
+
|
|
10499
|
+
<!-- Details Tab Content -->
|
|
10500
|
+
@if (activeTab() === 'details') {
|
|
10501
|
+
<div class="details-list">
|
|
10502
|
+
<!-- Assignee -->
|
|
10503
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10504
|
+
<div content-leading>
|
|
10505
|
+
<ds-avatar
|
|
10506
|
+
[size]="'sm'"
|
|
10507
|
+
[type]="'initials'"
|
|
10508
|
+
[initials]="'R'" />
|
|
10509
|
+
</div>
|
|
10510
|
+
<div content-main>
|
|
10511
|
+
<div class="detail-label">Sagsbehandler</div>
|
|
10512
|
+
<div class="detail-value">Ricki Meihlen</div>
|
|
10513
|
+
</div>
|
|
10514
|
+
</ds-mobile-list-item-static>
|
|
10515
|
+
|
|
10516
|
+
<!-- Technician -->
|
|
10517
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10518
|
+
<div content-leading>
|
|
10519
|
+
<ds-avatar
|
|
10520
|
+
[size]="'sm'"
|
|
10521
|
+
[type]="'initials'"
|
|
10522
|
+
[initials]="'M'" />
|
|
10523
|
+
</div>
|
|
10524
|
+
<div content-main>
|
|
10525
|
+
<div class="detail-label">Tekniker</div>
|
|
10526
|
+
<div class="detail-value">Martin Smith</div>
|
|
10527
|
+
</div>
|
|
10528
|
+
</ds-mobile-list-item-static>
|
|
10529
|
+
|
|
10530
|
+
<!-- Title -->
|
|
10531
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10532
|
+
<div content-leading>
|
|
10533
|
+
<ds-icon name="remixTextBlock" size="20px" color="tertiary" />
|
|
10534
|
+
</div>
|
|
10535
|
+
<div content-main>
|
|
10536
|
+
<div class="detail-value">{{ inquiryTitle }}</div>
|
|
10537
|
+
</div>
|
|
10538
|
+
</ds-mobile-list-item-static>
|
|
10539
|
+
|
|
10540
|
+
<!-- Description -->
|
|
10541
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10542
|
+
<div content-leading>
|
|
10543
|
+
<ds-icon name="remixAlignLeft" size="20px" color="tertiary" />
|
|
10544
|
+
</div>
|
|
10545
|
+
<div content-main>
|
|
10546
|
+
<div class="detail-value description-text">
|
|
10547
|
+
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.
|
|
10548
|
+
</div>
|
|
10549
|
+
<div class="detail-tag">Husholdningsapparater</div>
|
|
10550
|
+
</div>
|
|
10551
|
+
</ds-mobile-list-item-static>
|
|
10552
|
+
|
|
10553
|
+
<!-- Photos -->
|
|
10554
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10555
|
+
<div content-leading>
|
|
10556
|
+
<ds-icon name="remixCameraLine" size="20px" color="tertiary" />
|
|
10557
|
+
</div>
|
|
10558
|
+
<div content-main>
|
|
10559
|
+
<div class="photo-grid">
|
|
10560
|
+
<button class="photo-add">
|
|
10561
|
+
<ds-icon name="remixAddLine" size="20px" color="tertiary" />
|
|
10562
|
+
</button>
|
|
10563
|
+
<!-- Placeholder photos -->
|
|
10564
|
+
<div class="photo-item"></div>
|
|
10565
|
+
<div class="photo-item"></div>
|
|
10566
|
+
<div class="photo-item"></div>
|
|
10567
|
+
<div class="photo-item"></div>
|
|
10568
|
+
</div>
|
|
10569
|
+
</div>
|
|
10570
|
+
</ds-mobile-list-item-static>
|
|
10571
|
+
</div>
|
|
10572
|
+
}
|
|
10573
|
+
</div>
|
|
10574
|
+
</div>
|
|
10575
|
+
</ion-content>
|
|
10576
|
+
`, 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:#fff;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}.header-expandable__title{font-family:Brockmann,sans-serif;font-size:var(--font-size-2xl);font-weight:600;line-height:1.2;letter-spacing:-.5px;margin:0;color:#fff}@media (min-width: 768px){.header-expandable{padding:40px var(--content-padding-md) 32px var(--content-padding-md)}.header-expandable__title{font-size:var(--font-size-3xl)}}@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: DsMobileTabBarComponent, selector: "ds-mobile-tab-bar", 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"] }] });
|
|
10577
|
+
}
|
|
10578
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileInquiryDetailPageComponent, decorators: [{
|
|
10579
|
+
type: Component,
|
|
10580
|
+
args: [{ selector: 'app-mobile-inquiry-detail-page', standalone: true, imports: [
|
|
10581
|
+
CommonModule,
|
|
10582
|
+
IonHeader,
|
|
10583
|
+
IonToolbar,
|
|
10584
|
+
IonTitle,
|
|
10585
|
+
IonContent,
|
|
10586
|
+
IonRefresher,
|
|
10587
|
+
IonRefresherContent,
|
|
10588
|
+
DsIconComponent,
|
|
10589
|
+
DsAvatarComponent,
|
|
10590
|
+
DsMobileTabBarComponent,
|
|
10591
|
+
DsMobileListItemStaticComponent,
|
|
10592
|
+
DsMobileInteractiveListItemMessageComponent
|
|
10593
|
+
], host: {
|
|
10594
|
+
class: 'ion-page'
|
|
10595
|
+
}, template: `
|
|
10596
|
+
<!-- Fixed header at top -->
|
|
10597
|
+
<ion-header>
|
|
10598
|
+
<ion-toolbar>
|
|
10599
|
+
<div class="header-detail">
|
|
10600
|
+
<!-- Back Button -->
|
|
10601
|
+
<button class="back-button" (click)="goBack()" [attr.aria-label]="'Go back'">
|
|
10602
|
+
<ds-icon name="remixArrowLeftSLine" size="24px" color="white" />
|
|
10603
|
+
</button>
|
|
10604
|
+
|
|
10605
|
+
<!-- Title - fades in on scroll -->
|
|
10606
|
+
<ion-title class="header-detail__title">{{ inquiryTitle }}</ion-title>
|
|
10607
|
+
</div>
|
|
10608
|
+
</ion-toolbar>
|
|
10609
|
+
</ion-header>
|
|
10610
|
+
|
|
10611
|
+
<!-- Content with expandable header -->
|
|
10612
|
+
<ion-content [scrollEvents]="true" (ionScroll)="handleScroll($event)">
|
|
10613
|
+
<!-- Pull to refresh (only on native iOS/Android) -->
|
|
10614
|
+
@if (isNativePlatform()) {
|
|
10615
|
+
<ion-refresher
|
|
10616
|
+
slot="fixed"
|
|
10617
|
+
(ionRefresh)="handleRefresh($event)"
|
|
10618
|
+
[pullFactor]="0.4"
|
|
10619
|
+
[pullMin]="80"
|
|
10620
|
+
[pullMax]="240"
|
|
10621
|
+
closeDuration="600ms">
|
|
10622
|
+
<ion-refresher-content
|
|
10623
|
+
pullingIcon="chevron-down-circle-outline"
|
|
10624
|
+
refreshingSpinner="lines">
|
|
10625
|
+
</ion-refresher-content>
|
|
10626
|
+
</ion-refresher>
|
|
10627
|
+
}
|
|
10628
|
+
|
|
10629
|
+
<!-- Expandable header section (purple background) -->
|
|
10630
|
+
<div class="header-expandable">
|
|
10631
|
+
<div class="header-expandable-inner">
|
|
10632
|
+
<div class="header-expandable__text">
|
|
10633
|
+
<h1 class="header-expandable__title">{{ inquiryTitle }}</h1>
|
|
10634
|
+
</div>
|
|
10635
|
+
|
|
10636
|
+
<!-- Tabs in header -->
|
|
10637
|
+
<ds-mobile-tab-bar
|
|
10638
|
+
[tabs]="tabItems"
|
|
10639
|
+
[activeTab]="activeTab()"
|
|
10640
|
+
(tabChange)="setActiveTab($event)">
|
|
10641
|
+
</ds-mobile-tab-bar>
|
|
10642
|
+
</div>
|
|
10643
|
+
</div>
|
|
10644
|
+
|
|
10645
|
+
<!-- Content wrapper -->
|
|
10646
|
+
<div class="content-wrapper">
|
|
10647
|
+
<div class="content-inner">
|
|
10648
|
+
<!-- Activity Tab Content -->
|
|
10649
|
+
@if (activeTab() === 'activity') {
|
|
10650
|
+
<div class="activity-list">
|
|
10651
|
+
@for (activity of activities; track activity.id) {
|
|
10652
|
+
<div class="activity-item">
|
|
10653
|
+
@if (activity.actor) {
|
|
10654
|
+
<!-- Avatar with badge for actor activities -->
|
|
10655
|
+
<div class="avatar-wrapper">
|
|
10656
|
+
<ds-avatar
|
|
10657
|
+
[type]="'initials'"
|
|
10658
|
+
[initials]="activity.actorInitials || ''"
|
|
10659
|
+
size="md" />
|
|
10660
|
+
|
|
10661
|
+
<div class="avatar-badge">
|
|
10662
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 32" fill="none">
|
|
10663
|
+
<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"/>
|
|
10664
|
+
<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"/>
|
|
10665
|
+
</svg>
|
|
10666
|
+
</div>
|
|
10667
|
+
</div>
|
|
10668
|
+
} @else {
|
|
10669
|
+
<!-- Icon wrapper for non-actor activities -->
|
|
10670
|
+
<div class="activity-icon-wrapper">
|
|
10671
|
+
<ds-icon
|
|
10672
|
+
[name]="activity.iconName"
|
|
10673
|
+
size="18px"
|
|
10674
|
+
color="secondary" />
|
|
10675
|
+
</div>
|
|
10676
|
+
}
|
|
10677
|
+
|
|
10678
|
+
<div class="activity-content">
|
|
10679
|
+
<p class="activity-title">
|
|
10680
|
+
@if (activity.actor) {
|
|
10681
|
+
<span class="actor-name">{{ activity.actor }}</span>
|
|
10682
|
+
<span class="activity-text"> {{ activity.title }}</span>
|
|
10683
|
+
} @else {
|
|
10684
|
+
<span class="actor-name">{{ activity.title }}</span>
|
|
10685
|
+
}
|
|
10686
|
+
</p>
|
|
10687
|
+
@if (activity.description) {
|
|
10688
|
+
<p class="activity-description">{{ activity.description }}</p>
|
|
10689
|
+
}
|
|
10690
|
+
<div class="activity-timestamp">
|
|
10691
|
+
<ds-icon name="remixCalendarLine" size="12px" color="--color-text-tertiary" />
|
|
10692
|
+
<span>{{ activity.date }}</span>
|
|
10693
|
+
</div>
|
|
10694
|
+
</div>
|
|
10695
|
+
</div>
|
|
10696
|
+
}
|
|
10697
|
+
</div>
|
|
10698
|
+
}
|
|
10699
|
+
|
|
10700
|
+
<!-- Messages Tab Content -->
|
|
10701
|
+
@if (activeTab() === 'messages') {
|
|
10702
|
+
<div class="messages-list">
|
|
10703
|
+
@for (message of messageThreads; track message.id) {
|
|
10704
|
+
<ds-mobile-interactive-list-item-message
|
|
10705
|
+
[senderName]="message.senderName"
|
|
10706
|
+
[senderRole]="message.role"
|
|
10707
|
+
[message]="message.message"
|
|
10708
|
+
[avatarInitials]="message.senderInitials"
|
|
10709
|
+
[unread]="message.unread"
|
|
10710
|
+
(messageClick)="openMessage(message.id)">
|
|
10711
|
+
</ds-mobile-interactive-list-item-message>
|
|
10712
|
+
}
|
|
10713
|
+
</div>
|
|
10714
|
+
}
|
|
10715
|
+
|
|
10716
|
+
<!-- Details Tab Content -->
|
|
10717
|
+
@if (activeTab() === 'details') {
|
|
10718
|
+
<div class="details-list">
|
|
10719
|
+
<!-- Assignee -->
|
|
10720
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10721
|
+
<div content-leading>
|
|
10722
|
+
<ds-avatar
|
|
10723
|
+
[size]="'sm'"
|
|
10724
|
+
[type]="'initials'"
|
|
10725
|
+
[initials]="'R'" />
|
|
10726
|
+
</div>
|
|
10727
|
+
<div content-main>
|
|
10728
|
+
<div class="detail-label">Sagsbehandler</div>
|
|
10729
|
+
<div class="detail-value">Ricki Meihlen</div>
|
|
10730
|
+
</div>
|
|
10731
|
+
</ds-mobile-list-item-static>
|
|
10732
|
+
|
|
10733
|
+
<!-- Technician -->
|
|
10734
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10735
|
+
<div content-leading>
|
|
10736
|
+
<ds-avatar
|
|
10737
|
+
[size]="'sm'"
|
|
10738
|
+
[type]="'initials'"
|
|
10739
|
+
[initials]="'M'" />
|
|
10740
|
+
</div>
|
|
10741
|
+
<div content-main>
|
|
10742
|
+
<div class="detail-label">Tekniker</div>
|
|
10743
|
+
<div class="detail-value">Martin Smith</div>
|
|
10744
|
+
</div>
|
|
10745
|
+
</ds-mobile-list-item-static>
|
|
10746
|
+
|
|
10747
|
+
<!-- Title -->
|
|
10748
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10749
|
+
<div content-leading>
|
|
10750
|
+
<ds-icon name="remixTextBlock" size="20px" color="tertiary" />
|
|
10751
|
+
</div>
|
|
10752
|
+
<div content-main>
|
|
10753
|
+
<div class="detail-value">{{ inquiryTitle }}</div>
|
|
10754
|
+
</div>
|
|
10755
|
+
</ds-mobile-list-item-static>
|
|
10756
|
+
|
|
10757
|
+
<!-- Description -->
|
|
10758
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10759
|
+
<div content-leading>
|
|
10760
|
+
<ds-icon name="remixAlignLeft" size="20px" color="tertiary" />
|
|
10761
|
+
</div>
|
|
10762
|
+
<div content-main>
|
|
10763
|
+
<div class="detail-value description-text">
|
|
10764
|
+
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.
|
|
10765
|
+
</div>
|
|
10766
|
+
<div class="detail-tag">Husholdningsapparater</div>
|
|
10767
|
+
</div>
|
|
10768
|
+
</ds-mobile-list-item-static>
|
|
10769
|
+
|
|
10770
|
+
<!-- Photos -->
|
|
10771
|
+
<ds-mobile-list-item-static [leadingSize]="'32px'">
|
|
10772
|
+
<div content-leading>
|
|
10773
|
+
<ds-icon name="remixCameraLine" size="20px" color="tertiary" />
|
|
10774
|
+
</div>
|
|
10775
|
+
<div content-main>
|
|
10776
|
+
<div class="photo-grid">
|
|
10777
|
+
<button class="photo-add">
|
|
10778
|
+
<ds-icon name="remixAddLine" size="20px" color="tertiary" />
|
|
10779
|
+
</button>
|
|
10780
|
+
<!-- Placeholder photos -->
|
|
10781
|
+
<div class="photo-item"></div>
|
|
10782
|
+
<div class="photo-item"></div>
|
|
10783
|
+
<div class="photo-item"></div>
|
|
10784
|
+
<div class="photo-item"></div>
|
|
10785
|
+
</div>
|
|
10786
|
+
</div>
|
|
10787
|
+
</ds-mobile-list-item-static>
|
|
10788
|
+
</div>
|
|
10789
|
+
}
|
|
10790
|
+
</div>
|
|
10791
|
+
</div>
|
|
10792
|
+
</ion-content>
|
|
10793
|
+
`, 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:#fff;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}.header-expandable__title{font-family:Brockmann,sans-serif;font-size:var(--font-size-2xl);font-weight:600;line-height:1.2;letter-spacing:-.5px;margin:0;color:#fff}@media (min-width: 768px){.header-expandable{padding:40px var(--content-padding-md) 32px var(--content-padding-md)}.header-expandable__title{font-size:var(--font-size-3xl)}}@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"] }]
|
|
10794
|
+
}], ctorParameters: () => [{ type: UserService }, { type: i1.NavController }, { type: i0.ElementRef }], propDecorators: { ionContent: [{
|
|
10795
|
+
type: ViewChild,
|
|
10796
|
+
args: [IonContent]
|
|
10797
|
+
}] } });
|
|
10798
|
+
|
|
10799
|
+
/**
|
|
10800
|
+
* DsMobileTabsComponent
|
|
10801
|
+
*
|
|
10802
|
+
* Responsive tab navigation that adapts from mobile to desktop:
|
|
10803
|
+
* - Mobile (< 768px): Bottom tab bar with icons + labels
|
|
10804
|
+
* - Desktop (≥ 768px): Top navigation bar with logo, tabs, and avatar
|
|
10805
|
+
*
|
|
10806
|
+
* Wraps ion-tabs to maintain native routing functionality while
|
|
10807
|
+
* providing a responsive navigation experience with branding.
|
|
10808
|
+
*
|
|
10809
|
+
* @example
|
|
10810
|
+
* ```html
|
|
10811
|
+
* <ds-mobile-tabs
|
|
10812
|
+
* [tabs]="tabsConfig"
|
|
10813
|
+
* [avatarInitials]="'JD'"
|
|
10814
|
+
* (avatarClick)="handleAvatarClick()"
|
|
10815
|
+
* />
|
|
10816
|
+
* ```
|
|
10817
|
+
*/
|
|
10818
|
+
class DsMobileTabsComponent {
|
|
10819
|
+
elementRef;
|
|
10820
|
+
platformId = inject(PLATFORM_ID);
|
|
10821
|
+
resizeListener;
|
|
10822
|
+
mutationObserver;
|
|
10823
|
+
// Inputs
|
|
10824
|
+
tabs = [];
|
|
10825
|
+
// Avatar inputs
|
|
10826
|
+
avatarType = 'initials';
|
|
10827
|
+
avatarInitials = 'U';
|
|
10828
|
+
avatarSrc = '';
|
|
10829
|
+
avatarIconName = 'remixUser3Line';
|
|
10830
|
+
// Outputs
|
|
10831
|
+
avatarClick = new EventEmitter();
|
|
10832
|
+
// Internal state
|
|
10833
|
+
activeTab = signal('', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
|
|
10834
|
+
isDesktop = signal(false, ...(ngDevMode ? [{ debugName: "isDesktop" }] : []));
|
|
10835
|
+
constructor(elementRef) {
|
|
10836
|
+
this.elementRef = elementRef;
|
|
10837
|
+
}
|
|
10838
|
+
ngOnInit() {
|
|
10839
|
+
console.log('DsMobileTabsComponent initialized');
|
|
10840
|
+
// Only run breakpoint detection in browser
|
|
10841
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
10842
|
+
// Initial check
|
|
10843
|
+
this.checkBreakpoint();
|
|
10844
|
+
// Listen for window resize
|
|
10845
|
+
this.resizeListener = () => this.checkBreakpoint();
|
|
10846
|
+
window.addEventListener('resize', this.resizeListener);
|
|
10847
|
+
}
|
|
10848
|
+
}
|
|
10849
|
+
ngAfterViewInit() {
|
|
10850
|
+
// Initial removal
|
|
10851
|
+
this.removeTitleAttributes();
|
|
10852
|
+
// Set up mutation observer to continuously remove title attributes
|
|
10853
|
+
this.setupTitleRemovalObserver();
|
|
10854
|
+
}
|
|
10855
|
+
ngOnDestroy() {
|
|
10856
|
+
if (isPlatformBrowser(this.platformId) && this.resizeListener) {
|
|
10857
|
+
window.removeEventListener('resize', this.resizeListener);
|
|
10858
|
+
}
|
|
10859
|
+
if (this.mutationObserver) {
|
|
10860
|
+
this.mutationObserver.disconnect();
|
|
10861
|
+
}
|
|
10862
|
+
}
|
|
10863
|
+
setupTitleRemovalObserver() {
|
|
10864
|
+
const config = {
|
|
10865
|
+
attributes: true,
|
|
10866
|
+
attributeFilter: ['title'],
|
|
10867
|
+
subtree: true,
|
|
10868
|
+
childList: true
|
|
10869
|
+
};
|
|
10870
|
+
this.mutationObserver = new MutationObserver((mutations) => {
|
|
10871
|
+
mutations.forEach((mutation) => {
|
|
10872
|
+
if (mutation.type === 'attributes' && mutation.attributeName === 'title') {
|
|
10873
|
+
const target = mutation.target;
|
|
10874
|
+
if (target.tagName === 'ION-TAB-BUTTON' && target.hasAttribute('title')) {
|
|
10875
|
+
target.removeAttribute('title');
|
|
10876
|
+
}
|
|
10877
|
+
}
|
|
10878
|
+
});
|
|
10879
|
+
// Also do a sweep after any changes
|
|
10880
|
+
this.removeTitleAttributes();
|
|
10881
|
+
});
|
|
10882
|
+
this.mutationObserver.observe(this.elementRef.nativeElement, config);
|
|
10883
|
+
}
|
|
10884
|
+
removeTitleAttributes() {
|
|
10885
|
+
const tabButtons = this.elementRef.nativeElement.querySelectorAll('ion-tab-button');
|
|
10886
|
+
tabButtons.forEach((button) => {
|
|
10887
|
+
if (button.hasAttribute('title')) {
|
|
10888
|
+
button.removeAttribute('title');
|
|
10889
|
+
}
|
|
10890
|
+
// Also remove from the native button inside shadow DOM
|
|
10891
|
+
const nativeButton = button.shadowRoot?.querySelector('button');
|
|
10892
|
+
if (nativeButton?.hasAttribute('title')) {
|
|
10893
|
+
nativeButton.removeAttribute('title');
|
|
10894
|
+
}
|
|
10895
|
+
});
|
|
10896
|
+
}
|
|
10897
|
+
checkBreakpoint() {
|
|
10898
|
+
// 768px matches the @media (min-width: 768px) in CSS
|
|
10899
|
+
this.isDesktop.set(window.innerWidth >= 768);
|
|
10900
|
+
}
|
|
10901
|
+
trackByTabId(index, tab) {
|
|
10902
|
+
return tab.id;
|
|
10903
|
+
}
|
|
10904
|
+
isTabActive(tabId) {
|
|
10905
|
+
return this.activeTab() === tabId;
|
|
10906
|
+
}
|
|
10907
|
+
handleAvatarClick() {
|
|
10908
|
+
this.avatarClick.emit();
|
|
10909
|
+
}
|
|
10910
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobileTabsComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
10911
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: DsMobileTabsComponent, isStandalone: true, selector: "ds-mobile-tabs", inputs: { tabs: "tabs", avatarType: "avatarType", avatarInitials: "avatarInitials", avatarSrc: "avatarSrc", avatarIconName: "avatarIconName" }, outputs: { avatarClick: "avatarClick" }, ngImport: i0, template: `
|
|
10912
|
+
<ion-tabs>
|
|
10913
|
+
<ion-tab-bar
|
|
10914
|
+
[attr.slot]="isDesktop() ? 'top' : 'bottom'"
|
|
10915
|
+
class="ds-tab-bar"
|
|
10916
|
+
[class.ds-tab-bar--desktop]="isDesktop()">
|
|
10917
|
+
|
|
10918
|
+
<!-- Logo (desktop only, positioned via CSS) -->
|
|
10919
|
+
<div class="ds-tab-bar__logo">
|
|
10920
|
+
<svg class="logomark" width="32" height="28" viewBox="0 0 36 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
10921
|
+
<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"/>
|
|
10922
|
+
<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"/>
|
|
10923
|
+
</svg>
|
|
10924
|
+
</div>
|
|
10925
|
+
|
|
10926
|
+
<!-- Tab buttons container -->
|
|
10927
|
+
<div class="ds-tab-bar__tabs" *ngIf="tabs">
|
|
10928
|
+
<ion-tab-button
|
|
10929
|
+
*ngFor="let tab of tabs; trackBy: trackByTabId"
|
|
10930
|
+
[tab]="tab.id"
|
|
10931
|
+
[attr.data-icon]="tab.icon"
|
|
10932
|
+
[attr.data-icon-active]="tab.iconActive"
|
|
10933
|
+
[attr.aria-label]="tab.label"
|
|
10934
|
+
class="ds-tab-button ion-activatable"
|
|
10935
|
+
[class.tab-selected]="isTabActive(tab.id)">
|
|
10936
|
+
<div class="tab-icon-ripple"></div>
|
|
10937
|
+
<div class="tab-icon-wrapper">
|
|
10938
|
+
<ds-icon
|
|
10939
|
+
[name]="tab.icon"
|
|
10940
|
+
[size]="isDesktop() ? '20px' : '24px'"
|
|
10941
|
+
class="tab-icon-inactive"
|
|
10942
|
+
/>
|
|
10943
|
+
<ds-icon
|
|
10944
|
+
[name]="tab.iconActive"
|
|
10945
|
+
[size]="isDesktop() ? '20px' : '24px'"
|
|
10946
|
+
class="tab-icon-active"
|
|
10947
|
+
/>
|
|
10948
|
+
</div>
|
|
10949
|
+
<ion-label [attr.aria-hidden]="true">{{ tab.label }}</ion-label>
|
|
10950
|
+
</ion-tab-button>
|
|
10951
|
+
</div>
|
|
10952
|
+
|
|
10953
|
+
<!-- Avatar (desktop only, positioned via CSS) -->
|
|
10954
|
+
<div class="ds-tab-bar__actions">
|
|
10955
|
+
<ds-avatar
|
|
10956
|
+
[initials]="avatarInitials"
|
|
10957
|
+
[type]="avatarType"
|
|
10958
|
+
[src]="avatarSrc"
|
|
10959
|
+
[iconName]="avatarIconName"
|
|
10960
|
+
(click)="handleAvatarClick()"
|
|
10961
|
+
style="cursor: pointer;"
|
|
10962
|
+
/>
|
|
10963
|
+
</div>
|
|
10964
|
+
</ion-tab-bar>
|
|
10965
|
+
</ion-tabs>
|
|
10966
|
+
`, isInline: true, styles: [":host{display:block;height:100vh;height:100dvh}ion-tabs{height:100%;background:var(--color-brand-secondary)}.ds-tab-bar{--background: var(--color-background-neutral-primary);transition:transform .2s ease-in-out}ion-tab-bar[slot=bottom]{border-top:1px solid var(--border-color-default);padding-top:8px;padding-bottom:calc(var(--ion-safe-area-bottom, 34px) - 4px)}@media (max-width: 767px){ion-tab-bar[slot=bottom]{position:fixed;bottom:0;left:0;right:0;z-index:100}}@media (max-width: 767px){ion-tabs:has(ds-mobile-page-details) .ds-tab-bar{transform:translateY(100%);transition:transform .3s ease}}.ds-tab-bar__logo,.ds-tab-bar__actions{display:none}.ds-tab-bar__tabs{display:flex;width:100%;justify-content:space-around;align-items:center}@media (min-width: 769px){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)}}@media (display-mode: standalone){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)!important}}@media (min-width: 768px){ion-tab-bar[slot=top]{--background: var(--color-brand-secondary);position:relative;display:flex;align-items:center;padding:12px 24px;height:64px;max-width:none}.ds-tab-bar__logo{display:flex;position:absolute;left:24px;align-items:center}.ds-tab-bar__actions{display:flex;position:absolute;right:24px;align-items:center;gap:12px}.ds-tab-bar__tabs{display:flex;gap:8px;align-items:center;max-width:640px;width:100%;margin:0 auto;justify-content:center;padding-left:var(--content-padding-md);padding-right:var(--content-padding-md)}.logomark{height:28px;width:auto;flex-shrink:0}}@media (min-width: 992px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg);justify-content:center}}@media (min-width: 1440px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-tab-button{--color: var(--text-color-default-tertiary);--color-selected: var(--color-brand-base);display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:visible}.tab-icon-ripple{position:absolute;left:50%;top:50%;width:40px;height:40px;border-radius:50%;background:var(--color-brand-base);transform:translate(-50%,-50%) scale(0);opacity:0;pointer-events:none;transition:all .6s cubic-bezier(.36,1.2,.04,1.4);z-index:0}.tab-selected .tab-icon-ripple{transform:translate(-50%,-50%) scale(2);opacity:.05;animation:ripple-fade .6s cubic-bezier(.36,.5,.04,1.8) forwards}@keyframes ripple-fade{0%{opacity:0;transform:translate(-50%,-50%) scale(0)}30%{opacity:.1}to{opacity:0;transform:translate(-50%,-50%) scale(2)}}ion-tab-button::part(native){overflow:visible}ion-tab-button ion-ripple-effect{color:var(--color-brand-base);border-radius:1000px}ion-tab-button ion-label{font-size:var(--font-size-xs);font-weight:400;letter-spacing:-.3px;margin-top:0}.tab-icon-wrapper{position:relative;width:24px;height:24px;display:flex;align-items:center;justify-content:center;z-index:1;margin-bottom:4px}.tab-icon-inactive,.tab-icon-active{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);transition:all .8s cubic-bezier(.36,1,.04,1)}.tab-icon-inactive{opacity:1;transform:translate(-50%,-50%) scale(1)}.tab-icon-active{opacity:0;transform:translate(-50%,calc(-50% - 12px)) scale(.5)}.tab-selected .tab-icon-inactive{opacity:0;transform:translate(-50%,-50%) scale(.5)}.tab-selected .tab-icon-active{opacity:1;transform:translate(-50%,-50%) scale(1)}@media (min-width: 768px){.ds-tab-button{flex-direction:row;height:40px;padding:0 16px!important;border-radius:40px;transition:all .2s ease;width:-moz-fit-content;width:fit-content;min-width:auto;flex:0 0 auto;--color: rgba(255, 255, 255, .7);--color-selected: white;background:#ffffff1a;position:relative;overflow:hidden}.tab-icon-wrapper,.tab-icon-ripple{width:20px;height:20px}.ds-tab-button::part(native){border-radius:40px}.ds-tab-button:hover{--color: white;--color-selected: white}.ds-tab-button.tab-selected{background:var(--color-background-brand);--color-selected: white}.ds-tab-button .button-native{width:auto;padding:0}.ds-tab-button ion-label{font-size:var(--font-size-sm);font-weight:500;margin:0;color:inherit}.ds-tab-button .tab-icon-wrapper{margin-right:4px;margin-bottom:0}.ds-tab-button ion-ripple-effect{color:#ffffff4d;border-radius:1000px;transform:scale(1.5)}}@media (min-width: 768px){.ds-tab-bar__actions ds-avatar{cursor:pointer;transition:transform .2s ease}.ds-tab-bar__actions ds-avatar:hover{transform:scale(1.05)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IonTabs, selector: "ion-tabs" }, { kind: "component", type: IonTabBar, selector: "ion-tab-bar", inputs: ["color", "mode", "selectedTab", "translucent"] }, { kind: "component", type: IonTabButton, selector: "ion-tab-button", inputs: ["disabled", "download", "href", "layout", "mode", "rel", "selected", "tab", "target"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }] });
|
|
10967
|
+
}
|
|
10968
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsMobileTabsComponent, decorators: [{
|
|
10969
|
+
type: Component,
|
|
10970
|
+
args: [{ selector: 'ds-mobile-tabs', standalone: true, imports: [
|
|
10971
|
+
CommonModule,
|
|
10972
|
+
IonTabs,
|
|
10973
|
+
IonTabBar,
|
|
10974
|
+
IonTabButton,
|
|
10975
|
+
IonLabel,
|
|
10976
|
+
DsIconComponent,
|
|
10977
|
+
DsAvatarComponent
|
|
10978
|
+
], template: `
|
|
10979
|
+
<ion-tabs>
|
|
10980
|
+
<ion-tab-bar
|
|
10981
|
+
[attr.slot]="isDesktop() ? 'top' : 'bottom'"
|
|
10982
|
+
class="ds-tab-bar"
|
|
10983
|
+
[class.ds-tab-bar--desktop]="isDesktop()">
|
|
10984
|
+
|
|
10985
|
+
<!-- Logo (desktop only, positioned via CSS) -->
|
|
10986
|
+
<div class="ds-tab-bar__logo">
|
|
10987
|
+
<svg class="logomark" width="32" height="28" viewBox="0 0 36 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
10988
|
+
<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"/>
|
|
10989
|
+
<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"/>
|
|
10990
|
+
</svg>
|
|
10991
|
+
</div>
|
|
10992
|
+
|
|
10993
|
+
<!-- Tab buttons container -->
|
|
10994
|
+
<div class="ds-tab-bar__tabs" *ngIf="tabs">
|
|
10995
|
+
<ion-tab-button
|
|
10996
|
+
*ngFor="let tab of tabs; trackBy: trackByTabId"
|
|
10997
|
+
[tab]="tab.id"
|
|
10998
|
+
[attr.data-icon]="tab.icon"
|
|
10999
|
+
[attr.data-icon-active]="tab.iconActive"
|
|
11000
|
+
[attr.aria-label]="tab.label"
|
|
11001
|
+
class="ds-tab-button ion-activatable"
|
|
11002
|
+
[class.tab-selected]="isTabActive(tab.id)">
|
|
11003
|
+
<div class="tab-icon-ripple"></div>
|
|
11004
|
+
<div class="tab-icon-wrapper">
|
|
11005
|
+
<ds-icon
|
|
11006
|
+
[name]="tab.icon"
|
|
11007
|
+
[size]="isDesktop() ? '20px' : '24px'"
|
|
11008
|
+
class="tab-icon-inactive"
|
|
11009
|
+
/>
|
|
11010
|
+
<ds-icon
|
|
11011
|
+
[name]="tab.iconActive"
|
|
11012
|
+
[size]="isDesktop() ? '20px' : '24px'"
|
|
11013
|
+
class="tab-icon-active"
|
|
11014
|
+
/>
|
|
11015
|
+
</div>
|
|
11016
|
+
<ion-label [attr.aria-hidden]="true">{{ tab.label }}</ion-label>
|
|
11017
|
+
</ion-tab-button>
|
|
11018
|
+
</div>
|
|
11019
|
+
|
|
11020
|
+
<!-- Avatar (desktop only, positioned via CSS) -->
|
|
11021
|
+
<div class="ds-tab-bar__actions">
|
|
11022
|
+
<ds-avatar
|
|
11023
|
+
[initials]="avatarInitials"
|
|
11024
|
+
[type]="avatarType"
|
|
11025
|
+
[src]="avatarSrc"
|
|
11026
|
+
[iconName]="avatarIconName"
|
|
11027
|
+
(click)="handleAvatarClick()"
|
|
11028
|
+
style="cursor: pointer;"
|
|
11029
|
+
/>
|
|
11030
|
+
</div>
|
|
11031
|
+
</ion-tab-bar>
|
|
11032
|
+
</ion-tabs>
|
|
11033
|
+
`, styles: [":host{display:block;height:100vh;height:100dvh}ion-tabs{height:100%;background:var(--color-brand-secondary)}.ds-tab-bar{--background: var(--color-background-neutral-primary);transition:transform .2s ease-in-out}ion-tab-bar[slot=bottom]{border-top:1px solid var(--border-color-default);padding-top:8px;padding-bottom:calc(var(--ion-safe-area-bottom, 34px) - 4px)}@media (max-width: 767px){ion-tab-bar[slot=bottom]{position:fixed;bottom:0;left:0;right:0;z-index:100}}@media (max-width: 767px){ion-tabs:has(ds-mobile-page-details) .ds-tab-bar{transform:translateY(100%);transition:transform .3s ease}}.ds-tab-bar__logo,.ds-tab-bar__actions{display:none}.ds-tab-bar__tabs{display:flex;width:100%;justify-content:space-around;align-items:center}@media (min-width: 769px){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)}}@media (display-mode: standalone){ion-tab-bar[slot=bottom]{padding-bottom:env(safe-area-inset-bottom,0px)!important}}@media (min-width: 768px){ion-tab-bar[slot=top]{--background: var(--color-brand-secondary);position:relative;display:flex;align-items:center;padding:12px 24px;height:64px;max-width:none}.ds-tab-bar__logo{display:flex;position:absolute;left:24px;align-items:center}.ds-tab-bar__actions{display:flex;position:absolute;right:24px;align-items:center;gap:12px}.ds-tab-bar__tabs{display:flex;gap:8px;align-items:center;max-width:640px;width:100%;margin:0 auto;justify-content:center;padding-left:var(--content-padding-md);padding-right:var(--content-padding-md)}.logomark{height:28px;width:auto;flex-shrink:0}}@media (min-width: 992px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-lg);padding-right:var(--content-padding-lg);justify-content:center}}@media (min-width: 1440px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-xl);padding-right:var(--content-padding-xl)}}@media (min-width: 1768px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-2xl);padding-right:var(--content-padding-2xl)}}@media (min-width: 1920px){.ds-tab-bar__tabs{max-width:640px;padding-left:var(--content-padding-3xl);padding-right:var(--content-padding-3xl)}}ion-tab-button{--color: var(--text-color-default-tertiary);--color-selected: var(--color-brand-base);display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:visible}.tab-icon-ripple{position:absolute;left:50%;top:50%;width:40px;height:40px;border-radius:50%;background:var(--color-brand-base);transform:translate(-50%,-50%) scale(0);opacity:0;pointer-events:none;transition:all .6s cubic-bezier(.36,1.2,.04,1.4);z-index:0}.tab-selected .tab-icon-ripple{transform:translate(-50%,-50%) scale(2);opacity:.05;animation:ripple-fade .6s cubic-bezier(.36,.5,.04,1.8) forwards}@keyframes ripple-fade{0%{opacity:0;transform:translate(-50%,-50%) scale(0)}30%{opacity:.1}to{opacity:0;transform:translate(-50%,-50%) scale(2)}}ion-tab-button::part(native){overflow:visible}ion-tab-button ion-ripple-effect{color:var(--color-brand-base);border-radius:1000px}ion-tab-button ion-label{font-size:var(--font-size-xs);font-weight:400;letter-spacing:-.3px;margin-top:0}.tab-icon-wrapper{position:relative;width:24px;height:24px;display:flex;align-items:center;justify-content:center;z-index:1;margin-bottom:4px}.tab-icon-inactive,.tab-icon-active{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);transition:all .8s cubic-bezier(.36,1,.04,1)}.tab-icon-inactive{opacity:1;transform:translate(-50%,-50%) scale(1)}.tab-icon-active{opacity:0;transform:translate(-50%,calc(-50% - 12px)) scale(.5)}.tab-selected .tab-icon-inactive{opacity:0;transform:translate(-50%,-50%) scale(.5)}.tab-selected .tab-icon-active{opacity:1;transform:translate(-50%,-50%) scale(1)}@media (min-width: 768px){.ds-tab-button{flex-direction:row;height:40px;padding:0 16px!important;border-radius:40px;transition:all .2s ease;width:-moz-fit-content;width:fit-content;min-width:auto;flex:0 0 auto;--color: rgba(255, 255, 255, .7);--color-selected: white;background:#ffffff1a;position:relative;overflow:hidden}.tab-icon-wrapper,.tab-icon-ripple{width:20px;height:20px}.ds-tab-button::part(native){border-radius:40px}.ds-tab-button:hover{--color: white;--color-selected: white}.ds-tab-button.tab-selected{background:var(--color-background-brand);--color-selected: white}.ds-tab-button .button-native{width:auto;padding:0}.ds-tab-button ion-label{font-size:var(--font-size-sm);font-weight:500;margin:0;color:inherit}.ds-tab-button .tab-icon-wrapper{margin-right:4px;margin-bottom:0}.ds-tab-button ion-ripple-effect{color:#ffffff4d;border-radius:1000px;transform:scale(1.5)}}@media (min-width: 768px){.ds-tab-bar__actions ds-avatar{cursor:pointer;transition:transform .2s ease}.ds-tab-bar__actions ds-avatar:hover{transform:scale(1.05)}}\n"] }]
|
|
11034
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { tabs: [{
|
|
11035
|
+
type: Input
|
|
11036
|
+
}], avatarType: [{
|
|
11037
|
+
type: Input
|
|
11038
|
+
}], avatarInitials: [{
|
|
11039
|
+
type: Input
|
|
11040
|
+
}], avatarSrc: [{
|
|
11041
|
+
type: Input
|
|
11042
|
+
}], avatarIconName: [{
|
|
11043
|
+
type: Input
|
|
11044
|
+
}], avatarClick: [{
|
|
11045
|
+
type: Output
|
|
11046
|
+
}] } });
|
|
11047
|
+
|
|
11048
|
+
class MobileTabsExampleComponent {
|
|
11049
|
+
userService;
|
|
11050
|
+
modalController;
|
|
11051
|
+
router;
|
|
11052
|
+
constructor(userService, modalController, router) {
|
|
11053
|
+
this.userService = userService;
|
|
11054
|
+
this.modalController = modalController;
|
|
11055
|
+
this.router = router;
|
|
11056
|
+
console.log('MobileTabsExampleComponent constructor');
|
|
11057
|
+
}
|
|
11058
|
+
ngOnInit() {
|
|
11059
|
+
console.log('MobileTabsExampleComponent ngOnInit');
|
|
11060
|
+
// Configure user avatar globally - this is now the single source of truth
|
|
11061
|
+
this.userService.setAvatarInitials('LM');
|
|
11062
|
+
this.userService.setAvatarType('initials');
|
|
11063
|
+
}
|
|
11064
|
+
tabs = [
|
|
11065
|
+
{
|
|
11066
|
+
id: 'home',
|
|
11067
|
+
label: 'Hjem',
|
|
11068
|
+
route: 'home',
|
|
11069
|
+
icon: 'remixHomeSmile2Line',
|
|
11070
|
+
iconActive: 'remixHomeSmile2Fill'
|
|
11071
|
+
},
|
|
11072
|
+
{
|
|
11073
|
+
id: 'inquiries',
|
|
11074
|
+
label: 'Henvendelser',
|
|
11075
|
+
route: 'inquiries',
|
|
11076
|
+
icon: 'remixFileList3Line',
|
|
11077
|
+
iconActive: 'remixFileList3Fill'
|
|
11078
|
+
},
|
|
11079
|
+
{
|
|
11080
|
+
id: 'announcements',
|
|
11081
|
+
label: 'Fællesskab',
|
|
11082
|
+
route: 'announcements',
|
|
11083
|
+
icon: 'remixCommunityLine',
|
|
11084
|
+
iconActive: 'remixCommunityFill'
|
|
11085
|
+
},
|
|
11086
|
+
{
|
|
11087
|
+
id: 'handbook',
|
|
11088
|
+
label: 'Håndbog',
|
|
11089
|
+
route: 'handbook',
|
|
11090
|
+
icon: 'remixBook2Line',
|
|
11091
|
+
iconActive: 'remixBook2Fill'
|
|
11092
|
+
}
|
|
11093
|
+
];
|
|
11094
|
+
async handleAvatarClick() {
|
|
11095
|
+
console.log('Avatar clicked - opening profile bottom sheet');
|
|
11096
|
+
const sheet = await this.modalController.create({
|
|
11097
|
+
component: DsMobileActionsBottomSheetComponent,
|
|
11098
|
+
componentProps: {
|
|
11099
|
+
customActionGroups: [
|
|
11100
|
+
{
|
|
11101
|
+
actions: [
|
|
11102
|
+
{
|
|
11103
|
+
action: 'profile',
|
|
11104
|
+
title: 'Min profil',
|
|
11105
|
+
icon: 'remixUser3Line',
|
|
11106
|
+
destructive: false
|
|
11107
|
+
},
|
|
11108
|
+
{
|
|
11109
|
+
action: 'settings',
|
|
11110
|
+
title: 'Indstillinger',
|
|
11111
|
+
icon: 'remixSettings3Line',
|
|
11112
|
+
destructive: false
|
|
11113
|
+
},
|
|
11114
|
+
{
|
|
11115
|
+
action: 'whitelabel-demo',
|
|
11116
|
+
title: 'Whitelabel Demo',
|
|
11117
|
+
icon: 'remixPaletteLine',
|
|
11118
|
+
destructive: false
|
|
11119
|
+
}
|
|
11120
|
+
]
|
|
11121
|
+
},
|
|
11122
|
+
{
|
|
11123
|
+
actions: [
|
|
11124
|
+
{
|
|
11125
|
+
action: 'logout',
|
|
11126
|
+
title: 'Log ud',
|
|
11127
|
+
icon: 'remixLogoutBoxLine',
|
|
11128
|
+
destructive: true
|
|
11129
|
+
}
|
|
11130
|
+
]
|
|
11131
|
+
}
|
|
11132
|
+
]
|
|
11133
|
+
},
|
|
11134
|
+
// Auto-height: no breakpoints, no handle
|
|
11135
|
+
cssClass: 'ds-bottom-sheet auto-height'
|
|
11136
|
+
});
|
|
11137
|
+
await sheet.present();
|
|
11138
|
+
const result = await sheet.onWillDismiss();
|
|
11139
|
+
if (result.data?.action) {
|
|
11140
|
+
console.log('Profile action selected:', result.data.action);
|
|
11141
|
+
switch (result.data.action) {
|
|
11142
|
+
case 'logout':
|
|
11143
|
+
console.log('Logging out...');
|
|
11144
|
+
// TODO: Implement logout logic
|
|
11145
|
+
break;
|
|
11146
|
+
case 'profile':
|
|
11147
|
+
console.log('Opening profile...');
|
|
11148
|
+
// TODO: Navigate to profile page
|
|
11149
|
+
break;
|
|
11150
|
+
case 'settings':
|
|
11151
|
+
console.log('Opening settings...');
|
|
11152
|
+
// TODO: Navigate to settings page
|
|
11153
|
+
break;
|
|
11154
|
+
case 'whitelabel-demo':
|
|
11155
|
+
console.log('Opening whitelabel demo...');
|
|
11156
|
+
this.router.navigate(['/whitelabel-demo']);
|
|
11157
|
+
break;
|
|
11158
|
+
}
|
|
11159
|
+
}
|
|
11160
|
+
}
|
|
11161
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileTabsExampleComponent, deps: [{ token: UserService }, { token: i1.ModalController }, { token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Component });
|
|
11162
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: MobileTabsExampleComponent, isStandalone: true, selector: "app-mobile-tabs-example", ngImport: i0, template: `
|
|
11163
|
+
<ds-mobile-tabs
|
|
11164
|
+
[tabs]="tabs"
|
|
11165
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
11166
|
+
(avatarClick)="handleAvatarClick()"
|
|
11167
|
+
/>
|
|
11168
|
+
`, isInline: true, styles: [":host{display:block;height:100vh;width:100vw;position:relative}\n"], dependencies: [{ kind: "component", type: DsMobileTabsComponent, selector: "ds-mobile-tabs", inputs: ["tabs", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName"], outputs: ["avatarClick"] }] });
|
|
11169
|
+
}
|
|
11170
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobileTabsExampleComponent, decorators: [{
|
|
11171
|
+
type: Component,
|
|
11172
|
+
args: [{ selector: 'app-mobile-tabs-example', standalone: true, imports: [DsMobileTabsComponent], template: `
|
|
11173
|
+
<ds-mobile-tabs
|
|
11174
|
+
[tabs]="tabs"
|
|
11175
|
+
[avatarInitials]="userService.avatarInitials()"
|
|
11176
|
+
(avatarClick)="handleAvatarClick()"
|
|
11177
|
+
/>
|
|
11178
|
+
`, styles: [":host{display:block;height:100vh;width:100vw;position:relative}\n"] }]
|
|
11179
|
+
}], ctorParameters: () => [{ type: UserService }, { type: i1.ModalController }, { type: i1$1.Router }] });
|
|
11180
|
+
|
|
11181
|
+
/**
|
|
11182
|
+
* PostCreatePageComponent
|
|
11183
|
+
*
|
|
11184
|
+
* Full-screen detail page for creating new posts in the community feed.
|
|
11185
|
+
* Features Threads-inspired interface with rich text editing capabilities.
|
|
11186
|
+
*/
|
|
11187
|
+
class PostCreatePageComponent {
|
|
11188
|
+
router;
|
|
11189
|
+
route;
|
|
11190
|
+
userService;
|
|
11191
|
+
textareaInput;
|
|
11192
|
+
postContent = '';
|
|
11193
|
+
username = signal('Lars Mikkelsen', ...(ngDevMode ? [{ debugName: "username" }] : []));
|
|
11194
|
+
placeholder = signal("What's new?", ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
11195
|
+
// Edit mode state
|
|
11196
|
+
isEditMode = signal(false, ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
|
|
11197
|
+
postId = signal(null, ...(ngDevMode ? [{ debugName: "postId" }] : []));
|
|
11198
|
+
pageTitle = signal('New post', ...(ngDevMode ? [{ debugName: "pageTitle" }] : []));
|
|
11199
|
+
submitButtonLabel = signal('Post', ...(ngDevMode ? [{ debugName: "submitButtonLabel" }] : []));
|
|
11200
|
+
constructor(router, route, userService) {
|
|
11201
|
+
this.router = router;
|
|
11202
|
+
this.route = route;
|
|
11203
|
+
this.userService = userService;
|
|
11204
|
+
}
|
|
11205
|
+
ngOnInit() {
|
|
11206
|
+
// Check for edit mode via query parameters
|
|
11207
|
+
this.route.queryParams.subscribe(params => {
|
|
11208
|
+
const editMode = params['edit'] === 'true';
|
|
11209
|
+
const postId = params['id'];
|
|
11210
|
+
const content = params['content'];
|
|
11211
|
+
if (editMode && postId) {
|
|
11212
|
+
this.isEditMode.set(true);
|
|
11213
|
+
this.postId.set(postId);
|
|
11214
|
+
this.pageTitle.set('Edit post');
|
|
11215
|
+
this.submitButtonLabel.set('Save');
|
|
11216
|
+
// Prefill content if provided
|
|
11217
|
+
if (content) {
|
|
11218
|
+
this.postContent = decodeURIComponent(content);
|
|
11219
|
+
}
|
|
11220
|
+
}
|
|
11221
|
+
else {
|
|
11222
|
+
// Reset to create mode
|
|
11223
|
+
this.isEditMode.set(false);
|
|
11224
|
+
this.postId.set(null);
|
|
11225
|
+
this.pageTitle.set('New post');
|
|
11226
|
+
this.submitButtonLabel.set('Post');
|
|
11227
|
+
this.postContent = '';
|
|
11228
|
+
}
|
|
11229
|
+
});
|
|
11230
|
+
}
|
|
11231
|
+
ngAfterViewInit() {
|
|
11232
|
+
// Focus the textarea after view initialization to trigger keyboard on mobile
|
|
11233
|
+
setTimeout(() => {
|
|
11234
|
+
this.textareaInput?.nativeElement.focus();
|
|
11235
|
+
}, 300);
|
|
11236
|
+
}
|
|
11237
|
+
handleInput() {
|
|
11238
|
+
// Handle text input changes
|
|
11239
|
+
}
|
|
11240
|
+
canPost() {
|
|
11241
|
+
return this.postContent.trim().length > 0;
|
|
11242
|
+
}
|
|
11243
|
+
handleCancel() {
|
|
11244
|
+
if (this.postContent.trim().length > 0) {
|
|
11245
|
+
// Show confirmation dialog
|
|
11246
|
+
const confirmed = confirm('Discard this post?');
|
|
11247
|
+
if (confirmed) {
|
|
11248
|
+
this.router.navigate(['/mobile-tabs-example/community']);
|
|
11249
|
+
}
|
|
11250
|
+
}
|
|
11251
|
+
else {
|
|
11252
|
+
this.router.navigate(['/mobile-tabs-example/community']);
|
|
11253
|
+
}
|
|
11254
|
+
}
|
|
11255
|
+
handlePost() {
|
|
11256
|
+
if (!this.canPost())
|
|
11257
|
+
return;
|
|
11258
|
+
if (this.isEditMode()) {
|
|
11259
|
+
console.log('Updating post:', this.postId(), this.postContent);
|
|
11260
|
+
// TODO: Implement post update logic
|
|
11261
|
+
// this.postService.updatePost(this.postId(), this.postContent).subscribe(() => {
|
|
11262
|
+
// this.router.navigate(['/mobile-tabs-example/community']);
|
|
11263
|
+
// });
|
|
11264
|
+
}
|
|
11265
|
+
else {
|
|
11266
|
+
console.log('Creating post:', this.postContent);
|
|
11267
|
+
// TODO: Implement post creation logic
|
|
11268
|
+
// this.postService.createPost(this.postContent).subscribe(() => {
|
|
11269
|
+
// this.router.navigate(['/mobile-tabs-example/community']);
|
|
11270
|
+
// });
|
|
11271
|
+
}
|
|
11272
|
+
// For now, just navigate back
|
|
11273
|
+
this.router.navigate(['/mobile-tabs-example/community']);
|
|
11274
|
+
}
|
|
11275
|
+
handleAddImage() {
|
|
11276
|
+
console.log('Add image');
|
|
11277
|
+
// TODO: Open image picker
|
|
11278
|
+
}
|
|
11279
|
+
handleAddEmoji() {
|
|
11280
|
+
console.log('Add emoji');
|
|
11281
|
+
// TODO: Open emoji picker
|
|
11282
|
+
}
|
|
11283
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PostCreatePageComponent, deps: [{ token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: UserService }], target: i0.ɵɵFactoryTarget.Component });
|
|
11284
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: PostCreatePageComponent, isStandalone: true, selector: "app-post-create-page", viewQueries: [{ propertyName: "textareaInput", first: true, predicate: ["textareaInput"], descendants: true }], ngImport: i0, template: `
|
|
11285
|
+
<ds-mobile-page-details
|
|
11286
|
+
[title]="pageTitle()"
|
|
11287
|
+
[backRoute]="'/mobile-tabs-example/announcements'"
|
|
11288
|
+
(back)="handleCancel()">
|
|
11289
|
+
|
|
11290
|
+
<div class="post-create-container">
|
|
11291
|
+
<div class="post-composer">
|
|
11292
|
+
<div class="post-composer__avatar">
|
|
11293
|
+
<ds-avatar
|
|
11294
|
+
[initials]="userService.avatarInitials()"
|
|
11295
|
+
[type]="userService.avatarType()"
|
|
11296
|
+
[src]="userService.avatarSrc()"
|
|
11297
|
+
size="md" />
|
|
11298
|
+
</div>
|
|
11299
|
+
|
|
11300
|
+
<div class="post-composer__main">
|
|
11301
|
+
<div class="post-composer__header">
|
|
11302
|
+
<span class="post-composer__username">{{ username() }}</span>
|
|
11303
|
+
</div>
|
|
11304
|
+
|
|
11305
|
+
<textarea
|
|
11306
|
+
#textareaInput
|
|
11307
|
+
class="post-composer__textarea"
|
|
11308
|
+
[(ngModel)]="postContent"
|
|
11309
|
+
[placeholder]="placeholder()"
|
|
11310
|
+
(input)="handleInput()">
|
|
11311
|
+
</textarea>
|
|
11312
|
+
|
|
11313
|
+
<div class="post-composer__actions">
|
|
11314
|
+
<div class="post-composer__action-btns">
|
|
11315
|
+
<button class="post-composer__action-btn" (click)="handleAddImage()">
|
|
11316
|
+
<ds-icon name="remixImageLine" size="22px" />
|
|
11317
|
+
</button>
|
|
11318
|
+
<button class="post-composer__action-btn" (click)="handleAddEmoji()">
|
|
11319
|
+
<ds-icon name="remixEmotionLine" size="22px" />
|
|
11320
|
+
</button>
|
|
11321
|
+
</div>
|
|
11322
|
+
|
|
11323
|
+
<ds-button
|
|
11324
|
+
variant="primary"
|
|
11325
|
+
size="md"
|
|
11326
|
+
[disabled]="!canPost()"
|
|
11327
|
+
(clicked)="handlePost()">
|
|
11328
|
+
{{ submitButtonLabel() }}
|
|
11329
|
+
</ds-button>
|
|
11330
|
+
</div>
|
|
11331
|
+
</div>
|
|
11332
|
+
</div>
|
|
11333
|
+
</div>
|
|
11334
|
+
</ds-mobile-page-details>
|
|
11335
|
+
`, isInline: true, styles: [".post-create-container{display:flex;flex-direction:column;height:100%;max-width:640px}.content{flex:1;overflow-y:auto;padding:16px}.post-composer{display:flex;gap:12px;margin-bottom:24px;align-items:flex-start}.post-composer__avatar{flex-shrink:0;padding-top:2px}.post-composer__main{flex:1;min-width:0;display:flex;flex-direction:column;gap:12px}.post-composer__header{display:flex;align-items:center;gap:8px;height:32px}.post-composer__username{font-family:Brockmann,sans-serif;font-size:15px;font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a)}.post-composer__textarea{width:100%;min-height:120px;border:none;outline:none;resize:none;font-family:Brockmann,sans-serif;font-size:15px;font-weight:400;line-height:22px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a);background:transparent;padding:0}.post-composer__textarea::placeholder{color:var(--color-text-tertiary, #999999)}.post-composer__actions{display:flex;align-items:center;justify-content:space-between;gap:16px}.post-composer__action-btns{display:flex;align-items:center;gap:16px}.post-composer__action-btn{background:none;border:none;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-text-secondary, #737373);transition:color .2s ease}.post-composer__action-btn:hover{color:var(--color-text-primary, #1a1a1a)}.thread-line{position:absolute;left:35px;top:60px;bottom:0;width:2px;background:var(--border-color-default)}@media (max-width: 768px){.content{padding:12px 16px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsButtonComponent, selector: "ds-button", inputs: ["variant", "size", "disabled", "loading", "pressed", "expanded", "leadingIcon", "trailingIcon", "ariaLabel", "iconOnly"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsMobilePageDetailsComponent, selector: "ds-mobile-page-details", inputs: ["title", "backRoute"], outputs: ["back"] }] });
|
|
11336
|
+
}
|
|
11337
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PostCreatePageComponent, decorators: [{
|
|
11338
|
+
type: Component,
|
|
11339
|
+
args: [{ selector: 'app-post-create-page', standalone: true, imports: [
|
|
11340
|
+
CommonModule,
|
|
11341
|
+
FormsModule,
|
|
11342
|
+
DsAvatarComponent,
|
|
11343
|
+
DsIconComponent,
|
|
11344
|
+
DsButtonComponent,
|
|
11345
|
+
DsMobilePageDetailsComponent
|
|
11346
|
+
], template: `
|
|
11347
|
+
<ds-mobile-page-details
|
|
11348
|
+
[title]="pageTitle()"
|
|
11349
|
+
[backRoute]="'/mobile-tabs-example/announcements'"
|
|
11350
|
+
(back)="handleCancel()">
|
|
11351
|
+
|
|
11352
|
+
<div class="post-create-container">
|
|
11353
|
+
<div class="post-composer">
|
|
11354
|
+
<div class="post-composer__avatar">
|
|
11355
|
+
<ds-avatar
|
|
11356
|
+
[initials]="userService.avatarInitials()"
|
|
11357
|
+
[type]="userService.avatarType()"
|
|
11358
|
+
[src]="userService.avatarSrc()"
|
|
11359
|
+
size="md" />
|
|
11360
|
+
</div>
|
|
11361
|
+
|
|
11362
|
+
<div class="post-composer__main">
|
|
11363
|
+
<div class="post-composer__header">
|
|
11364
|
+
<span class="post-composer__username">{{ username() }}</span>
|
|
11365
|
+
</div>
|
|
11366
|
+
|
|
11367
|
+
<textarea
|
|
11368
|
+
#textareaInput
|
|
11369
|
+
class="post-composer__textarea"
|
|
11370
|
+
[(ngModel)]="postContent"
|
|
11371
|
+
[placeholder]="placeholder()"
|
|
11372
|
+
(input)="handleInput()">
|
|
11373
|
+
</textarea>
|
|
11374
|
+
|
|
11375
|
+
<div class="post-composer__actions">
|
|
11376
|
+
<div class="post-composer__action-btns">
|
|
11377
|
+
<button class="post-composer__action-btn" (click)="handleAddImage()">
|
|
11378
|
+
<ds-icon name="remixImageLine" size="22px" />
|
|
11379
|
+
</button>
|
|
11380
|
+
<button class="post-composer__action-btn" (click)="handleAddEmoji()">
|
|
11381
|
+
<ds-icon name="remixEmotionLine" size="22px" />
|
|
11382
|
+
</button>
|
|
11383
|
+
</div>
|
|
11384
|
+
|
|
11385
|
+
<ds-button
|
|
11386
|
+
variant="primary"
|
|
11387
|
+
size="md"
|
|
11388
|
+
[disabled]="!canPost()"
|
|
11389
|
+
(clicked)="handlePost()">
|
|
11390
|
+
{{ submitButtonLabel() }}
|
|
11391
|
+
</ds-button>
|
|
11392
|
+
</div>
|
|
11393
|
+
</div>
|
|
11394
|
+
</div>
|
|
11395
|
+
</div>
|
|
11396
|
+
</ds-mobile-page-details>
|
|
11397
|
+
`, styles: [".post-create-container{display:flex;flex-direction:column;height:100%;max-width:640px}.content{flex:1;overflow-y:auto;padding:16px}.post-composer{display:flex;gap:12px;margin-bottom:24px;align-items:flex-start}.post-composer__avatar{flex-shrink:0;padding-top:2px}.post-composer__main{flex:1;min-width:0;display:flex;flex-direction:column;gap:12px}.post-composer__header{display:flex;align-items:center;gap:8px;height:32px}.post-composer__username{font-family:Brockmann,sans-serif;font-size:15px;font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a)}.post-composer__textarea{width:100%;min-height:120px;border:none;outline:none;resize:none;font-family:Brockmann,sans-serif;font-size:15px;font-weight:400;line-height:22px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a);background:transparent;padding:0}.post-composer__textarea::placeholder{color:var(--color-text-tertiary, #999999)}.post-composer__actions{display:flex;align-items:center;justify-content:space-between;gap:16px}.post-composer__action-btns{display:flex;align-items:center;gap:16px}.post-composer__action-btn{background:none;border:none;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-text-secondary, #737373);transition:color .2s ease}.post-composer__action-btn:hover{color:var(--color-text-primary, #1a1a1a)}.thread-line{position:absolute;left:35px;top:60px;bottom:0;width:2px;background:var(--border-color-default)}@media (max-width: 768px){.content{padding:12px 16px}}\n"] }]
|
|
11398
|
+
}], ctorParameters: () => [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: UserService }], propDecorators: { textareaInput: [{
|
|
11399
|
+
type: ViewChild,
|
|
11400
|
+
args: ['textareaInput']
|
|
11401
|
+
}] } });
|
|
11402
|
+
|
|
11403
|
+
class MobilePostDetailPageComponent {
|
|
11404
|
+
lightbox;
|
|
11405
|
+
bottomSheet;
|
|
11406
|
+
repliesCount = 6;
|
|
11407
|
+
constructor(lightbox, bottomSheet) {
|
|
11408
|
+
this.lightbox = lightbox;
|
|
11409
|
+
this.bottomSheet = bottomSheet;
|
|
11410
|
+
}
|
|
11411
|
+
/**
|
|
11412
|
+
* Open an image in the lightbox viewer
|
|
11413
|
+
*/
|
|
11414
|
+
openImageLightbox(imageSrc, title, description) {
|
|
11415
|
+
const authorMeta = {
|
|
11416
|
+
name: 'Sophie Andersen',
|
|
11417
|
+
role: 'Lejer',
|
|
11418
|
+
avatarInitials: 'SA',
|
|
11419
|
+
timestamp: '4t siden'
|
|
11420
|
+
};
|
|
11421
|
+
this.lightbox.open({
|
|
11422
|
+
images: [
|
|
11423
|
+
{
|
|
11424
|
+
type: 'image',
|
|
11425
|
+
src: imageSrc,
|
|
11426
|
+
alt: title,
|
|
11427
|
+
title: title,
|
|
11428
|
+
description: description,
|
|
11429
|
+
isLiked: true,
|
|
11430
|
+
likeCount: 156,
|
|
11431
|
+
commentCount: 34
|
|
11432
|
+
}
|
|
11433
|
+
],
|
|
11434
|
+
author: authorMeta,
|
|
11435
|
+
enableZoom: true,
|
|
11436
|
+
showControls: false, // Single image, no need for controls
|
|
11437
|
+
showInfo: true
|
|
11438
|
+
});
|
|
11439
|
+
}
|
|
11440
|
+
/**
|
|
11441
|
+
* Handle long press on a comment to show action sheet
|
|
11442
|
+
*/
|
|
11443
|
+
async handleCommentLongPress(authorName, content, isOwnComment) {
|
|
11444
|
+
const sheet = await this.bottomSheet.create({
|
|
11445
|
+
component: DsMobileActionsBottomSheetComponent,
|
|
11446
|
+
componentProps: {
|
|
11447
|
+
isOwnContent: isOwnComment
|
|
11448
|
+
},
|
|
11449
|
+
breakpoints: [0, 1],
|
|
11450
|
+
initialBreakpoint: 1,
|
|
11451
|
+
handle: true,
|
|
11452
|
+
backdropDismiss: true,
|
|
11453
|
+
cssClass: 'auto-height'
|
|
11454
|
+
});
|
|
11455
|
+
const result = await sheet.onWillDismiss();
|
|
11456
|
+
if (result.role === 'select' && result.data) {
|
|
11457
|
+
const action = result.data.action;
|
|
11458
|
+
switch (action) {
|
|
11459
|
+
case 'like':
|
|
11460
|
+
console.log('Like comment by', authorName);
|
|
11461
|
+
// Implement like logic
|
|
11462
|
+
break;
|
|
11463
|
+
case 'reply':
|
|
11464
|
+
console.log('Reply to comment by', authorName);
|
|
11465
|
+
// Implement reply logic
|
|
11466
|
+
break;
|
|
11467
|
+
case 'edit':
|
|
11468
|
+
console.log('Edit comment by', authorName);
|
|
11469
|
+
// Implement edit logic
|
|
11470
|
+
break;
|
|
11471
|
+
case 'delete':
|
|
11472
|
+
console.log('Delete comment by', authorName);
|
|
11473
|
+
// Implement delete logic (with confirmation)
|
|
11474
|
+
break;
|
|
11475
|
+
}
|
|
11476
|
+
}
|
|
11477
|
+
}
|
|
11478
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobilePostDetailPageComponent, deps: [{ token: DsMobileLightboxService }, { token: DsMobileBottomSheetService }], target: i0.ɵɵFactoryTarget.Component });
|
|
11479
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: MobilePostDetailPageComponent, isStandalone: true, selector: "app-mobile-post-detail-page", ngImport: i0, template: `
|
|
11480
|
+
<ds-mobile-page-details title="Opslag">
|
|
11481
|
+
<div class="post-detail-container">
|
|
11482
|
+
<!-- Post Section -->
|
|
11483
|
+
<div class="post-section">
|
|
11484
|
+
<ds-mobile-post-card
|
|
11485
|
+
[authorName]="'Sophie Andersen'"
|
|
11486
|
+
[authorRole]="'Lejer'"
|
|
11487
|
+
[timestamp]="'4t siden'"
|
|
11488
|
+
[avatarInitials]="'SA'"
|
|
11489
|
+
[variant]="'detail'">
|
|
11490
|
+
|
|
11491
|
+
<post-content class="no-indent">
|
|
11492
|
+
<post-text>Se denne smukke udsigt fra min altan! Morgenkaffe har aldrig smagt så godt ☕️</post-text>
|
|
11493
|
+
<post-media>
|
|
11494
|
+
<img
|
|
11495
|
+
src="/Assets/Dummy-photos/balcony-view.jpg"
|
|
11496
|
+
alt="Altanudsigt"
|
|
11497
|
+
class="clickable-image"
|
|
11498
|
+
(click)="openImageLightbox('/Assets/Dummy-photos/balcony-view.jpg', 'Altanudsigt', 'Morgenkaffe har aldrig smagt så godt ☕️')"
|
|
11499
|
+
/>
|
|
11500
|
+
</post-media>
|
|
11501
|
+
</post-content>
|
|
11502
|
+
|
|
11503
|
+
<post-actions class="no-indent">
|
|
11504
|
+
<action-like [active]="true" [count]="156" />
|
|
11505
|
+
<action-comment [count]="34" />
|
|
11506
|
+
</post-actions>
|
|
11507
|
+
</ds-mobile-post-card>
|
|
11508
|
+
</div>
|
|
11509
|
+
|
|
11510
|
+
<!-- Comments Section -->
|
|
11511
|
+
<div class="comments-section">
|
|
11512
|
+
<h2 class="comments-header">{{ repliesCount }} svar</h2>
|
|
11513
|
+
|
|
11514
|
+
<div class="comments-list">
|
|
11515
|
+
<ds-mobile-comment
|
|
11516
|
+
[authorName]="'Anders Jensen'"
|
|
11517
|
+
[authorRole]="'Lejer'"
|
|
11518
|
+
[timestamp]="'3t siden'"
|
|
11519
|
+
[avatarInitials]="'AJ'"
|
|
11520
|
+
[content]="'Wow, den udsigt er fantastisk! Hvilken etage er du på?'"
|
|
11521
|
+
[likeCount]="12"
|
|
11522
|
+
[clickable]="true"
|
|
11523
|
+
[isOwnComment]="false"
|
|
11524
|
+
(longPress)="handleCommentLongPress('Anders Jensen', 'Wow, den udsigt er fantastisk! Hvilken etage er du på?', false)" />
|
|
11525
|
+
|
|
11526
|
+
<ds-mobile-comment
|
|
11527
|
+
[authorName]="'Thomas Hansen'"
|
|
11528
|
+
[authorRole]="'Lejer'"
|
|
11529
|
+
[timestamp]="'3t siden'"
|
|
11530
|
+
[avatarInitials]="'TH'"
|
|
11531
|
+
[content]="'Smuk! Jeg kan også se byens silhuet fra min lejlighed 🌆'"
|
|
11532
|
+
[isLiked]="true"
|
|
11533
|
+
[likeCount]="8"
|
|
11534
|
+
[clickable]="true"
|
|
11535
|
+
[isOwnComment]="true"
|
|
11536
|
+
(longPress)="handleCommentLongPress('Thomas Hansen', 'Smuk! Jeg kan også se byens silhuet fra min lejlighed 🌆', true)" />
|
|
11537
|
+
|
|
11538
|
+
<ds-mobile-comment
|
|
11539
|
+
[authorName]="'Emma Petersen'"
|
|
11540
|
+
[authorRole]="'Lejer'"
|
|
11541
|
+
[timestamp]="'2t siden'"
|
|
11542
|
+
[avatarInitials]="'EP'"
|
|
11543
|
+
[content]="'Dette er præcis derfor jeg elsker at bo her. Godt billede!'"
|
|
11544
|
+
[likeCount]="15"
|
|
11545
|
+
[clickable]="true"
|
|
11546
|
+
[isOwnComment]="false"
|
|
11547
|
+
(longPress)="handleCommentLongPress('Emma Petersen', 'Dette er præcis derfor jeg elsker at bo her. Godt billede!', false)" />
|
|
11548
|
+
|
|
11549
|
+
<ds-mobile-comment
|
|
11550
|
+
[authorName]="'Nikolaj Sørensen'"
|
|
11551
|
+
[authorRole]="'Lejer'"
|
|
11552
|
+
[timestamp]="'2t siden'"
|
|
11553
|
+
[avatarInitials]="'NS'"
|
|
11554
|
+
[content]="'Solnedgangene fra den vinkel må være utrolige'"
|
|
11555
|
+
[likeCount]="6"
|
|
11556
|
+
[clickable]="true"
|
|
11557
|
+
[isOwnComment]="false"
|
|
11558
|
+
(longPress)="handleCommentLongPress('Nikolaj Sørensen', 'Solnedgangene fra den vinkel må være utrolige', false)" />
|
|
11559
|
+
|
|
11560
|
+
<ds-mobile-comment
|
|
11561
|
+
[authorName]="'Mette Larsen'"
|
|
11562
|
+
[authorRole]="'Lejer'"
|
|
11563
|
+
[timestamp]="'1t siden'"
|
|
11564
|
+
[avatarInitials]="'ML'"
|
|
11565
|
+
[content]="'Giver mig lyst til at få min morgenkaffe på altanen også! ☕'"
|
|
11566
|
+
[likeCount]="9"
|
|
11567
|
+
[clickable]="true"
|
|
11568
|
+
[isOwnComment]="false"
|
|
11569
|
+
(longPress)="handleCommentLongPress('Mette Larsen', 'Giver mig lyst til at få min morgenkaffe på altanen også! ☕', false)" />
|
|
11570
|
+
|
|
11571
|
+
<ds-mobile-comment
|
|
11572
|
+
[authorName]="'Frederik Nielsen'"
|
|
11573
|
+
[authorRole]="'Lejer'"
|
|
11574
|
+
[timestamp]="'1t siden'"
|
|
11575
|
+
[avatarInitials]="'FN'"
|
|
11576
|
+
[content]="'Heldig! Min altan vender den anden vej, men stadig pæn'"
|
|
11577
|
+
[likeCount]="4"
|
|
11578
|
+
[clickable]="true"
|
|
11579
|
+
[isOwnComment]="false"
|
|
11580
|
+
(longPress)="handleCommentLongPress('Frederik Nielsen', 'Heldig! Min altan vender den anden vej, men stadig pæn', false)" />
|
|
11581
|
+
|
|
11582
|
+
<ds-mobile-comment
|
|
11583
|
+
[authorName]="'Caroline Jensen'"
|
|
11584
|
+
[authorRole]="'Lejer'"
|
|
11585
|
+
[timestamp]="'45m siden'"
|
|
11586
|
+
[avatarInitials]="'CJ'"
|
|
11587
|
+
[content]="'Denne bygning har den bedste udsigt i byen, uden tvivl'"
|
|
11588
|
+
[likeCount]="11"
|
|
11589
|
+
[clickable]="true"
|
|
11590
|
+
[isOwnComment]="false"
|
|
11591
|
+
(longPress)="handleCommentLongPress('Caroline Jensen', 'Denne bygning har den bedste udsigt i byen, uden tvivl', false)" />
|
|
11592
|
+
|
|
11593
|
+
<ds-mobile-comment
|
|
11594
|
+
[authorName]="'Anna Hansen'"
|
|
11595
|
+
[authorRole]="'Lejer'"
|
|
11596
|
+
[timestamp]="'30m siden'"
|
|
11597
|
+
[avatarInitials]="'AH'"
|
|
11598
|
+
[content]="'Jeg skal se din altan en dag! 😍'"
|
|
11599
|
+
[clickable]="true"
|
|
11600
|
+
[isOwnComment]="false"
|
|
11601
|
+
(longPress)="handleCommentLongPress('Anna Hansen', 'Jeg skal se din altan en dag! 😍', false)" />
|
|
11602
|
+
</div>
|
|
11603
|
+
</div>
|
|
11604
|
+
</div>
|
|
11605
|
+
</ds-mobile-page-details>
|
|
11606
|
+
`, isInline: true, styles: [".post-detail-container{display:flex;flex-direction:column;gap:16px;max-width:640px}.post-section{border-bottom:1px solid var(--border-color-default);padding-bottom:16px}.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}.comments-section{display:flex;flex-direction:column;margin-left:-8px;margin-right:-8px}.comments-header{font-family:Brockmann,sans-serif;font-size:18px;font-weight:600;line-height:24px;color:var(--color-text-primary, #1a1a1a);margin-bottom:16px;padding-left:8px;padding-right:8px}.comments-list{display:flex;flex-direction:column}\n"], dependencies: [{ kind: "component", type: DsMobilePageDetailsComponent, selector: "ds-mobile-page-details", inputs: ["title", "backRoute"], outputs: ["back"] }, { kind: "component", type: DsMobilePostCardComponent, selector: "ds-mobile-post-card", inputs: ["authorName", "authorRole", "timestamp", "avatarInitials", "avatarType", "avatarSrc", "avatarIconName", "showBadge", "variant", "clickable"], outputs: ["postClick", "commentClick", "longPress"] }, { kind: "component", type: PostContentComponent$1, selector: "post-content" }, { kind: "component", type: PostTextComponent$1, selector: "post-text" }, { kind: "component", type: PostMediaComponent$1, selector: "post-media" }, { kind: "component", type: PostActionsComponent$1, selector: "post-actions" }, { kind: "component", type: ActionLikeComponent$1, selector: "action-like", inputs: ["active", "count"], outputs: ["activeChange", "countChange", "likeClick"] }, { kind: "component", type: ActionCommentComponent$1, selector: "action-comment", inputs: ["count"], outputs: ["commentClick"] }, { kind: "component", type: DsMobileCommentComponent, selector: "ds-mobile-comment", inputs: ["authorName", "authorRole", "timestamp", "content", "avatarInitials", "avatarType", "clickable", "isOwnComment", "isLiked", "likeCount"], outputs: ["isLikedChange", "likeCountChange", "commentClick", "replyClick", "editClick", "longPress"] }] });
|
|
11607
|
+
}
|
|
11608
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MobilePostDetailPageComponent, decorators: [{
|
|
11609
|
+
type: Component,
|
|
11610
|
+
args: [{ selector: 'app-mobile-post-detail-page', standalone: true, imports: [
|
|
11611
|
+
DsMobilePageDetailsComponent,
|
|
11612
|
+
DsMobilePostCardComponent,
|
|
11613
|
+
PostContentComponent$1,
|
|
11614
|
+
PostTextComponent$1,
|
|
11615
|
+
PostMediaComponent$1,
|
|
11616
|
+
PostActionsComponent$1,
|
|
11617
|
+
ActionLikeComponent$1,
|
|
11618
|
+
ActionCommentComponent$1,
|
|
11619
|
+
DsMobileCommentComponent
|
|
11620
|
+
], template: `
|
|
11621
|
+
<ds-mobile-page-details title="Opslag">
|
|
11622
|
+
<div class="post-detail-container">
|
|
11623
|
+
<!-- Post Section -->
|
|
11624
|
+
<div class="post-section">
|
|
11625
|
+
<ds-mobile-post-card
|
|
11626
|
+
[authorName]="'Sophie Andersen'"
|
|
11627
|
+
[authorRole]="'Lejer'"
|
|
11628
|
+
[timestamp]="'4t siden'"
|
|
11629
|
+
[avatarInitials]="'SA'"
|
|
11630
|
+
[variant]="'detail'">
|
|
11631
|
+
|
|
11632
|
+
<post-content class="no-indent">
|
|
11633
|
+
<post-text>Se denne smukke udsigt fra min altan! Morgenkaffe har aldrig smagt så godt ☕️</post-text>
|
|
11634
|
+
<post-media>
|
|
11635
|
+
<img
|
|
11636
|
+
src="/Assets/Dummy-photos/balcony-view.jpg"
|
|
11637
|
+
alt="Altanudsigt"
|
|
11638
|
+
class="clickable-image"
|
|
11639
|
+
(click)="openImageLightbox('/Assets/Dummy-photos/balcony-view.jpg', 'Altanudsigt', 'Morgenkaffe har aldrig smagt så godt ☕️')"
|
|
11640
|
+
/>
|
|
11641
|
+
</post-media>
|
|
11642
|
+
</post-content>
|
|
11643
|
+
|
|
11644
|
+
<post-actions class="no-indent">
|
|
11645
|
+
<action-like [active]="true" [count]="156" />
|
|
11646
|
+
<action-comment [count]="34" />
|
|
11647
|
+
</post-actions>
|
|
11648
|
+
</ds-mobile-post-card>
|
|
11649
|
+
</div>
|
|
11650
|
+
|
|
11651
|
+
<!-- Comments Section -->
|
|
11652
|
+
<div class="comments-section">
|
|
11653
|
+
<h2 class="comments-header">{{ repliesCount }} svar</h2>
|
|
11654
|
+
|
|
11655
|
+
<div class="comments-list">
|
|
11656
|
+
<ds-mobile-comment
|
|
11657
|
+
[authorName]="'Anders Jensen'"
|
|
11658
|
+
[authorRole]="'Lejer'"
|
|
11659
|
+
[timestamp]="'3t siden'"
|
|
11660
|
+
[avatarInitials]="'AJ'"
|
|
11661
|
+
[content]="'Wow, den udsigt er fantastisk! Hvilken etage er du på?'"
|
|
11662
|
+
[likeCount]="12"
|
|
11663
|
+
[clickable]="true"
|
|
11664
|
+
[isOwnComment]="false"
|
|
11665
|
+
(longPress)="handleCommentLongPress('Anders Jensen', 'Wow, den udsigt er fantastisk! Hvilken etage er du på?', false)" />
|
|
11666
|
+
|
|
11667
|
+
<ds-mobile-comment
|
|
11668
|
+
[authorName]="'Thomas Hansen'"
|
|
11669
|
+
[authorRole]="'Lejer'"
|
|
11670
|
+
[timestamp]="'3t siden'"
|
|
11671
|
+
[avatarInitials]="'TH'"
|
|
11672
|
+
[content]="'Smuk! Jeg kan også se byens silhuet fra min lejlighed 🌆'"
|
|
11673
|
+
[isLiked]="true"
|
|
11674
|
+
[likeCount]="8"
|
|
11675
|
+
[clickable]="true"
|
|
11676
|
+
[isOwnComment]="true"
|
|
11677
|
+
(longPress)="handleCommentLongPress('Thomas Hansen', 'Smuk! Jeg kan også se byens silhuet fra min lejlighed 🌆', true)" />
|
|
11678
|
+
|
|
11679
|
+
<ds-mobile-comment
|
|
11680
|
+
[authorName]="'Emma Petersen'"
|
|
11681
|
+
[authorRole]="'Lejer'"
|
|
11682
|
+
[timestamp]="'2t siden'"
|
|
11683
|
+
[avatarInitials]="'EP'"
|
|
11684
|
+
[content]="'Dette er præcis derfor jeg elsker at bo her. Godt billede!'"
|
|
11685
|
+
[likeCount]="15"
|
|
11686
|
+
[clickable]="true"
|
|
11687
|
+
[isOwnComment]="false"
|
|
11688
|
+
(longPress)="handleCommentLongPress('Emma Petersen', 'Dette er præcis derfor jeg elsker at bo her. Godt billede!', false)" />
|
|
11689
|
+
|
|
11690
|
+
<ds-mobile-comment
|
|
11691
|
+
[authorName]="'Nikolaj Sørensen'"
|
|
11692
|
+
[authorRole]="'Lejer'"
|
|
11693
|
+
[timestamp]="'2t siden'"
|
|
11694
|
+
[avatarInitials]="'NS'"
|
|
11695
|
+
[content]="'Solnedgangene fra den vinkel må være utrolige'"
|
|
11696
|
+
[likeCount]="6"
|
|
11697
|
+
[clickable]="true"
|
|
11698
|
+
[isOwnComment]="false"
|
|
11699
|
+
(longPress)="handleCommentLongPress('Nikolaj Sørensen', 'Solnedgangene fra den vinkel må være utrolige', false)" />
|
|
11700
|
+
|
|
11701
|
+
<ds-mobile-comment
|
|
11702
|
+
[authorName]="'Mette Larsen'"
|
|
11703
|
+
[authorRole]="'Lejer'"
|
|
11704
|
+
[timestamp]="'1t siden'"
|
|
11705
|
+
[avatarInitials]="'ML'"
|
|
11706
|
+
[content]="'Giver mig lyst til at få min morgenkaffe på altanen også! ☕'"
|
|
11707
|
+
[likeCount]="9"
|
|
11708
|
+
[clickable]="true"
|
|
11709
|
+
[isOwnComment]="false"
|
|
11710
|
+
(longPress)="handleCommentLongPress('Mette Larsen', 'Giver mig lyst til at få min morgenkaffe på altanen også! ☕', false)" />
|
|
11711
|
+
|
|
11712
|
+
<ds-mobile-comment
|
|
11713
|
+
[authorName]="'Frederik Nielsen'"
|
|
11714
|
+
[authorRole]="'Lejer'"
|
|
11715
|
+
[timestamp]="'1t siden'"
|
|
11716
|
+
[avatarInitials]="'FN'"
|
|
11717
|
+
[content]="'Heldig! Min altan vender den anden vej, men stadig pæn'"
|
|
11718
|
+
[likeCount]="4"
|
|
11719
|
+
[clickable]="true"
|
|
11720
|
+
[isOwnComment]="false"
|
|
11721
|
+
(longPress)="handleCommentLongPress('Frederik Nielsen', 'Heldig! Min altan vender den anden vej, men stadig pæn', false)" />
|
|
11722
|
+
|
|
11723
|
+
<ds-mobile-comment
|
|
11724
|
+
[authorName]="'Caroline Jensen'"
|
|
11725
|
+
[authorRole]="'Lejer'"
|
|
11726
|
+
[timestamp]="'45m siden'"
|
|
11727
|
+
[avatarInitials]="'CJ'"
|
|
11728
|
+
[content]="'Denne bygning har den bedste udsigt i byen, uden tvivl'"
|
|
11729
|
+
[likeCount]="11"
|
|
11730
|
+
[clickable]="true"
|
|
11731
|
+
[isOwnComment]="false"
|
|
11732
|
+
(longPress)="handleCommentLongPress('Caroline Jensen', 'Denne bygning har den bedste udsigt i byen, uden tvivl', false)" />
|
|
11733
|
+
|
|
11734
|
+
<ds-mobile-comment
|
|
11735
|
+
[authorName]="'Anna Hansen'"
|
|
11736
|
+
[authorRole]="'Lejer'"
|
|
11737
|
+
[timestamp]="'30m siden'"
|
|
11738
|
+
[avatarInitials]="'AH'"
|
|
11739
|
+
[content]="'Jeg skal se din altan en dag! 😍'"
|
|
11740
|
+
[clickable]="true"
|
|
11741
|
+
[isOwnComment]="false"
|
|
11742
|
+
(longPress)="handleCommentLongPress('Anna Hansen', 'Jeg skal se din altan en dag! 😍', false)" />
|
|
11743
|
+
</div>
|
|
11744
|
+
</div>
|
|
11745
|
+
</div>
|
|
11746
|
+
</ds-mobile-page-details>
|
|
11747
|
+
`, styles: [".post-detail-container{display:flex;flex-direction:column;gap:16px;max-width:640px}.post-section{border-bottom:1px solid var(--border-color-default);padding-bottom:16px}.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}.comments-section{display:flex;flex-direction:column;margin-left:-8px;margin-right:-8px}.comments-header{font-family:Brockmann,sans-serif;font-size:18px;font-weight:600;line-height:24px;color:var(--color-text-primary, #1a1a1a);margin-bottom:16px;padding-left:8px;padding-right:8px}.comments-list{display:flex;flex-direction:column}\n"] }]
|
|
11748
|
+
}], ctorParameters: () => [{ type: DsMobileLightboxService }, { type: DsMobileBottomSheetService }] });
|
|
11749
|
+
|
|
11750
|
+
const DEFAULT_CONFIG = {
|
|
11751
|
+
logoUrl: '/assets/logos/propbinder-logo.svg',
|
|
11752
|
+
logoMarkUrl: '/assets/logos/propbinder-logomark.svg',
|
|
11753
|
+
logoAlt: 'Propbinder',
|
|
11754
|
+
primaryColor: '#6B5FF5', // Propbinder brand purple (--color-background-brand)
|
|
11755
|
+
secondaryColor: '#221a4c', // Propbinder dark purple for headers (--color-brand-secondary)
|
|
11756
|
+
organizationName: 'Propbinder',
|
|
11757
|
+
organizationId: 'default'
|
|
11758
|
+
};
|
|
11759
|
+
/**
|
|
11760
|
+
* WhitelabelService
|
|
11761
|
+
*
|
|
11762
|
+
* Manages whitelabel configuration including logos and brand colors.
|
|
11763
|
+
* Automatically updates CSS custom properties when colors change.
|
|
11764
|
+
*
|
|
11765
|
+
* @example
|
|
11766
|
+
* Initialize with custom config:
|
|
11767
|
+
* ```typescript
|
|
11768
|
+
* whitelabelService.initialize({
|
|
11769
|
+
* logoUrl: '/assets/logos/acme-logo.svg',
|
|
11770
|
+
* logoMarkUrl: '/assets/logos/acme-mark.svg',
|
|
11771
|
+
* primaryColor: '#2563eb',
|
|
11772
|
+
* secondaryColor: '#3b82f6',
|
|
11773
|
+
* organizationName: 'Acme Corp'
|
|
11774
|
+
* });
|
|
11775
|
+
* ```
|
|
11776
|
+
*
|
|
11777
|
+
* Load from API:
|
|
11778
|
+
* ```typescript
|
|
11779
|
+
* await whitelabelService.loadFromApi('acme-corp');
|
|
11780
|
+
* ```
|
|
11781
|
+
*/
|
|
11782
|
+
class WhitelabelService {
|
|
11783
|
+
_config = signal(DEFAULT_CONFIG, ...(ngDevMode ? [{ debugName: "_config" }] : []));
|
|
11784
|
+
// Readonly getters for accessing config values
|
|
11785
|
+
logoUrl = () => this._config().logoUrl;
|
|
11786
|
+
logoMarkUrl = () => this._config().logoMarkUrl;
|
|
11787
|
+
logoAlt = () => this._config().logoAlt;
|
|
11788
|
+
primaryColor = () => this._config().primaryColor;
|
|
11789
|
+
secondaryColor = () => this._config().secondaryColor;
|
|
11790
|
+
organizationName = () => this._config().organizationName;
|
|
11791
|
+
organizationId = () => this._config().organizationId;
|
|
11792
|
+
// Full config accessor
|
|
11793
|
+
config = this._config.asReadonly();
|
|
11794
|
+
constructor() {
|
|
11795
|
+
// Apply default colors on initialization
|
|
11796
|
+
this.applyColors(DEFAULT_CONFIG.primaryColor, DEFAULT_CONFIG.secondaryColor);
|
|
11797
|
+
// Watch for config changes and update CSS custom properties
|
|
11798
|
+
effect(() => {
|
|
11799
|
+
const config = this._config();
|
|
11800
|
+
this.applyColors(config.primaryColor, config.secondaryColor);
|
|
11801
|
+
});
|
|
11802
|
+
}
|
|
11803
|
+
/**
|
|
11804
|
+
* Initialize whitelabel configuration
|
|
11805
|
+
* Call this early in app initialization (app.config.ts or app.component.ts)
|
|
11806
|
+
*/
|
|
11807
|
+
initialize(config) {
|
|
11808
|
+
this._config.update(current => ({
|
|
11809
|
+
...current,
|
|
11810
|
+
...config
|
|
11811
|
+
}));
|
|
11812
|
+
}
|
|
11813
|
+
/**
|
|
11814
|
+
* Load whitelabel config from API
|
|
11815
|
+
* Typically called on app startup based on subdomain, user tenant, etc.
|
|
11816
|
+
*
|
|
11817
|
+
* @param organizationId - The organization identifier (subdomain, tenant ID, etc.)
|
|
11818
|
+
*/
|
|
11819
|
+
async loadFromApi(organizationId) {
|
|
11820
|
+
try {
|
|
11821
|
+
// Example API call structure
|
|
11822
|
+
// const response = await fetch(`/api/whitelabel/${organizationId || 'default'}`);
|
|
11823
|
+
// const config = await response.json();
|
|
11824
|
+
// this.initialize(config);
|
|
11825
|
+
console.log('Loading whitelabel config from API for:', organizationId);
|
|
11826
|
+
// Example: Different configs for different organizations
|
|
11827
|
+
if (organizationId === 'demo-client') {
|
|
11828
|
+
this.initialize({
|
|
11829
|
+
logoUrl: '/assets/logos/demo-logo.svg',
|
|
11830
|
+
logoMarkUrl: '/assets/logos/demo-mark.svg',
|
|
11831
|
+
logoAlt: 'Demo Client',
|
|
11832
|
+
primaryColor: '#2563eb', // Blue
|
|
11833
|
+
secondaryColor: '#3b82f6', // Lighter blue
|
|
11834
|
+
organizationName: 'Demo Client',
|
|
11835
|
+
organizationId: 'demo-client'
|
|
11836
|
+
});
|
|
11837
|
+
}
|
|
11838
|
+
// Add more organization-specific configs as needed
|
|
11839
|
+
}
|
|
11840
|
+
catch (error) {
|
|
11841
|
+
console.error('Failed to load whitelabel config:', error);
|
|
11842
|
+
// Fallback to defaults already set
|
|
11843
|
+
}
|
|
11844
|
+
}
|
|
11845
|
+
/**
|
|
11846
|
+
* Update config dynamically (e.g., when user switches organizations)
|
|
11847
|
+
*/
|
|
11848
|
+
updateConfig(updates) {
|
|
11849
|
+
this.initialize(updates);
|
|
11850
|
+
}
|
|
11851
|
+
/**
|
|
11852
|
+
* Update only the brand colors
|
|
11853
|
+
*/
|
|
11854
|
+
updateColors(primaryColor, secondaryColor) {
|
|
11855
|
+
this._config.update(current => ({
|
|
11856
|
+
...current,
|
|
11857
|
+
primaryColor,
|
|
11858
|
+
secondaryColor
|
|
11859
|
+
}));
|
|
11860
|
+
}
|
|
11861
|
+
/**
|
|
11862
|
+
* Reset to default configuration
|
|
11863
|
+
*/
|
|
11864
|
+
resetToDefault() {
|
|
11865
|
+
this._config.set(DEFAULT_CONFIG);
|
|
11866
|
+
}
|
|
11867
|
+
/**
|
|
11868
|
+
* Apply colors to CSS custom properties
|
|
11869
|
+
* This updates the actual CSS variables used throughout the app
|
|
11870
|
+
*/
|
|
11871
|
+
applyColors(primaryColor, secondaryColor) {
|
|
11872
|
+
if (typeof document !== 'undefined') {
|
|
11873
|
+
const root = document.documentElement;
|
|
11874
|
+
root.style.setProperty('--color-background-brand', primaryColor);
|
|
11875
|
+
root.style.setProperty('--color-brand-secondary', secondaryColor);
|
|
11876
|
+
console.log('Applied whitelabel colors:', { primaryColor, secondaryColor });
|
|
11877
|
+
}
|
|
11878
|
+
}
|
|
11879
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11880
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelService, providedIn: 'root' });
|
|
11881
|
+
}
|
|
11882
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelService, decorators: [{
|
|
11883
|
+
type: Injectable,
|
|
11884
|
+
args: [{
|
|
11885
|
+
providedIn: 'root'
|
|
11886
|
+
}]
|
|
11887
|
+
}], ctorParameters: () => [] });
|
|
11888
|
+
|
|
11889
|
+
/**
|
|
11890
|
+
* DsLogoComponent
|
|
11891
|
+
*
|
|
11892
|
+
* Displays the whitelabeled logo or logomark based on current configuration.
|
|
11893
|
+
* Automatically pulls logo assets from WhitelabelService.
|
|
11894
|
+
*
|
|
11895
|
+
* @example
|
|
11896
|
+
* Full logo in header:
|
|
11897
|
+
* ```html
|
|
11898
|
+
* <ds-logo variant="full" size="md" />
|
|
11899
|
+
* ```
|
|
11900
|
+
*
|
|
11901
|
+
* Logomark for compact spaces:
|
|
11902
|
+
* ```html
|
|
11903
|
+
* <ds-logo variant="mark" size="sm" />
|
|
11904
|
+
* ```
|
|
11905
|
+
*/
|
|
11906
|
+
class DsLogoComponent {
|
|
11907
|
+
whitelabelService = inject(WhitelabelService);
|
|
11908
|
+
variant = 'full';
|
|
11909
|
+
size = 'md';
|
|
11910
|
+
customHeight;
|
|
11911
|
+
customWidth;
|
|
11912
|
+
logoSrc = computed(() => {
|
|
11913
|
+
return this.variant === 'full'
|
|
11914
|
+
? this.whitelabelService.logoUrl()
|
|
11915
|
+
: this.whitelabelService.logoMarkUrl();
|
|
11916
|
+
}, ...(ngDevMode ? [{ debugName: "logoSrc" }] : []));
|
|
11917
|
+
logoAlt = computed(() => {
|
|
11918
|
+
const alt = this.whitelabelService.logoAlt();
|
|
11919
|
+
return this.variant === 'full' ? alt : `${alt} logo`;
|
|
11920
|
+
}, ...(ngDevMode ? [{ debugName: "logoAlt" }] : []));
|
|
11921
|
+
logoClasses = computed(() => {
|
|
11922
|
+
return `logo logo--${this.variant} logo--${this.size}`;
|
|
11923
|
+
}, ...(ngDevMode ? [{ debugName: "logoClasses" }] : []));
|
|
11924
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsLogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11925
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: DsLogoComponent, isStandalone: true, selector: "ds-logo", inputs: { variant: "variant", size: "size", customHeight: "customHeight", customWidth: "customWidth" }, ngImport: i0, template: `
|
|
11926
|
+
<img
|
|
11927
|
+
[src]="logoSrc()"
|
|
11928
|
+
[alt]="logoAlt()"
|
|
11929
|
+
[class]="logoClasses()"
|
|
11930
|
+
[style.height.px]="customHeight"
|
|
11931
|
+
[style.width.px]="customWidth"
|
|
11932
|
+
/>
|
|
11933
|
+
`, isInline: true, styles: [":host{display:inline-block;line-height:0}.logo{display:block;object-fit:contain}.logo--full.logo--sm{height:24px;width:auto}.logo--full.logo--md{height:32px;width:auto}.logo--full.logo--lg{height:40px;width:auto}.logo--full.logo--xl{height:48px;width:auto}.logo--mark.logo--sm{height:20px;width:20px}.logo--mark.logo--md{height:28px;width:28px}.logo--mark.logo--lg{height:36px;width:36px}.logo--mark.logo--xl{height:44px;width:44px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
11934
|
+
}
|
|
11935
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsLogoComponent, decorators: [{
|
|
11936
|
+
type: Component,
|
|
11937
|
+
args: [{ selector: 'ds-logo', standalone: true, imports: [CommonModule], template: `
|
|
11938
|
+
<img
|
|
11939
|
+
[src]="logoSrc()"
|
|
11940
|
+
[alt]="logoAlt()"
|
|
11941
|
+
[class]="logoClasses()"
|
|
11942
|
+
[style.height.px]="customHeight"
|
|
11943
|
+
[style.width.px]="customWidth"
|
|
11944
|
+
/>
|
|
11945
|
+
`, styles: [":host{display:inline-block;line-height:0}.logo{display:block;object-fit:contain}.logo--full.logo--sm{height:24px;width:auto}.logo--full.logo--md{height:32px;width:auto}.logo--full.logo--lg{height:40px;width:auto}.logo--full.logo--xl{height:48px;width:auto}.logo--mark.logo--sm{height:20px;width:20px}.logo--mark.logo--md{height:28px;width:28px}.logo--mark.logo--lg{height:36px;width:36px}.logo--mark.logo--xl{height:44px;width:44px}\n"] }]
|
|
11946
|
+
}], propDecorators: { variant: [{
|
|
11947
|
+
type: Input
|
|
11948
|
+
}], size: [{
|
|
11949
|
+
type: Input
|
|
11950
|
+
}], customHeight: [{
|
|
11951
|
+
type: Input
|
|
11952
|
+
}], customWidth: [{
|
|
11953
|
+
type: Input
|
|
11954
|
+
}] } });
|
|
11955
|
+
|
|
11956
|
+
/**
|
|
11957
|
+
* DsAvatarWithBadgeComponent
|
|
11958
|
+
*
|
|
11959
|
+
* Displays an avatar with a logomark badge overlay.
|
|
11960
|
+
* Useful for showing user avatars with organization branding.
|
|
11961
|
+
*
|
|
11962
|
+
* @example
|
|
11963
|
+
* ```html
|
|
11964
|
+
* <ds-avatar-with-badge
|
|
11965
|
+
* [type]="'initials'"
|
|
11966
|
+
* [initials]="'JD'"
|
|
11967
|
+
* [size]="'lg'"
|
|
11968
|
+
* [badgePosition]="'bottom-right'"
|
|
11969
|
+
* />
|
|
11970
|
+
* ```
|
|
11971
|
+
*/
|
|
11972
|
+
class DsAvatarWithBadgeComponent {
|
|
11973
|
+
// Avatar props
|
|
11974
|
+
type = 'initials';
|
|
11975
|
+
size = 'md';
|
|
11976
|
+
initials = '';
|
|
11977
|
+
src = '';
|
|
11978
|
+
iconName = 'remixUser3Fill';
|
|
11979
|
+
// Badge props
|
|
11980
|
+
showBadge = true;
|
|
11981
|
+
badgePosition = 'bottom-right';
|
|
11982
|
+
badgeClasses = computed(() => {
|
|
11983
|
+
return `avatar-badge avatar-badge--${this.badgePosition} avatar-badge--${this.size}`;
|
|
11984
|
+
}, ...(ngDevMode ? [{ debugName: "badgeClasses" }] : []));
|
|
11985
|
+
// Calculate badge logo size based on avatar size
|
|
11986
|
+
badgeLogoSize = computed(() => {
|
|
11987
|
+
const sizeMap = {
|
|
11988
|
+
xs: 10,
|
|
11989
|
+
sm: 14,
|
|
11990
|
+
md: 16,
|
|
11991
|
+
lg: 22,
|
|
11992
|
+
xl: 28
|
|
11993
|
+
};
|
|
11994
|
+
return sizeMap[this.size];
|
|
11995
|
+
}, ...(ngDevMode ? [{ debugName: "badgeLogoSize" }] : []));
|
|
11996
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsAvatarWithBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11997
|
+
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: `
|
|
11998
|
+
<div class="avatar-badge-container">
|
|
11999
|
+
<ds-avatar
|
|
12000
|
+
[type]="type"
|
|
12001
|
+
[size]="size"
|
|
12002
|
+
[initials]="initials"
|
|
12003
|
+
[src]="src"
|
|
12004
|
+
[iconName]="iconName"
|
|
12005
|
+
/>
|
|
12006
|
+
|
|
12007
|
+
@if (showBadge) {
|
|
12008
|
+
<div [class]="badgeClasses()">
|
|
12009
|
+
<ds-logo
|
|
12010
|
+
variant="mark"
|
|
12011
|
+
[customHeight]="badgeLogoSize()"
|
|
12012
|
+
[customWidth]="badgeLogoSize()"
|
|
12013
|
+
/>
|
|
12014
|
+
</div>
|
|
12015
|
+
}
|
|
12016
|
+
</div>
|
|
12017
|
+
`, isInline: true, styles: [":host{display:inline-block;position:relative}.avatar-badge-container{position:relative;display:inline-block}.avatar-badge{position:absolute;background:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 4px #0000001a}.avatar-badge--bottom-right{bottom:0;right:0}.avatar-badge--bottom-left{bottom:0;left:0}.avatar-badge--top-right{top:0;right:0}.avatar-badge--top-left{top:0;left:0}.avatar-badge--xs{width:16px;height:16px;padding:3px}.avatar-badge--sm{width:20px;height:20px;padding:3px}.avatar-badge--md{width:24px;height:24px;padding:4px}.avatar-badge--lg{width:32px;height:32px;padding:5px}.avatar-badge--xl{width:40px;height:40px;padding:6px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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"] }] });
|
|
12018
|
+
}
|
|
12019
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DsAvatarWithBadgeComponent, decorators: [{
|
|
12020
|
+
type: Component,
|
|
12021
|
+
args: [{ selector: 'ds-avatar-with-badge', standalone: true, imports: [CommonModule, DsAvatarComponent, DsLogoComponent], encapsulation: ViewEncapsulation.Emulated, template: `
|
|
12022
|
+
<div class="avatar-badge-container">
|
|
12023
|
+
<ds-avatar
|
|
12024
|
+
[type]="type"
|
|
12025
|
+
[size]="size"
|
|
12026
|
+
[initials]="initials"
|
|
12027
|
+
[src]="src"
|
|
12028
|
+
[iconName]="iconName"
|
|
12029
|
+
/>
|
|
12030
|
+
|
|
12031
|
+
@if (showBadge) {
|
|
12032
|
+
<div [class]="badgeClasses()">
|
|
12033
|
+
<ds-logo
|
|
12034
|
+
variant="mark"
|
|
12035
|
+
[customHeight]="badgeLogoSize()"
|
|
12036
|
+
[customWidth]="badgeLogoSize()"
|
|
12037
|
+
/>
|
|
12038
|
+
</div>
|
|
12039
|
+
}
|
|
12040
|
+
</div>
|
|
12041
|
+
`, styles: [":host{display:inline-block;position:relative}.avatar-badge-container{position:relative;display:inline-block}.avatar-badge{position:absolute;background:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 4px #0000001a}.avatar-badge--bottom-right{bottom:0;right:0}.avatar-badge--bottom-left{bottom:0;left:0}.avatar-badge--top-right{top:0;right:0}.avatar-badge--top-left{top:0;left:0}.avatar-badge--xs{width:16px;height:16px;padding:3px}.avatar-badge--sm{width:20px;height:20px;padding:3px}.avatar-badge--md{width:24px;height:24px;padding:4px}.avatar-badge--lg{width:32px;height:32px;padding:5px}.avatar-badge--xl{width:40px;height:40px;padding:6px}\n"] }]
|
|
12042
|
+
}], propDecorators: { type: [{
|
|
12043
|
+
type: Input
|
|
12044
|
+
}], size: [{
|
|
12045
|
+
type: Input
|
|
12046
|
+
}], initials: [{
|
|
12047
|
+
type: Input
|
|
12048
|
+
}], src: [{
|
|
12049
|
+
type: Input
|
|
12050
|
+
}], iconName: [{
|
|
12051
|
+
type: Input
|
|
12052
|
+
}], showBadge: [{
|
|
12053
|
+
type: Input
|
|
12054
|
+
}], badgePosition: [{
|
|
12055
|
+
type: Input
|
|
12056
|
+
}] } });
|
|
12057
|
+
|
|
12058
|
+
/**
|
|
12059
|
+
* Whitelabel Demo Page
|
|
12060
|
+
*
|
|
12061
|
+
* Demonstrates the whitelabeling system with live color and logo switching.
|
|
12062
|
+
*/
|
|
12063
|
+
class WhitelabelDemoPage {
|
|
12064
|
+
whitelabelService = inject(WhitelabelService);
|
|
12065
|
+
// Custom color inputs
|
|
12066
|
+
customPrimaryColor = '#6B5FF5';
|
|
12067
|
+
customSecondaryColor = '#221a4c';
|
|
12068
|
+
// Logo upload state
|
|
12069
|
+
uploadedFullLogoName = '';
|
|
12070
|
+
uploadedLogomarkName = '';
|
|
12071
|
+
ngOnInit() {
|
|
12072
|
+
console.log('Whitelabel Demo Page initialized');
|
|
12073
|
+
// Initialize custom colors with current values
|
|
12074
|
+
this.customPrimaryColor = this.whitelabelService.primaryColor();
|
|
12075
|
+
this.customSecondaryColor = this.whitelabelService.secondaryColor();
|
|
12076
|
+
}
|
|
12077
|
+
handleFullLogoUpload(event) {
|
|
12078
|
+
const input = event.target;
|
|
12079
|
+
if (input.files && input.files[0]) {
|
|
12080
|
+
const file = input.files[0];
|
|
12081
|
+
this.uploadedFullLogoName = file.name;
|
|
12082
|
+
// Convert to data URL
|
|
12083
|
+
const reader = new FileReader();
|
|
12084
|
+
reader.onload = (e) => {
|
|
12085
|
+
const dataUrl = e.target?.result;
|
|
12086
|
+
this.whitelabelService.updateConfig({
|
|
12087
|
+
logoUrl: dataUrl
|
|
12088
|
+
});
|
|
12089
|
+
};
|
|
12090
|
+
reader.readAsDataURL(file);
|
|
12091
|
+
}
|
|
12092
|
+
}
|
|
12093
|
+
handleLogomarkUpload(event) {
|
|
12094
|
+
const input = event.target;
|
|
12095
|
+
if (input.files && input.files[0]) {
|
|
12096
|
+
const file = input.files[0];
|
|
12097
|
+
this.uploadedLogomarkName = file.name;
|
|
12098
|
+
// Convert to data URL
|
|
12099
|
+
const reader = new FileReader();
|
|
12100
|
+
reader.onload = (e) => {
|
|
12101
|
+
const dataUrl = e.target?.result;
|
|
12102
|
+
this.whitelabelService.updateConfig({
|
|
12103
|
+
logoMarkUrl: dataUrl
|
|
12104
|
+
});
|
|
12105
|
+
};
|
|
12106
|
+
reader.readAsDataURL(file);
|
|
12107
|
+
}
|
|
12108
|
+
}
|
|
12109
|
+
resetFullLogo() {
|
|
12110
|
+
this.uploadedFullLogoName = '';
|
|
12111
|
+
this.whitelabelService.updateConfig({
|
|
12112
|
+
logoUrl: '/assets/logos/propbinder-logo.svg'
|
|
12113
|
+
});
|
|
12114
|
+
}
|
|
12115
|
+
resetLogomark() {
|
|
12116
|
+
this.uploadedLogomarkName = '';
|
|
12117
|
+
this.whitelabelService.updateConfig({
|
|
12118
|
+
logoMarkUrl: '/assets/logos/propbinder-logomark.svg'
|
|
12119
|
+
});
|
|
12120
|
+
}
|
|
12121
|
+
configJson() {
|
|
12122
|
+
return JSON.stringify(this.whitelabelService.config(), null, 2);
|
|
12123
|
+
}
|
|
12124
|
+
applyDefaultTheme() {
|
|
12125
|
+
this.whitelabelService.updateConfig({
|
|
12126
|
+
primaryColor: '#6B5FF5',
|
|
12127
|
+
secondaryColor: '#221a4c',
|
|
12128
|
+
organizationName: 'Propbinder',
|
|
12129
|
+
organizationId: 'default'
|
|
12130
|
+
});
|
|
12131
|
+
this.updateCustomColorInputs();
|
|
12132
|
+
}
|
|
12133
|
+
applyBlueTheme() {
|
|
12134
|
+
this.whitelabelService.updateConfig({
|
|
12135
|
+
primaryColor: '#2563eb',
|
|
12136
|
+
secondaryColor: '#3b82f6',
|
|
12137
|
+
organizationName: 'Blue Corp',
|
|
12138
|
+
organizationId: 'blue-corp'
|
|
12139
|
+
});
|
|
12140
|
+
this.updateCustomColorInputs();
|
|
12141
|
+
}
|
|
12142
|
+
applyGreenTheme() {
|
|
12143
|
+
this.whitelabelService.updateConfig({
|
|
12144
|
+
primaryColor: '#16a34a',
|
|
12145
|
+
secondaryColor: '#22c55e',
|
|
12146
|
+
organizationName: 'Green Industries',
|
|
12147
|
+
organizationId: 'green-industries'
|
|
12148
|
+
});
|
|
12149
|
+
this.updateCustomColorInputs();
|
|
12150
|
+
}
|
|
12151
|
+
applyOrangeTheme() {
|
|
12152
|
+
this.whitelabelService.updateConfig({
|
|
12153
|
+
primaryColor: '#ea580c',
|
|
12154
|
+
secondaryColor: '#f97316',
|
|
12155
|
+
organizationName: 'Orange Solutions',
|
|
12156
|
+
organizationId: 'orange-solutions'
|
|
12157
|
+
});
|
|
12158
|
+
this.updateCustomColorInputs();
|
|
12159
|
+
}
|
|
12160
|
+
applyCustomColors() {
|
|
12161
|
+
this.whitelabelService.updateColors(this.customPrimaryColor, this.customSecondaryColor);
|
|
12162
|
+
}
|
|
12163
|
+
updateCustomColorInputs() {
|
|
12164
|
+
this.customPrimaryColor = this.whitelabelService.primaryColor();
|
|
12165
|
+
this.customSecondaryColor = this.whitelabelService.secondaryColor();
|
|
12166
|
+
}
|
|
12167
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12168
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: WhitelabelDemoPage, isStandalone: true, selector: "app-whitelabel-demo", ngImport: i0, template: `
|
|
12169
|
+
<ion-header>
|
|
12170
|
+
<ion-toolbar>
|
|
12171
|
+
<ion-title>Whitelabel Demo</ion-title>
|
|
12172
|
+
</ion-toolbar>
|
|
12173
|
+
</ion-header>
|
|
12174
|
+
|
|
12175
|
+
<ion-content>
|
|
12176
|
+
<div class="demo-container">
|
|
12177
|
+
<!-- Logo Section -->
|
|
12178
|
+
<div class="demo-section">
|
|
12179
|
+
<h2>Logos</h2>
|
|
12180
|
+
<div class="logo-showcase">
|
|
12181
|
+
<div>
|
|
12182
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Full Logo (md)</p>
|
|
12183
|
+
<ds-logo variant="full" size="md" />
|
|
12184
|
+
</div>
|
|
12185
|
+
<div>
|
|
12186
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Logomark (sm)</p>
|
|
12187
|
+
<ds-logo variant="mark" size="sm" />
|
|
12188
|
+
</div>
|
|
12189
|
+
<div>
|
|
12190
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Logomark (md)</p>
|
|
12191
|
+
<ds-logo variant="mark" size="md" />
|
|
12192
|
+
</div>
|
|
12193
|
+
<div>
|
|
12194
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Logomark (lg)</p>
|
|
12195
|
+
<ds-logo variant="mark" size="lg" />
|
|
12196
|
+
</div>
|
|
12197
|
+
</div>
|
|
12198
|
+
|
|
12199
|
+
<!-- Logo Upload Section -->
|
|
12200
|
+
<div class="logo-upload">
|
|
12201
|
+
<div class="upload-section">
|
|
12202
|
+
<h3>Upload Full Logo</h3>
|
|
12203
|
+
<div class="file-input-wrapper">
|
|
12204
|
+
<input
|
|
12205
|
+
#fullLogoInput
|
|
12206
|
+
type="file"
|
|
12207
|
+
accept="image/*"
|
|
12208
|
+
(change)="handleFullLogoUpload($event)"
|
|
12209
|
+
/>
|
|
12210
|
+
<button class="upload-button" (click)="fullLogoInput.click()">
|
|
12211
|
+
Choose File
|
|
12212
|
+
</button>
|
|
12213
|
+
@if (uploadedFullLogoName) {
|
|
12214
|
+
<span class="file-name">{{ uploadedFullLogoName }}</span>
|
|
12215
|
+
}
|
|
12216
|
+
@if (uploadedFullLogoName) {
|
|
12217
|
+
<button class="reset-button" (click)="resetFullLogo()">Reset</button>
|
|
12218
|
+
}
|
|
12219
|
+
</div>
|
|
12220
|
+
</div>
|
|
12221
|
+
|
|
12222
|
+
<div class="upload-section">
|
|
12223
|
+
<h3>Upload Logomark</h3>
|
|
12224
|
+
<div class="file-input-wrapper">
|
|
12225
|
+
<input
|
|
12226
|
+
#logomarkInput
|
|
12227
|
+
type="file"
|
|
12228
|
+
accept="image/*"
|
|
12229
|
+
(change)="handleLogomarkUpload($event)"
|
|
12230
|
+
/>
|
|
12231
|
+
<button class="upload-button" (click)="logomarkInput.click()">
|
|
12232
|
+
Choose File
|
|
12233
|
+
</button>
|
|
12234
|
+
@if (uploadedLogomarkName) {
|
|
12235
|
+
<span class="file-name">{{ uploadedLogomarkName }}</span>
|
|
12236
|
+
}
|
|
12237
|
+
@if (uploadedLogomarkName) {
|
|
12238
|
+
<button class="reset-button" (click)="resetLogomark()">Reset</button>
|
|
12239
|
+
}
|
|
12240
|
+
</div>
|
|
12241
|
+
</div>
|
|
12242
|
+
|
|
12243
|
+
<p style="font-size: 12px; color: #999; margin-top: 12px;">
|
|
12244
|
+
Tip: Use SVG or PNG files with transparent backgrounds for best results
|
|
12245
|
+
</p>
|
|
12246
|
+
</div>
|
|
12247
|
+
</div>
|
|
12248
|
+
|
|
12249
|
+
<!-- Avatar with Badge Section -->
|
|
12250
|
+
<div class="demo-section">
|
|
12251
|
+
<h2>Avatar with Logo Badge</h2>
|
|
12252
|
+
<div class="avatar-showcase">
|
|
12253
|
+
<div>
|
|
12254
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Small</p>
|
|
12255
|
+
<ds-avatar-with-badge
|
|
12256
|
+
[type]="'initials'"
|
|
12257
|
+
[initials]="'JD'"
|
|
12258
|
+
[size]="'sm'"
|
|
12259
|
+
[badgePosition]="'bottom-right'"
|
|
12260
|
+
/>
|
|
12261
|
+
</div>
|
|
12262
|
+
<div>
|
|
12263
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Medium</p>
|
|
12264
|
+
<ds-avatar-with-badge
|
|
12265
|
+
[type]="'initials'"
|
|
12266
|
+
[initials]="'JD'"
|
|
12267
|
+
[size]="'md'"
|
|
12268
|
+
[badgePosition]="'bottom-right'"
|
|
12269
|
+
/>
|
|
12270
|
+
</div>
|
|
12271
|
+
<div>
|
|
12272
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Large</p>
|
|
12273
|
+
<ds-avatar-with-badge
|
|
12274
|
+
[type]="'initials'"
|
|
12275
|
+
[initials]="'JD'"
|
|
12276
|
+
[size]="'lg'"
|
|
12277
|
+
[badgePosition]="'bottom-right'"
|
|
12278
|
+
/>
|
|
12279
|
+
</div>
|
|
12280
|
+
<div>
|
|
12281
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">X-Large</p>
|
|
12282
|
+
<ds-avatar-with-badge
|
|
12283
|
+
[type]="'initials'"
|
|
12284
|
+
[initials]="'JD'"
|
|
12285
|
+
[size]="'xl'"
|
|
12286
|
+
[badgePosition]="'bottom-right'"
|
|
12287
|
+
/>
|
|
12288
|
+
</div>
|
|
12289
|
+
</div>
|
|
12290
|
+
</div>
|
|
12291
|
+
|
|
12292
|
+
<!-- Color Section -->
|
|
12293
|
+
<div class="demo-section">
|
|
12294
|
+
<h2>Brand Colors</h2>
|
|
12295
|
+
<div class="color-demo">
|
|
12296
|
+
<p style="margin-bottom: 8px; color: #666;">Current brand colors:</p>
|
|
12297
|
+
<div class="color-swatch">
|
|
12298
|
+
<div class="swatch swatch--primary">
|
|
12299
|
+
Primary<br/>
|
|
12300
|
+
<span style="font-size: 11px; opacity: 0.9;">{{ whitelabelService.primaryColor() }}</span>
|
|
12301
|
+
</div>
|
|
12302
|
+
<div class="swatch swatch--secondary">
|
|
12303
|
+
Secondary<br/>
|
|
12304
|
+
<span style="font-size: 11px; opacity: 0.9;">{{ whitelabelService.secondaryColor() }}</span>
|
|
12305
|
+
</div>
|
|
12306
|
+
</div>
|
|
12307
|
+
|
|
12308
|
+
<!-- Custom Color Inputs -->
|
|
12309
|
+
<div class="color-inputs">
|
|
12310
|
+
<div class="color-input-row">
|
|
12311
|
+
<label>Primary:</label>
|
|
12312
|
+
<input
|
|
12313
|
+
type="color"
|
|
12314
|
+
[(ngModel)]="customPrimaryColor"
|
|
12315
|
+
(change)="applyCustomColors()"
|
|
12316
|
+
/>
|
|
12317
|
+
<input
|
|
12318
|
+
type="text"
|
|
12319
|
+
[(ngModel)]="customPrimaryColor"
|
|
12320
|
+
(change)="applyCustomColors()"
|
|
12321
|
+
placeholder="#6B5FF5"
|
|
12322
|
+
/>
|
|
12323
|
+
</div>
|
|
12324
|
+
<div class="color-input-row">
|
|
12325
|
+
<label>Secondary:</label>
|
|
12326
|
+
<input
|
|
12327
|
+
type="color"
|
|
12328
|
+
[(ngModel)]="customSecondaryColor"
|
|
12329
|
+
(change)="applyCustomColors()"
|
|
12330
|
+
/>
|
|
12331
|
+
<input
|
|
12332
|
+
type="text"
|
|
12333
|
+
[(ngModel)]="customSecondaryColor"
|
|
12334
|
+
(change)="applyCustomColors()"
|
|
12335
|
+
placeholder="#221a4c"
|
|
12336
|
+
/>
|
|
12337
|
+
</div>
|
|
12338
|
+
</div>
|
|
12339
|
+
</div>
|
|
12340
|
+
</div>
|
|
12341
|
+
|
|
12342
|
+
<!-- Theme Switcher -->
|
|
12343
|
+
<div class="demo-section">
|
|
12344
|
+
<h2>Switch Organization Theme</h2>
|
|
12345
|
+
<div class="button-group">
|
|
12346
|
+
<ion-button (click)="applyDefaultTheme()">
|
|
12347
|
+
Default (Purple)
|
|
12348
|
+
</ion-button>
|
|
12349
|
+
<ion-button (click)="applyBlueTheme()">
|
|
12350
|
+
Blue Theme
|
|
12351
|
+
</ion-button>
|
|
12352
|
+
<ion-button (click)="applyGreenTheme()">
|
|
12353
|
+
Green Theme
|
|
12354
|
+
</ion-button>
|
|
12355
|
+
<ion-button (click)="applyOrangeTheme()">
|
|
12356
|
+
Orange Theme
|
|
12357
|
+
</ion-button>
|
|
12358
|
+
</div>
|
|
12359
|
+
</div>
|
|
12360
|
+
|
|
12361
|
+
<!-- Current Config -->
|
|
12362
|
+
<div class="demo-section">
|
|
12363
|
+
<h2>Current Configuration</h2>
|
|
12364
|
+
<div class="current-config">
|
|
12365
|
+
<pre>{{ configJson() }}</pre>
|
|
12366
|
+
</div>
|
|
12367
|
+
</div>
|
|
12368
|
+
</div>
|
|
12369
|
+
</ion-content>
|
|
12370
|
+
`, isInline: true, styles: [":host{display:block}ion-toolbar{--background: var(--color-brand-secondary);--color: white}ion-content{--background: #f5f5f5}.demo-container{padding:20px;max-width:800px;margin:0 auto}.demo-section{margin-bottom:32px}.demo-section h2{margin-bottom:16px;font-size:20px;font-weight:600}.logo-showcase{display:flex;gap:24px;align-items:center;padding:24px;background:#fff;border-radius:8px}.avatar-showcase{display:flex;gap:16px;align-items:center;padding:24px;background:#fff;border-radius:8px;flex-wrap:wrap}.button-group{display:flex;gap:12px;flex-wrap:wrap}.color-demo{padding:24px;background:#fff;border-radius:8px}.color-swatch{display:flex;gap:16px;margin-top:16px}.swatch{flex:1;min-height:100px;border-radius:8px;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:600}.swatch--primary{background:var(--color-background-brand)}.swatch--secondary{background:var(--color-brand-secondary)}.current-config{padding:16px;background:#f5f5f5;border-radius:8px;margin-top:16px}.current-config pre{margin:0;font-size:12px;overflow-x:auto}.color-inputs{display:flex;flex-direction:column;gap:16px;margin-top:16px}.color-input-row{display:flex;align-items:center;gap:12px}.color-input-row label{min-width:100px;font-weight:600;font-size:14px}.color-input-row input[type=color]{width:50px;height:40px;border:none;border-radius:8px;cursor:pointer}.color-input-row input[type=text]{flex:1;padding:8px 12px;border:1px solid #ddd;border-radius:8px;font-family:monospace;font-size:14px}.logo-upload{margin-top:24px;padding:20px;background:#fff;border-radius:8px}.upload-section{margin-bottom:20px}.upload-section h3{font-size:16px;font-weight:600;margin-bottom:12px}.file-input-wrapper{display:flex;align-items:center;gap:12px}.file-input-wrapper input[type=file]{display:none}.upload-button{padding:10px 16px;background:var(--color-background-brand);color:#fff;border:none;border-radius:8px;cursor:pointer;font-weight:600;font-size:14px}.upload-button:hover{opacity:.9}.file-name{font-size:14px;color:#666}.reset-button{padding:8px 12px;background:#f5f5f5;color:#666;border:1px solid #ddd;border-radius:8px;cursor:pointer;font-size:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.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: 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: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { 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"] }] });
|
|
12371
|
+
}
|
|
12372
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: WhitelabelDemoPage, decorators: [{
|
|
12373
|
+
type: Component,
|
|
12374
|
+
args: [{ selector: 'app-whitelabel-demo', standalone: true, imports: [
|
|
12375
|
+
CommonModule,
|
|
12376
|
+
FormsModule,
|
|
12377
|
+
IonContent,
|
|
12378
|
+
IonHeader,
|
|
12379
|
+
IonToolbar,
|
|
12380
|
+
IonTitle,
|
|
12381
|
+
IonButton,
|
|
12382
|
+
DsLogoComponent,
|
|
12383
|
+
DsAvatarWithBadgeComponent
|
|
12384
|
+
], template: `
|
|
12385
|
+
<ion-header>
|
|
12386
|
+
<ion-toolbar>
|
|
12387
|
+
<ion-title>Whitelabel Demo</ion-title>
|
|
12388
|
+
</ion-toolbar>
|
|
12389
|
+
</ion-header>
|
|
12390
|
+
|
|
12391
|
+
<ion-content>
|
|
12392
|
+
<div class="demo-container">
|
|
12393
|
+
<!-- Logo Section -->
|
|
12394
|
+
<div class="demo-section">
|
|
12395
|
+
<h2>Logos</h2>
|
|
12396
|
+
<div class="logo-showcase">
|
|
12397
|
+
<div>
|
|
12398
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Full Logo (md)</p>
|
|
12399
|
+
<ds-logo variant="full" size="md" />
|
|
12400
|
+
</div>
|
|
12401
|
+
<div>
|
|
12402
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Logomark (sm)</p>
|
|
12403
|
+
<ds-logo variant="mark" size="sm" />
|
|
12404
|
+
</div>
|
|
12405
|
+
<div>
|
|
12406
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Logomark (md)</p>
|
|
12407
|
+
<ds-logo variant="mark" size="md" />
|
|
12408
|
+
</div>
|
|
12409
|
+
<div>
|
|
12410
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Logomark (lg)</p>
|
|
12411
|
+
<ds-logo variant="mark" size="lg" />
|
|
12412
|
+
</div>
|
|
12413
|
+
</div>
|
|
12414
|
+
|
|
12415
|
+
<!-- Logo Upload Section -->
|
|
12416
|
+
<div class="logo-upload">
|
|
12417
|
+
<div class="upload-section">
|
|
12418
|
+
<h3>Upload Full Logo</h3>
|
|
12419
|
+
<div class="file-input-wrapper">
|
|
12420
|
+
<input
|
|
12421
|
+
#fullLogoInput
|
|
12422
|
+
type="file"
|
|
12423
|
+
accept="image/*"
|
|
12424
|
+
(change)="handleFullLogoUpload($event)"
|
|
12425
|
+
/>
|
|
12426
|
+
<button class="upload-button" (click)="fullLogoInput.click()">
|
|
12427
|
+
Choose File
|
|
12428
|
+
</button>
|
|
12429
|
+
@if (uploadedFullLogoName) {
|
|
12430
|
+
<span class="file-name">{{ uploadedFullLogoName }}</span>
|
|
12431
|
+
}
|
|
12432
|
+
@if (uploadedFullLogoName) {
|
|
12433
|
+
<button class="reset-button" (click)="resetFullLogo()">Reset</button>
|
|
12434
|
+
}
|
|
12435
|
+
</div>
|
|
12436
|
+
</div>
|
|
12437
|
+
|
|
12438
|
+
<div class="upload-section">
|
|
12439
|
+
<h3>Upload Logomark</h3>
|
|
12440
|
+
<div class="file-input-wrapper">
|
|
12441
|
+
<input
|
|
12442
|
+
#logomarkInput
|
|
12443
|
+
type="file"
|
|
12444
|
+
accept="image/*"
|
|
12445
|
+
(change)="handleLogomarkUpload($event)"
|
|
12446
|
+
/>
|
|
12447
|
+
<button class="upload-button" (click)="logomarkInput.click()">
|
|
12448
|
+
Choose File
|
|
12449
|
+
</button>
|
|
12450
|
+
@if (uploadedLogomarkName) {
|
|
12451
|
+
<span class="file-name">{{ uploadedLogomarkName }}</span>
|
|
12452
|
+
}
|
|
12453
|
+
@if (uploadedLogomarkName) {
|
|
12454
|
+
<button class="reset-button" (click)="resetLogomark()">Reset</button>
|
|
12455
|
+
}
|
|
12456
|
+
</div>
|
|
12457
|
+
</div>
|
|
12458
|
+
|
|
12459
|
+
<p style="font-size: 12px; color: #999; margin-top: 12px;">
|
|
12460
|
+
Tip: Use SVG or PNG files with transparent backgrounds for best results
|
|
12461
|
+
</p>
|
|
12462
|
+
</div>
|
|
12463
|
+
</div>
|
|
12464
|
+
|
|
12465
|
+
<!-- Avatar with Badge Section -->
|
|
12466
|
+
<div class="demo-section">
|
|
12467
|
+
<h2>Avatar with Logo Badge</h2>
|
|
12468
|
+
<div class="avatar-showcase">
|
|
12469
|
+
<div>
|
|
12470
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Small</p>
|
|
12471
|
+
<ds-avatar-with-badge
|
|
12472
|
+
[type]="'initials'"
|
|
12473
|
+
[initials]="'JD'"
|
|
12474
|
+
[size]="'sm'"
|
|
12475
|
+
[badgePosition]="'bottom-right'"
|
|
12476
|
+
/>
|
|
12477
|
+
</div>
|
|
12478
|
+
<div>
|
|
12479
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Medium</p>
|
|
12480
|
+
<ds-avatar-with-badge
|
|
12481
|
+
[type]="'initials'"
|
|
12482
|
+
[initials]="'JD'"
|
|
12483
|
+
[size]="'md'"
|
|
12484
|
+
[badgePosition]="'bottom-right'"
|
|
12485
|
+
/>
|
|
12486
|
+
</div>
|
|
12487
|
+
<div>
|
|
12488
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">Large</p>
|
|
12489
|
+
<ds-avatar-with-badge
|
|
12490
|
+
[type]="'initials'"
|
|
12491
|
+
[initials]="'JD'"
|
|
12492
|
+
[size]="'lg'"
|
|
12493
|
+
[badgePosition]="'bottom-right'"
|
|
12494
|
+
/>
|
|
12495
|
+
</div>
|
|
12496
|
+
<div>
|
|
12497
|
+
<p style="margin-bottom: 8px; font-size: 12px; color: #666;">X-Large</p>
|
|
12498
|
+
<ds-avatar-with-badge
|
|
12499
|
+
[type]="'initials'"
|
|
12500
|
+
[initials]="'JD'"
|
|
12501
|
+
[size]="'xl'"
|
|
12502
|
+
[badgePosition]="'bottom-right'"
|
|
12503
|
+
/>
|
|
12504
|
+
</div>
|
|
12505
|
+
</div>
|
|
12506
|
+
</div>
|
|
12507
|
+
|
|
12508
|
+
<!-- Color Section -->
|
|
12509
|
+
<div class="demo-section">
|
|
12510
|
+
<h2>Brand Colors</h2>
|
|
12511
|
+
<div class="color-demo">
|
|
12512
|
+
<p style="margin-bottom: 8px; color: #666;">Current brand colors:</p>
|
|
12513
|
+
<div class="color-swatch">
|
|
12514
|
+
<div class="swatch swatch--primary">
|
|
12515
|
+
Primary<br/>
|
|
12516
|
+
<span style="font-size: 11px; opacity: 0.9;">{{ whitelabelService.primaryColor() }}</span>
|
|
12517
|
+
</div>
|
|
12518
|
+
<div class="swatch swatch--secondary">
|
|
12519
|
+
Secondary<br/>
|
|
12520
|
+
<span style="font-size: 11px; opacity: 0.9;">{{ whitelabelService.secondaryColor() }}</span>
|
|
12521
|
+
</div>
|
|
12522
|
+
</div>
|
|
12523
|
+
|
|
12524
|
+
<!-- Custom Color Inputs -->
|
|
12525
|
+
<div class="color-inputs">
|
|
12526
|
+
<div class="color-input-row">
|
|
12527
|
+
<label>Primary:</label>
|
|
12528
|
+
<input
|
|
12529
|
+
type="color"
|
|
12530
|
+
[(ngModel)]="customPrimaryColor"
|
|
12531
|
+
(change)="applyCustomColors()"
|
|
12532
|
+
/>
|
|
12533
|
+
<input
|
|
12534
|
+
type="text"
|
|
12535
|
+
[(ngModel)]="customPrimaryColor"
|
|
12536
|
+
(change)="applyCustomColors()"
|
|
12537
|
+
placeholder="#6B5FF5"
|
|
12538
|
+
/>
|
|
12539
|
+
</div>
|
|
12540
|
+
<div class="color-input-row">
|
|
12541
|
+
<label>Secondary:</label>
|
|
12542
|
+
<input
|
|
12543
|
+
type="color"
|
|
12544
|
+
[(ngModel)]="customSecondaryColor"
|
|
12545
|
+
(change)="applyCustomColors()"
|
|
12546
|
+
/>
|
|
12547
|
+
<input
|
|
12548
|
+
type="text"
|
|
12549
|
+
[(ngModel)]="customSecondaryColor"
|
|
12550
|
+
(change)="applyCustomColors()"
|
|
12551
|
+
placeholder="#221a4c"
|
|
12552
|
+
/>
|
|
12553
|
+
</div>
|
|
12554
|
+
</div>
|
|
12555
|
+
</div>
|
|
12556
|
+
</div>
|
|
12557
|
+
|
|
12558
|
+
<!-- Theme Switcher -->
|
|
12559
|
+
<div class="demo-section">
|
|
12560
|
+
<h2>Switch Organization Theme</h2>
|
|
12561
|
+
<div class="button-group">
|
|
12562
|
+
<ion-button (click)="applyDefaultTheme()">
|
|
12563
|
+
Default (Purple)
|
|
12564
|
+
</ion-button>
|
|
12565
|
+
<ion-button (click)="applyBlueTheme()">
|
|
12566
|
+
Blue Theme
|
|
12567
|
+
</ion-button>
|
|
12568
|
+
<ion-button (click)="applyGreenTheme()">
|
|
12569
|
+
Green Theme
|
|
12570
|
+
</ion-button>
|
|
12571
|
+
<ion-button (click)="applyOrangeTheme()">
|
|
12572
|
+
Orange Theme
|
|
12573
|
+
</ion-button>
|
|
12574
|
+
</div>
|
|
12575
|
+
</div>
|
|
12576
|
+
|
|
12577
|
+
<!-- Current Config -->
|
|
12578
|
+
<div class="demo-section">
|
|
12579
|
+
<h2>Current Configuration</h2>
|
|
12580
|
+
<div class="current-config">
|
|
12581
|
+
<pre>{{ configJson() }}</pre>
|
|
12582
|
+
</div>
|
|
12583
|
+
</div>
|
|
12584
|
+
</div>
|
|
12585
|
+
</ion-content>
|
|
12586
|
+
`, styles: [":host{display:block}ion-toolbar{--background: var(--color-brand-secondary);--color: white}ion-content{--background: #f5f5f5}.demo-container{padding:20px;max-width:800px;margin:0 auto}.demo-section{margin-bottom:32px}.demo-section h2{margin-bottom:16px;font-size:20px;font-weight:600}.logo-showcase{display:flex;gap:24px;align-items:center;padding:24px;background:#fff;border-radius:8px}.avatar-showcase{display:flex;gap:16px;align-items:center;padding:24px;background:#fff;border-radius:8px;flex-wrap:wrap}.button-group{display:flex;gap:12px;flex-wrap:wrap}.color-demo{padding:24px;background:#fff;border-radius:8px}.color-swatch{display:flex;gap:16px;margin-top:16px}.swatch{flex:1;min-height:100px;border-radius:8px;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:600}.swatch--primary{background:var(--color-background-brand)}.swatch--secondary{background:var(--color-brand-secondary)}.current-config{padding:16px;background:#f5f5f5;border-radius:8px;margin-top:16px}.current-config pre{margin:0;font-size:12px;overflow-x:auto}.color-inputs{display:flex;flex-direction:column;gap:16px;margin-top:16px}.color-input-row{display:flex;align-items:center;gap:12px}.color-input-row label{min-width:100px;font-weight:600;font-size:14px}.color-input-row input[type=color]{width:50px;height:40px;border:none;border-radius:8px;cursor:pointer}.color-input-row input[type=text]{flex:1;padding:8px 12px;border:1px solid #ddd;border-radius:8px;font-family:monospace;font-size:14px}.logo-upload{margin-top:24px;padding:20px;background:#fff;border-radius:8px}.upload-section{margin-bottom:20px}.upload-section h3{font-size:16px;font-weight:600;margin-bottom:12px}.file-input-wrapper{display:flex;align-items:center;gap:12px}.file-input-wrapper input[type=file]{display:none}.upload-button{padding:10px 16px;background:var(--color-background-brand);color:#fff;border:none;border-radius:8px;cursor:pointer;font-weight:600;font-size:14px}.upload-button:hover{opacity:.9}.file-name{font-size:14px;color:#666}.reset-button{padding:8px 12px;background:#f5f5f5;color:#666;border:1px solid #ddd;border-radius:8px;cursor:pointer;font-size:14px}\n"] }]
|
|
12587
|
+
}] });
|
|
12588
|
+
|
|
8287
12589
|
/* Auto-generated. Do not edit. */
|
|
8288
12590
|
|
|
8289
12591
|
/**
|
|
8290
12592
|
* Generated bundle index. Do not edit.
|
|
8291
12593
|
*/
|
|
8292
12594
|
|
|
8293
|
-
export { ActionCommentComponent$1 as ActionCommentComponent, ActionLikeComponent$1 as ActionLikeComponent, ContentRowComponent, DsMobileActionsBottomSheetComponent, DsMobileAppLayoutComponent, DsMobileBottomSheetService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileContentSectionComponent, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileInlinePhotoComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileLongPressDirective, DsMobileModalService, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostCardComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobileTabsComponent, MobilePageBase, PostActionsComponent$1 as PostActionsComponent, PostAttachmentsComponent$1 as PostAttachmentsComponent, PostContentComponent$1 as PostContentComponent, PostMediaComponent$1 as PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent$1 as PostTextComponent, SectionHeaderComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent };
|
|
12595
|
+
export { ActionCommentComponent$1 as ActionCommentComponent, ActionLikeComponent$1 as ActionLikeComponent, ContentRowComponent, DsMobileActionsBottomSheetComponent, DsMobileAppLayoutComponent, DsMobileBottomSheetService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileContentSectionComponent, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileInlinePhotoComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileLongPressDirective, DsMobileModalService, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostCardComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobileTabsComponent$1 as DsMobileTabsComponent, MobileCommunityPageComponent, MobileHandbookPageComponent, MobileHomePageComponent, MobileInquiriesPageComponent, MobileInquiryDetailPageComponent, MobilePageBase, MobilePostDetailPageComponent, MobileTabsExampleComponent, PostActionsComponent$1 as PostActionsComponent, PostAttachmentsComponent$1 as PostAttachmentsComponent, PostContentComponent$1 as PostContentComponent, PostCreatePageComponent, PostMediaComponent$1 as PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent$1 as PostTextComponent, SectionHeaderComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent, UserService, WhitelabelDemoPage, customBackTransition, customPageTransition };
|
|
8294
12596
|
//# sourceMappingURL=propbinder-mobile-design.mjs.map
|