@propbinder/mobile-design 0.2.48 → 0.2.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ng-package.json +24 -0
- package/package.json +3 -39
- package/src/animations/page-transitions.ts +165 -0
- package/src/assets/fonts/brockmann-mediumitalic-webfont.woff2 +0 -0
- package/src/assets/fonts/brockmann-regularitalic-webfont.woff2 +0 -0
- package/src/assets/fonts/brockmann-semibolditalic-webfont.woff2 +0 -0
- package/src/components/action-list-item/ds-mobile-action-list-item.ts +102 -0
- package/src/components/action-list-item/index.ts +2 -0
- package/src/components/app-icon/ds-app-icon.ts +133 -0
- package/src/components/app-icon/index.ts +2 -0
- package/src/components/attachment-preview/ds-mobile-attachment-preview.css +139 -0
- package/src/components/attachment-preview/ds-mobile-attachment-preview.ts +164 -0
- package/src/components/attachment-preview/index.ts +1 -0
- package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +142 -0
- package/src/components/avatar-with-badge/index.ts +2 -0
- package/src/components/booking-modal/ds-mobile-booking-confirmation-wrapper.ts +71 -0
- package/src/components/booking-modal/ds-mobile-booking-modal.service.ts +121 -0
- package/src/components/booking-modal/ds-mobile-booking-modal.ts +598 -0
- package/src/components/booking-modal/ds-mobile-booking-summary.ts +161 -0
- package/src/components/booking-modal/index.ts +4 -0
- package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +266 -0
- package/src/components/bottom-sheet/ds-mobile-bottom-sheet-header.ts +146 -0
- package/src/components/bottom-sheet/ds-mobile-bottom-sheet-wrapper.ts +156 -0
- package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +101 -0
- package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +169 -0
- package/src/components/bottom-sheet/ds-mobile-confirmation-sheet.ts +211 -0
- package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +578 -0
- package/src/components/bottom-sheet/ds-mobile-profile-actions-sheet.ts +614 -0
- package/src/components/bottom-sheet/index.ts +8 -0
- package/src/components/bottom-sheet/modal-shadow-fix.ts +42 -0
- package/src/components/card-inline/ds-mobile-card-inline.ts +301 -0
- package/src/components/card-inline/index.ts +2 -0
- package/src/components/card-inline-banner/ds-mobile-card-inline-banner.ts +118 -0
- package/src/components/card-inline-banner/index.ts +1 -0
- package/src/components/card-inline-contact/ds-mobile-card-inline-contact.ts +120 -0
- package/src/components/card-inline-contact/index.ts +1 -0
- package/src/components/card-inline-file/ds-mobile-card-inline-file.ts +141 -0
- package/src/components/card-inline-file/index.ts +1 -0
- package/src/components/chat-modal/ds-mobile-chat-modal.css +159 -0
- package/src/components/chat-modal/ds-mobile-chat-modal.service.ts +105 -0
- package/src/components/chat-modal/ds-mobile-chat-modal.ts +918 -0
- package/src/components/chat-modal/index.ts +8 -0
- package/src/components/comment/ds-mobile-comment.ts +568 -0
- package/src/components/comment/index.ts +2 -0
- package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +182 -0
- package/src/components/contact-list-item/index.ts +2 -0
- package/src/components/content/ds-mobile-content.ts +139 -0
- package/src/components/content/index.ts +2 -0
- package/src/components/dropdown/ds-mobile-dropdown.css +199 -0
- package/src/components/dropdown/ds-mobile-dropdown.ts +340 -0
- package/src/components/dropdown/index.ts +2 -0
- package/src/components/ds-mobile-tabs.css +407 -0
- package/src/components/ds-mobile-tabs.ts +216 -0
- package/src/components/empty-state/ds-mobile-empty-state.ts +120 -0
- package/src/components/empty-state/index.ts +2 -0
- package/src/components/fab/ds-mobile-fab.ts +315 -0
- package/src/components/fab/index.ts +1 -0
- package/src/components/facility-creation-modal/ds-mobile-facility-creation-confirmation-wrapper.ts +121 -0
- package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.css +189 -0
- package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.service.ts +135 -0
- package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.ts +656 -0
- package/src/components/facility-creation-modal/index.ts +9 -0
- package/src/components/facility-creation-modal/sheets/ds-mobile-access-sheet.ts +105 -0
- package/src/components/facility-creation-modal/sheets/ds-mobile-price-sheet.ts +188 -0
- package/src/components/facility-creation-modal/sheets/ds-mobile-when-can-book-sheet.ts +460 -0
- package/src/components/facility-creation-modal/sheets/ds-mobile-who-can-book-sheet.ts +134 -0
- package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.service.ts +69 -0
- package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.ts +379 -0
- package/src/components/facility-detail-modal/index.ts +2 -0
- package/src/components/file-attachment/ds-mobile-file-attachment.ts +164 -0
- package/src/components/file-attachment/index.ts +2 -0
- package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.css +214 -0
- package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +84 -0
- package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +424 -0
- package/src/components/handbook-detail-modal/index.ts +3 -0
- package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +175 -0
- package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +533 -0
- package/src/components/handbook-folder/index.ts +4 -0
- package/src/components/header-content/ds-mobile-header-content.ts +222 -0
- package/src/components/header-content/index.ts +2 -0
- package/src/components/illustration/ds-mobile-illustration.ts +124 -0
- package/src/components/illustration/index.ts +2 -0
- package/src/components/index.ts +124 -0
- package/src/components/inline-photo/ds-mobile-inline-photo.ts +361 -0
- package/src/components/inline-photo/index.ts +1 -0
- package/src/components/inline-tabs/ds-mobile-inline-tabs.ts +132 -0
- package/src/components/inline-tabs/index.ts +2 -0
- package/src/components/interactive-list-item-booking/ds-mobile-interactive-list-item-booking.ts +350 -0
- package/src/components/interactive-list-item-booking/index.ts +1 -0
- package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +321 -0
- package/src/components/interactive-list-item-inquiry/index.ts +2 -0
- package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +237 -0
- package/src/components/interactive-list-item-message/index.ts +2 -0
- package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +549 -0
- package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +124 -0
- package/src/components/interactive-list-item-post/index.ts +13 -0
- package/src/components/lightbox/ds-mobile-lightbox-footer.ts +315 -0
- package/src/components/lightbox/ds-mobile-lightbox-header.ts +202 -0
- package/src/components/lightbox/ds-mobile-lightbox-image.ts +484 -0
- package/src/components/lightbox/ds-mobile-lightbox-pdf.css +377 -0
- package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +374 -0
- package/src/components/lightbox/ds-mobile-lightbox.css +587 -0
- package/src/components/lightbox/ds-mobile-lightbox.service.ts +296 -0
- package/src/components/lightbox/ds-mobile-lightbox.ts +529 -0
- package/src/components/lightbox/index.ts +22 -0
- package/src/components/list-item/ds-mobile-list-item.ts +603 -0
- package/src/components/list-item/index.ts +2 -0
- package/src/components/list-item-static/ds-mobile-list-item-static.ts +133 -0
- package/src/components/list-item-static/index.ts +2 -0
- package/src/components/loader-overlay/ds-mobile-loader-overlay.css +49 -0
- package/src/components/loader-overlay/ds-mobile-loader-overlay.ts +77 -0
- package/src/components/loader-overlay/index.ts +1 -0
- package/src/components/logo/ds-logo.ts +95 -0
- package/src/components/logo/index.ts +2 -0
- package/src/components/message-bubble/ds-mobile-message-bubble.ts +633 -0
- package/src/components/message-bubble/index.ts +7 -0
- package/src/components/message-composer/ds-mobile-message-composer.ts +1146 -0
- package/src/components/message-composer/index.ts +7 -0
- package/src/components/modal/ds-mobile-modal.css +163 -0
- package/src/components/modal/ds-mobile-modal.service.ts +329 -0
- package/src/components/modal/index.ts +8 -0
- package/src/components/modal-base/ds-mobile-modal-base.css +378 -0
- package/src/components/modal-base/ds-mobile-modal-base.ts +261 -0
- package/src/components/modal-base/index.ts +2 -0
- package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.css +112 -0
- package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.service.ts +93 -0
- package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.ts +442 -0
- package/src/components/new-inquiry-modal/index.ts +4 -0
- package/src/components/offline-banner/ds-mobile-offline-banner.ts +135 -0
- package/src/components/offline-banner/index.ts +1 -0
- package/src/components/page-details/ds-mobile-page-details.css +83 -0
- package/src/components/page-details/ds-mobile-page-details.ts +282 -0
- package/src/components/page-details/index.ts +2 -0
- package/src/components/page-main/ds-mobile-page-main.css +68 -0
- package/src/components/page-main/ds-mobile-page-main.ts +421 -0
- package/src/components/page-main/index.ts +2 -0
- package/src/components/post-composer/ds-mobile-post-composer.ts +140 -0
- package/src/components/post-composer/index.ts +2 -0
- package/src/components/post-detail-modal/ds-mobile-post-detail-modal.css +390 -0
- package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +108 -0
- package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +722 -0
- package/src/components/post-detail-modal/index.ts +9 -0
- package/src/components/property-banner/ds-mobile-property-banner.ts +95 -0
- package/src/components/property-banner/index.ts +2 -0
- package/src/components/section/ds-mobile-section.ts +263 -0
- package/src/components/section/index.ts +2 -0
- package/src/components/shared/directives/index.ts +2 -0
- package/src/components/shared/directives/long-press.directive.ts +212 -0
- package/src/components/shared/index.ts +3 -0
- package/src/components/shared/mobile-modal-base.ts +457 -0
- package/src/components/shared/mobile-page-base.ts +204 -0
- package/src/components/swiper/ds-mobile-swiper-with-nav.ts +160 -0
- package/src/components/swiper/ds-mobile-swiper.ts +327 -0
- package/src/components/swiper/index.ts +3 -0
- package/src/components/system-message-banner/ds-mobile-system-message-banner.ts +129 -0
- package/src/components/system-message-banner/index.ts +2 -0
- package/src/components/tab-bar/ds-mobile-tab-bar.css +533 -0
- package/src/components/tab-bar/ds-mobile-tab-bar.ts +735 -0
- package/src/components/tab-bar/index.ts +2 -0
- package/src/components/tabs/ds-mobile-tabs.css +25 -0
- package/src/components/tabs/ds-mobile-tabs.ts +89 -0
- package/src/components/tabs/index.ts +2 -0
- package/src/components/text-input/ds-text-input.ts +287 -0
- package/src/components/text-input/index.ts +2 -0
- package/src/examples/booking.page.ts +434 -0
- package/src/examples/community.page.ts +776 -0
- package/src/examples/handbook.page.ts +324 -0
- package/src/examples/home.page.ts +347 -0
- package/src/examples/index.ts +12 -0
- package/src/examples/inquiries.example.ts +273 -0
- package/src/examples/inquiry-detail.example.css +189 -0
- package/src/examples/inquiry-detail.example.ts +415 -0
- package/src/examples/mobile-tabs-example.component.ts +208 -0
- package/src/examples/post-create.page.ts +311 -0
- package/src/examples/post-detail.page.ts +296 -0
- package/src/examples/sign-in.page.ts +291 -0
- package/src/examples/whitelabel-demo-modal.component.ts +1094 -0
- package/src/examples/whitelabel-demo-modal.service.ts +77 -0
- package/src/models/index.ts +7 -0
- package/src/models/post.model.ts +41 -0
- package/src/pages/community.page.ts +769 -0
- package/src/pages/handbook.page.ts +388 -0
- package/src/pages/home.page.ts +303 -0
- package/src/pages/index.ts +11 -0
- package/src/pages/inquiries.example.ts +273 -0
- package/src/pages/inquiry-detail.example.css +189 -0
- package/src/pages/inquiry-detail.example.ts +415 -0
- package/src/pages/mobile-tabs-example.component.ts +179 -0
- package/src/pages/post-create.page.ts +311 -0
- package/src/pages/post-detail.page.ts +296 -0
- package/src/pages/sign-in.page.ts +291 -0
- package/src/pages/whitelabel-demo-modal.component.ts +1094 -0
- package/src/pages/whitelabel-demo-modal.service.ts +77 -0
- package/src/public-api.ts +6 -0
- package/src/services/base-modal.service.ts +101 -0
- package/src/services/index.ts +11 -0
- package/src/services/posts.service.ts +542 -0
- package/src/services/tracking-permission.service.ts +88 -0
- package/src/services/user.service.ts +60 -0
- package/src/services/whitelabel.service.ts +675 -0
- package/{styles → src/styles}/ionic.css +25 -0
- package/tsconfig.lib.json +17 -0
- package/tsconfig.lib.prod.json +9 -0
- package/tsconfig.spec.json +13 -0
- package/fesm2022/propbinder-mobile-design.mjs +0 -26168
- package/fesm2022/propbinder-mobile-design.mjs.map +0 -1
- package/index.d.ts +0 -8169
- /package/{assets → src/assets}/fonts/Brockmann-Bold.otf +0 -0
- /package/{assets → src/assets}/fonts/Brockmann-BoldItalic.otf +0 -0
- /package/{assets → src/assets}/fonts/Brockmann-Medium.otf +0 -0
- /package/{assets → src/assets}/fonts/Brockmann-MediumItalic.otf +0 -0
- /package/{assets → src/assets}/fonts/Brockmann-Regular.otf +0 -0
- /package/{assets → src/assets}/fonts/Brockmann-RegularItalic.otf +0 -0
- /package/{assets → src/assets}/fonts/Brockmann-SemiBold.otf +0 -0
- /package/{assets → src/assets}/fonts/Brockmann-SemiBoldItalic.otf +0 -0
- /package/{assets → src/assets}/fonts/Brockmann_desktop_license.pdf +0 -0
- /package/{assets → src/assets}/fonts/brockmann-medium-webfont.woff2 +0 -0
- /package/{assets → src/assets}/fonts/brockmann-regular-webfont.woff2 +0 -0
- /package/{assets → src/assets}/fonts/brockmann-semibold-webfont.woff2 +0 -0
- /package/{styles → src/components/shared}/mobile-common.css +0 -0
- /package/{styles → src/components/shared}/mobile-page-base.css +0 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import { Component, signal, Input, OnInit, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { ModalController } from '@ionic/angular/standalone';
|
|
4
|
+
import { DsMobileHandbookFolderMiniComponent } from '../handbook-folder/ds-mobile-handbook-folder-mini';
|
|
5
|
+
import { DsMobileCardInlineFileComponent } from '../card-inline-file';
|
|
6
|
+
import { DsMobileCardInlineContactComponent } from '../card-inline-contact';
|
|
7
|
+
import { DsMobileSwiperComponent } from '../swiper';
|
|
8
|
+
import { DsMobileModalBaseComponent } from '../modal-base/ds-mobile-modal-base';
|
|
9
|
+
import { DsMobileSectionComponent } from '../section';
|
|
10
|
+
import { DsMobileActionsBottomSheetComponent, ActionGroup } from '../bottom-sheet/ds-mobile-actions-bottom-sheet';
|
|
11
|
+
import { disableModalShadowPointerEvents } from '../bottom-sheet/modal-shadow-fix';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Handbook detail data interface
|
|
15
|
+
*
|
|
16
|
+
* Represents a handbook category/folder with its sections/items.
|
|
17
|
+
* Use this interface to map your API response data to the component.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const handbookData: HandbookDetailData = {
|
|
22
|
+
* title: 'Access Systems',
|
|
23
|
+
* variant: 'blue',
|
|
24
|
+
* iconName: 'remixKey2Line',
|
|
25
|
+
* itemCount: 5,
|
|
26
|
+
* items: [...]
|
|
27
|
+
* };
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export interface HandbookDetailData {
|
|
31
|
+
/** Category/folder title */
|
|
32
|
+
title: string;
|
|
33
|
+
/** Color variant: 'success', 'warning', 'destructive', 'blue', 'light-purple', 'pink', 'salmon-orange', 'orange', 'lime-green', 'grey' */
|
|
34
|
+
variant: string;
|
|
35
|
+
/** Optional custom hex color */
|
|
36
|
+
customColor?: string;
|
|
37
|
+
/** Icon name from design system (e.g., 'remixKey2Line', 'remixLightbulbLine') */
|
|
38
|
+
iconName: string;
|
|
39
|
+
/** Total number of items/sections in this category */
|
|
40
|
+
itemCount: number;
|
|
41
|
+
/** Array of handbook sections/items */
|
|
42
|
+
items?: HandbookItem[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Handbook section/item interface
|
|
47
|
+
*
|
|
48
|
+
* Represents a single section within a handbook category.
|
|
49
|
+
* Each section can have a title, description, images, contacts, and attachments.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const item: HandbookItem = {
|
|
54
|
+
* title: 'Key Box Entrance',
|
|
55
|
+
* description: 'Key box located at main entrance...',
|
|
56
|
+
* images: ['https://api.example.com/images/keybox.jpg'],
|
|
57
|
+
* contacts: [{ name: 'Security Co', initials: 'S', phoneNumber: '+45 12345678' }],
|
|
58
|
+
* attachments: [{ name: 'Manual.pdf', type: 'pdf', url: 'https://...' }]
|
|
59
|
+
* };
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export interface HandbookItem {
|
|
63
|
+
/** Section title */
|
|
64
|
+
title: string;
|
|
65
|
+
/** Optional section description */
|
|
66
|
+
description?: string;
|
|
67
|
+
/** Array of image URLs to display */
|
|
68
|
+
images?: string[];
|
|
69
|
+
/** Array of file attachments */
|
|
70
|
+
attachments?: AttachmentItem[];
|
|
71
|
+
/** Array of contact information */
|
|
72
|
+
contacts?: ContactItem[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* File attachment interface
|
|
77
|
+
*
|
|
78
|
+
* Represents a file attachment in a handbook section.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const attachment: AttachmentItem = {
|
|
83
|
+
* name: 'Installation_Manual.pdf',
|
|
84
|
+
* type: 'pdf',
|
|
85
|
+
* url: 'https://api.example.com/files/manual.pdf'
|
|
86
|
+
* };
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export interface AttachmentItem {
|
|
90
|
+
/** File name to display */
|
|
91
|
+
name: string;
|
|
92
|
+
/** File type: 'pdf', 'doc', etc. (used for icon display) */
|
|
93
|
+
type?: string;
|
|
94
|
+
/** Optional URL for downloading/opening the file */
|
|
95
|
+
url?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Contact information interface
|
|
100
|
+
*
|
|
101
|
+
* Represents contact information in a handbook section.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* const contact: ContactItem = {
|
|
106
|
+
* name: 'Propbinder ApS',
|
|
107
|
+
* initials: 'P',
|
|
108
|
+
* contactPerson: 'John Doe',
|
|
109
|
+
* phoneNumber: '+45 12345678',
|
|
110
|
+
* email: 'support@propbinder.dk'
|
|
111
|
+
* };
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export interface ContactItem {
|
|
115
|
+
/** Company or contact name */
|
|
116
|
+
name: string;
|
|
117
|
+
/** Initials for avatar (1-2 letters) */
|
|
118
|
+
initials: string;
|
|
119
|
+
/** Optional contact person name */
|
|
120
|
+
contactPerson?: string;
|
|
121
|
+
/** Optional phone number */
|
|
122
|
+
phoneNumber?: string;
|
|
123
|
+
/** Optional email address */
|
|
124
|
+
email?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* DsMobileHandbookDetailModalComponent
|
|
129
|
+
*
|
|
130
|
+
* Modal wrapper for displaying handbook folder details.
|
|
131
|
+
*
|
|
132
|
+
* Features:
|
|
133
|
+
* - Folder content display
|
|
134
|
+
* - Items list with descriptions
|
|
135
|
+
* - Images and attachments
|
|
136
|
+
* - Contact information
|
|
137
|
+
* - Native modal controls (close, swipe down)
|
|
138
|
+
* - Safe area support
|
|
139
|
+
*
|
|
140
|
+
* This component is typically not used directly - use DsMobileHandbookDetailModalService instead.
|
|
141
|
+
*/
|
|
142
|
+
@Component({
|
|
143
|
+
selector: 'ds-mobile-handbook-detail-modal',
|
|
144
|
+
standalone: true,
|
|
145
|
+
imports: [
|
|
146
|
+
CommonModule,
|
|
147
|
+
DsMobileHandbookFolderMiniComponent,
|
|
148
|
+
DsMobileCardInlineFileComponent,
|
|
149
|
+
DsMobileCardInlineContactComponent,
|
|
150
|
+
DsMobileSwiperComponent,
|
|
151
|
+
DsMobileModalBaseComponent,
|
|
152
|
+
DsMobileSectionComponent,
|
|
153
|
+
],
|
|
154
|
+
styleUrls: ['./ds-mobile-handbook-detail-modal.css'],
|
|
155
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
156
|
+
template: `
|
|
157
|
+
<ds-mobile-modal-base [loading]="loading" [error]="error" [headerTitle]="handbook().title" [headerMeta]="handbook().itemCount + ' emner'" closeButtonLabel="Luk">
|
|
158
|
+
<!-- Header Folder Icon -->
|
|
159
|
+
<ds-mobile-handbook-folder-mini header-leading [variant]="handbook().variant" [customColor]="handbook().customColor" [iconName]="handbook().iconName">
|
|
160
|
+
</ds-mobile-handbook-folder-mini>
|
|
161
|
+
|
|
162
|
+
<!-- Content (main content slot) -->
|
|
163
|
+
@if (handbook().items && handbook().items!.length > 0) {
|
|
164
|
+
@for (item of getDisplayItems(); track item.title + $index) {
|
|
165
|
+
<ds-mobile-section [headline]="item.title || ''" contentGap="20px">
|
|
166
|
+
@if (item.description) {
|
|
167
|
+
<div class="item-description" [innerHTML]="item.description"></div>
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
<!-- Images -->
|
|
171
|
+
@if (item.images && item.images.length > 0) {
|
|
172
|
+
<ds-mobile-swiper [slideWidth]="item.images.length === 1 ? '100%' : '85%'" [gap]="16">
|
|
173
|
+
@for (image of item.images; track image) {
|
|
174
|
+
<div class="swiper-slide">
|
|
175
|
+
<img [src]="image" [alt]="item.title" class="item-image" />
|
|
176
|
+
</div>
|
|
177
|
+
}
|
|
178
|
+
</ds-mobile-swiper>
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
<!-- Contacts and Attachments (grouped) -->
|
|
182
|
+
@if ((item.contacts && item.contacts.length > 0) || (item.attachments && item.attachments.length > 0)) {
|
|
183
|
+
<div class="contacts-attachments-group">
|
|
184
|
+
@if (item.contacts && item.contacts.length > 0) {
|
|
185
|
+
@for (contact of item.contacts; track contact.name) {
|
|
186
|
+
<ds-mobile-card-inline-contact
|
|
187
|
+
[name]="contact.name"
|
|
188
|
+
[initials]="contact.initials"
|
|
189
|
+
[contactPerson]="contact.contactPerson || ''"
|
|
190
|
+
[phoneNumber]="contact.phoneNumber || ''"
|
|
191
|
+
[clickable]="true"
|
|
192
|
+
(contactClick)="handleContactClick(contact)"
|
|
193
|
+
>
|
|
194
|
+
</ds-mobile-card-inline-contact>
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@if (item.attachments && item.attachments.length > 0) {
|
|
199
|
+
@for (attachment of item.attachments; track attachment.name) {
|
|
200
|
+
<ds-mobile-card-inline-file
|
|
201
|
+
[fileName]="attachment.name"
|
|
202
|
+
[variant]="attachment.type === 'pdf' ? 'pdf' : 'doc'"
|
|
203
|
+
[fileUrl]="attachment.url"
|
|
204
|
+
(fileClick)="handleAttachmentClick(attachment)"
|
|
205
|
+
>
|
|
206
|
+
</ds-mobile-card-inline-file>
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
</div>
|
|
210
|
+
}
|
|
211
|
+
</ds-mobile-section>
|
|
212
|
+
}
|
|
213
|
+
} @else {
|
|
214
|
+
<!-- Empty State -->
|
|
215
|
+
<ds-mobile-section>
|
|
216
|
+
<div class="handbook-empty-state">
|
|
217
|
+
<img src="/Assets/Empty%20state-chat.png" alt="No items yet" class="empty-state-image" />
|
|
218
|
+
<h3 class="empty-state-title">No items yet</h3>
|
|
219
|
+
<p class="empty-state-description">This folder is empty</p>
|
|
220
|
+
</div>
|
|
221
|
+
</ds-mobile-section>
|
|
222
|
+
}
|
|
223
|
+
</ds-mobile-modal-base>
|
|
224
|
+
`,
|
|
225
|
+
})
|
|
226
|
+
export class DsMobileHandbookDetailModalComponent implements OnInit {
|
|
227
|
+
// Handbook data passed from service
|
|
228
|
+
@Input() handbookData!: HandbookDetailData;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Loading state - when true, shows loading indicator
|
|
232
|
+
*/
|
|
233
|
+
@Input() loading: boolean = false;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Error state - when set, shows error message
|
|
237
|
+
*/
|
|
238
|
+
@Input() error?: string;
|
|
239
|
+
|
|
240
|
+
// Signal for reactive handbook data
|
|
241
|
+
handbook = signal<HandbookDetailData>({
|
|
242
|
+
title: '',
|
|
243
|
+
variant: 'light-purple',
|
|
244
|
+
iconName: 'remixFolder3Line',
|
|
245
|
+
itemCount: 0,
|
|
246
|
+
items: [],
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
constructor(private modalController: ModalController) {}
|
|
250
|
+
|
|
251
|
+
ngOnInit(): void {
|
|
252
|
+
// Initialize handbook data from input
|
|
253
|
+
if (this.handbookData) {
|
|
254
|
+
this.handbook.set(this.handbookData);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Split handbook items to enforce content structure rules:
|
|
260
|
+
* - Never mix photos and documents (attachments) in the same section
|
|
261
|
+
* - Never mix contact persons and attachments together in the same section
|
|
262
|
+
*
|
|
263
|
+
* This method splits items that violate these rules into multiple display items.
|
|
264
|
+
* Each resulting item will have only compatible content types.
|
|
265
|
+
*/
|
|
266
|
+
splitItemsByContentRules(item: HandbookItem): HandbookItem[] {
|
|
267
|
+
const displayItems: HandbookItem[] = [];
|
|
268
|
+
|
|
269
|
+
const hasImages = item.images && item.images.length > 0;
|
|
270
|
+
const hasContacts = item.contacts && item.contacts.length > 0;
|
|
271
|
+
const hasAttachments = item.attachments && item.attachments.length > 0;
|
|
272
|
+
const hasContent = hasContacts || hasAttachments;
|
|
273
|
+
|
|
274
|
+
// Case 1: Images AND other content -> Split Pictures from (Contacts + Attachments)
|
|
275
|
+
if (hasImages && hasContent) {
|
|
276
|
+
// Part 1: Images
|
|
277
|
+
displayItems.push({
|
|
278
|
+
title: item.title,
|
|
279
|
+
description: item.description,
|
|
280
|
+
images: item.images,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Part 2: Contacts + Attachments
|
|
284
|
+
displayItems.push({
|
|
285
|
+
title: '', // No title for the continuation
|
|
286
|
+
description: undefined,
|
|
287
|
+
contacts: item.contacts,
|
|
288
|
+
attachments: item.attachments,
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
return displayItems;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Case 2: No splitting needed (Images only, or No Images)
|
|
295
|
+
// This allows Contacts and Attachments to coexist in one item
|
|
296
|
+
return [item];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Get all display items with enforced content structure rules applied
|
|
301
|
+
*/
|
|
302
|
+
getDisplayItems(): HandbookItem[] {
|
|
303
|
+
const items = this.handbook().items || [];
|
|
304
|
+
const displayItems: HandbookItem[] = [];
|
|
305
|
+
|
|
306
|
+
for (const item of items) {
|
|
307
|
+
const splitItems = this.splitItemsByContentRules(item);
|
|
308
|
+
displayItems.push(...splitItems);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return displayItems;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Handle contact click - shows bottom sheet with call and copy actions
|
|
316
|
+
*/
|
|
317
|
+
async handleContactClick(contact: ContactItem): Promise<void> {
|
|
318
|
+
// Only show actions if there's a phone number
|
|
319
|
+
if (!contact.phoneNumber) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const actionGroups: ActionGroup[] = [
|
|
324
|
+
{
|
|
325
|
+
actions: [
|
|
326
|
+
{
|
|
327
|
+
action: 'call',
|
|
328
|
+
title: 'Ring',
|
|
329
|
+
icon: 'remixPhoneLine',
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
action: 'copy',
|
|
333
|
+
title: 'Kopier nummer',
|
|
334
|
+
icon: 'remixFileCopyLine',
|
|
335
|
+
},
|
|
336
|
+
],
|
|
337
|
+
},
|
|
338
|
+
];
|
|
339
|
+
|
|
340
|
+
const sheet = await this.modalController.create({
|
|
341
|
+
component: DsMobileActionsBottomSheetComponent,
|
|
342
|
+
componentProps: {
|
|
343
|
+
customActionGroups: actionGroups,
|
|
344
|
+
},
|
|
345
|
+
breakpoints: [0, 1],
|
|
346
|
+
initialBreakpoint: 1,
|
|
347
|
+
handle: true,
|
|
348
|
+
cssClass: ['ds-bottom-sheet', 'auto-height'],
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
await sheet.present();
|
|
352
|
+
disableModalShadowPointerEvents(sheet);
|
|
353
|
+
|
|
354
|
+
const result = await sheet.onWillDismiss();
|
|
355
|
+
if (result.data?.action) {
|
|
356
|
+
this.handleContactAction(result.data.action, contact);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Handle the selected contact action
|
|
362
|
+
*/
|
|
363
|
+
private async handleContactAction(action: string, contact: ContactItem): Promise<void> {
|
|
364
|
+
switch (action) {
|
|
365
|
+
case 'call':
|
|
366
|
+
// Open phone dialer with the contact's phone number
|
|
367
|
+
if (contact.phoneNumber) {
|
|
368
|
+
window.location.href = `tel:${contact.phoneNumber}`;
|
|
369
|
+
}
|
|
370
|
+
break;
|
|
371
|
+
|
|
372
|
+
case 'copy':
|
|
373
|
+
// Copy phone number to clipboard
|
|
374
|
+
if (contact.phoneNumber) {
|
|
375
|
+
try {
|
|
376
|
+
// Try modern Clipboard API first
|
|
377
|
+
await navigator.clipboard.writeText(contact.phoneNumber);
|
|
378
|
+
console.log('Phone number copied to clipboard:', contact.phoneNumber);
|
|
379
|
+
// TODO: Show toast notification if you have a toast service
|
|
380
|
+
} catch (err) {
|
|
381
|
+
console.error('Failed to copy phone number:', err);
|
|
382
|
+
// Fallback: Try older execCommand method
|
|
383
|
+
this.fallbackCopyToClipboard(contact.phoneNumber);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Fallback method for copying text to clipboard (for older browsers/webviews)
|
|
392
|
+
*/
|
|
393
|
+
private fallbackCopyToClipboard(text: string): void {
|
|
394
|
+
const textArea = document.createElement('textarea');
|
|
395
|
+
textArea.value = text;
|
|
396
|
+
textArea.style.position = 'fixed';
|
|
397
|
+
textArea.style.left = '-999999px';
|
|
398
|
+
textArea.style.top = '-999999px';
|
|
399
|
+
document.body.appendChild(textArea);
|
|
400
|
+
textArea.focus();
|
|
401
|
+
textArea.select();
|
|
402
|
+
|
|
403
|
+
try {
|
|
404
|
+
const successful = document.execCommand('copy');
|
|
405
|
+
if (successful) {
|
|
406
|
+
console.log('Phone number copied to clipboard (fallback):', text);
|
|
407
|
+
} else {
|
|
408
|
+
console.error('Fallback copy failed');
|
|
409
|
+
}
|
|
410
|
+
} catch (err) {
|
|
411
|
+
console.error('Fallback copy error:', err);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
document.body.removeChild(textArea);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Handle attachment click
|
|
419
|
+
*/
|
|
420
|
+
handleAttachmentClick(attachment: AttachmentItem): void {
|
|
421
|
+
console.log('Attachment clicked:', attachment);
|
|
422
|
+
// Attachment action is now handled by DsMobileCardInlineFileComponent via fileUrl input
|
|
423
|
+
}
|
|
424
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { Component, Input } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { DsIconComponent } from '@propbinder/design-system';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* DsMobileHandbookFolderMiniComponent
|
|
7
|
+
*
|
|
8
|
+
* A minimized folder icon component for use in headers and small spaces.
|
|
9
|
+
* Simplified version without animations or page sheets - just folder and icon.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```html
|
|
13
|
+
* <ds-mobile-handbook-folder-mini
|
|
14
|
+
* [variant]="'pink'"
|
|
15
|
+
* [iconName]="'remixLightbulbLine'">
|
|
16
|
+
* </ds-mobile-handbook-folder-mini>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
@Component({
|
|
20
|
+
selector: 'ds-mobile-handbook-folder-mini',
|
|
21
|
+
standalone: true,
|
|
22
|
+
imports: [CommonModule, DsIconComponent],
|
|
23
|
+
styles: [
|
|
24
|
+
`
|
|
25
|
+
:host {
|
|
26
|
+
display: inline-block;
|
|
27
|
+
width: 32px;
|
|
28
|
+
height: 32px;
|
|
29
|
+
flex-shrink: 0;
|
|
30
|
+
|
|
31
|
+
/* Native support for extended API colors */
|
|
32
|
+
--color-red-base: #dc3545;
|
|
33
|
+
--color-red-strong: #ae1d3b;
|
|
34
|
+
--color-green-base: #28a745;
|
|
35
|
+
--color-green-strong: #058057;
|
|
36
|
+
--color-yellow-base: #ffc107;
|
|
37
|
+
--color-yellow-strong: #e4b200;
|
|
38
|
+
--color-purple-base: #6f42c1;
|
|
39
|
+
--color-purple-strong: #4204c5;
|
|
40
|
+
--color-indigo-base: #6610f2;
|
|
41
|
+
--color-indigo-strong: #a527a2;
|
|
42
|
+
--color-lime-base: #82c91e;
|
|
43
|
+
--color-lime-strong: #58a503;
|
|
44
|
+
--color-teal-base: #20c997;
|
|
45
|
+
--color-teal-strong: #0ca678;
|
|
46
|
+
--color-cyan-base: #17a2b8;
|
|
47
|
+
--color-cyan-strong: #1098ad;
|
|
48
|
+
--color-brown-base: #795548;
|
|
49
|
+
--color-brown-strong: #5c4033;
|
|
50
|
+
--color-light-blue-base: #add8e6;
|
|
51
|
+
--color-light-blue-strong: #87ceeb;
|
|
52
|
+
--color-light-green-base: #90ee90;
|
|
53
|
+
--color-light-green-strong: #32cd32;
|
|
54
|
+
--color-coral-base: #f08080;
|
|
55
|
+
--color-coral-strong: #cd5c5c;
|
|
56
|
+
--color-salmon-base: #ffa07a;
|
|
57
|
+
--color-salmon-strong: #fa8072;
|
|
58
|
+
--color-seagreen-base: #20b2aa;
|
|
59
|
+
--color-seagreen-strong: #2e8b57;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.mini-folder-container {
|
|
63
|
+
position: relative;
|
|
64
|
+
width: 100%;
|
|
65
|
+
height: 100%;
|
|
66
|
+
display: flex;
|
|
67
|
+
flex-direction: column;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.mini-folder-tab {
|
|
71
|
+
width: 50%;
|
|
72
|
+
height: auto;
|
|
73
|
+
display: block;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.mini-folder-back {
|
|
77
|
+
height: 28px;
|
|
78
|
+
border-radius: 0px 4px 4px 4px;
|
|
79
|
+
position: relative;
|
|
80
|
+
margin-top: -1px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.mini-folder-front {
|
|
84
|
+
position: absolute;
|
|
85
|
+
bottom: 0;
|
|
86
|
+
left: 0;
|
|
87
|
+
right: 0;
|
|
88
|
+
height: 24px;
|
|
89
|
+
border-radius: 4px;
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
z-index: 2;
|
|
94
|
+
box-shadow:
|
|
95
|
+
inset 0 8px 8px rgba(255, 255, 255, 0.2),
|
|
96
|
+
inset 0 0.5px 0.5px rgba(255, 255, 255, 0.3);
|
|
97
|
+
}
|
|
98
|
+
`,
|
|
99
|
+
],
|
|
100
|
+
template: `
|
|
101
|
+
<div class="mini-folder-container">
|
|
102
|
+
<!-- Folder Tab SVG -->
|
|
103
|
+
<svg class="mini-folder-tab" width="101" height="24" viewBox="0 0 101 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
104
|
+
<path
|
|
105
|
+
d="M100.037 23.9999L100.5 24L0 24.0001V10.7646C0 4.80853 4.91797 -0.0234985 11 -0.0196688L66.4213 -0.0322266C69.3519 -0.0115886 72.197 1.20548 74.2473 3.29947L90.6765 20.0951C93.1218 22.5925 96.5417 23.9999 100.037 23.9999Z"
|
|
106
|
+
[attr.fill]="customColor || getColorVar('strong')"
|
|
107
|
+
/>
|
|
108
|
+
</svg>
|
|
109
|
+
|
|
110
|
+
<!-- Folder Back -->
|
|
111
|
+
<div class="mini-folder-back" [style.background-color]="customColor || getColorVar('strong')">
|
|
112
|
+
<!-- Folder Front -->
|
|
113
|
+
<div class="mini-folder-front" [style.background-color]="customColor || getColorVar('base')">
|
|
114
|
+
<ds-icon [name]="iconName" [size]="'14px'" [style.color]="'white'" />
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
`,
|
|
119
|
+
})
|
|
120
|
+
export class DsMobileHandbookFolderMiniComponent {
|
|
121
|
+
/**
|
|
122
|
+
* Color variant for the folder
|
|
123
|
+
* Available variants: success, warning, destructive, blue, light-purple, pink, salmon-orange, orange, lime-green, grey
|
|
124
|
+
*/
|
|
125
|
+
@Input() variant: string = 'light-purple';
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Optional custom hex color for the folder.
|
|
129
|
+
* If provided, overrides the variant color.
|
|
130
|
+
*/
|
|
131
|
+
@Input() customColor?: string;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Icon name from the design system icon library
|
|
135
|
+
*/
|
|
136
|
+
@Input() iconName: string = 'remixFolder3Line';
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get the CSS variable name for the color variant
|
|
140
|
+
*/
|
|
141
|
+
getColorVar(suffix: 'base' | 'strong'): string {
|
|
142
|
+
const variantMap: Record<string, string> = {
|
|
143
|
+
// Core design system variants
|
|
144
|
+
success: 'success',
|
|
145
|
+
warning: 'warning',
|
|
146
|
+
destructive: 'destructive',
|
|
147
|
+
blue: 'blue',
|
|
148
|
+
'light-purple': 'light-purple',
|
|
149
|
+
pink: 'pink',
|
|
150
|
+
'salmon-orange': 'salmon-orange',
|
|
151
|
+
orange: 'orange',
|
|
152
|
+
'lime-green': 'lime-green',
|
|
153
|
+
grey: 'grey',
|
|
154
|
+
|
|
155
|
+
// Extended API colors mapping to their native exact counterparts now
|
|
156
|
+
red: 'red',
|
|
157
|
+
green: 'green',
|
|
158
|
+
yellow: 'yellow',
|
|
159
|
+
purple: 'purple',
|
|
160
|
+
indigo: 'indigo',
|
|
161
|
+
lime: 'lime',
|
|
162
|
+
teal: 'teal',
|
|
163
|
+
cyan: 'cyan',
|
|
164
|
+
brown: 'brown',
|
|
165
|
+
'light-blue': 'light-blue',
|
|
166
|
+
'light-green': 'light-green',
|
|
167
|
+
coral: 'coral',
|
|
168
|
+
salmon: 'salmon',
|
|
169
|
+
seagreen: 'seagreen',
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const colorName = variantMap[this.variant] || 'light-purple';
|
|
173
|
+
return `var(--color-${colorName}-${suffix})`;
|
|
174
|
+
}
|
|
175
|
+
}
|