@unopsitg/ux 21.0.2 → 21.0.19
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/assets/_card.scss +89 -2
- package/assets/_config.scss +3 -3
- package/assets/_content.scss +39 -5
- package/assets/_footer.scss +59 -3
- package/assets/_main.scss +6 -8
- package/assets/_responsive.scss +15 -3
- package/assets/_sass_variables.scss +8 -2
- package/assets/_search.scss +3 -3
- package/assets/_tabs.scss +44 -0
- package/assets/_tags.scss +1 -1
- package/assets/_topbar.scss +45 -17
- package/assets/_utils.scss +0 -12
- package/assets/layout.scss +1 -0
- package/assets/sidebar/_sidebar_compact.scss +1 -6
- package/assets/sidebar/_sidebar_horizontal.scss +97 -76
- package/assets/sidebar/_sidebar_slim.scss +1 -6
- package/assets/sidebar/_sidebar_theme_core.scss +19 -19
- package/assets/sidebar/themes/_dark.scss +5 -5
- package/assets/sidebar/themes/_light.scss +2 -2
- package/assets/sidebar/themes/_primary.scss +8 -8
- package/assets/tailwind.css +54 -25
- package/assets/variables/_common.scss +1 -0
- package/assets/variables/_light.scss +2 -2
- package/fesm2022/unopsitg-ux.mjs +1568 -207
- package/fesm2022/unopsitg-ux.mjs.map +1 -1
- package/package.json +1 -1
- package/types/unopsitg-ux.d.ts +277 -185
- package/assets/opp/AppLogo/AppLogo-onDark_V.svg +0 -55
- package/assets/opp/AppLogo/AppLogo-onLight_V.svg +0 -55
- package/assets/opp/AppLogo-dark-vertical.svg +0 -55
- package/assets/opp/drive-download-20260421T141232Z-3-001.zip +0 -0
- package/assets/opp/favicon/favicon.svg +0 -17
- package/assets/opp/logo-dark-horizontal.svg +0 -55
- package/assets/opp/logo-light-horizontal.svg +0 -55
package/fesm2022/unopsitg-ux.mjs
CHANGED
|
@@ -3,23 +3,23 @@ import SoftBase from '@primeuix/themes/aura';
|
|
|
3
3
|
import CrispBase from '@primeuix/themes/lara';
|
|
4
4
|
import ContrastBase from '@primeuix/themes/nora';
|
|
5
5
|
import * as i0 from '@angular/core';
|
|
6
|
-
import { InjectionToken, signal, inject, computed, effect, Injectable, Component, PLATFORM_ID, model, booleanAttribute, Input, input, HostListener, ViewChild, ElementRef,
|
|
6
|
+
import { InjectionToken, signal, inject, computed, effect, Injectable, Component, PLATFORM_ID, model, booleanAttribute, Input, input, ChangeDetectionStrategy, HostListener, ViewChild, ElementRef, output, DestroyRef, Directive, ContentChildren } from '@angular/core';
|
|
7
7
|
import * as i1 from '@angular/router';
|
|
8
8
|
import { Router, NavigationEnd, RouterModule } from '@angular/router';
|
|
9
9
|
import * as i1$1 from '@angular/common';
|
|
10
|
-
import { CommonModule, isPlatformBrowser } from '@angular/common';
|
|
10
|
+
import { CommonModule, isPlatformBrowser, NgTemplateOutlet, NgClass } from '@angular/common';
|
|
11
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
11
12
|
import { BehaviorSubject, filter, Subject, takeUntil } from 'rxjs';
|
|
12
|
-
import * as
|
|
13
|
+
import * as i1$2 from '@angular/forms';
|
|
13
14
|
import { FormsModule } from '@angular/forms';
|
|
14
15
|
import { PrimeNG } from 'primeng/config';
|
|
15
16
|
import * as i4 from 'primeng/drawer';
|
|
16
17
|
import { DrawerModule } from 'primeng/drawer';
|
|
17
|
-
import * as i5
|
|
18
|
+
import * as i5 from 'primeng/radiobutton';
|
|
18
19
|
import { RadioButtonModule } from 'primeng/radiobutton';
|
|
19
20
|
import * as i3 from 'primeng/selectbutton';
|
|
20
21
|
import { SelectButtonModule } from 'primeng/selectbutton';
|
|
21
|
-
import
|
|
22
|
-
import * as i6 from 'primeng/button';
|
|
22
|
+
import * as i2$1 from 'primeng/button';
|
|
23
23
|
import { ButtonModule } from 'primeng/button';
|
|
24
24
|
import * as i2 from 'primeng/divider';
|
|
25
25
|
import { DividerModule } from 'primeng/divider';
|
|
@@ -29,7 +29,7 @@ import * as i3$1 from 'primeng/select';
|
|
|
29
29
|
import { SelectModule } from 'primeng/select';
|
|
30
30
|
import * as i3$2 from 'primeng/autofocus';
|
|
31
31
|
import { AutoFocusModule } from 'primeng/autofocus';
|
|
32
|
-
import * as i1$
|
|
32
|
+
import * as i1$3 from 'primeng/dialog';
|
|
33
33
|
import { DialogModule } from 'primeng/dialog';
|
|
34
34
|
import * as i4$2 from 'primeng/ripple';
|
|
35
35
|
import { RippleModule } from 'primeng/ripple';
|
|
@@ -39,14 +39,34 @@ import * as i10 from 'primeng/avatar';
|
|
|
39
39
|
import { AvatarModule } from 'primeng/avatar';
|
|
40
40
|
import * as i8 from 'primeng/badge';
|
|
41
41
|
import { BadgeModule } from 'primeng/badge';
|
|
42
|
-
import * as i5$
|
|
42
|
+
import * as i5$1 from 'primeng/iconfield';
|
|
43
43
|
import { IconFieldModule } from 'primeng/iconfield';
|
|
44
|
-
import * as i6
|
|
44
|
+
import * as i6 from 'primeng/inputicon';
|
|
45
45
|
import { InputIconModule } from 'primeng/inputicon';
|
|
46
46
|
import * as i9 from 'primeng/overlaybadge';
|
|
47
47
|
import { OverlayBadgeModule } from 'primeng/overlaybadge';
|
|
48
48
|
import * as i3$4 from 'primeng/styleclass';
|
|
49
49
|
import { StyleClassModule } from 'primeng/styleclass';
|
|
50
|
+
import * as i2$2 from 'primeng/paginator';
|
|
51
|
+
import { PaginatorModule } from 'primeng/paginator';
|
|
52
|
+
import * as i4$3 from 'primeng/tabs';
|
|
53
|
+
import { TabsModule } from 'primeng/tabs';
|
|
54
|
+
import * as i3$5 from 'primeng/fileupload';
|
|
55
|
+
import { FileUploadModule } from 'primeng/fileupload';
|
|
56
|
+
import * as i7 from 'primeng/menu';
|
|
57
|
+
import { MenuModule } from 'primeng/menu';
|
|
58
|
+
import * as i10$1 from 'primeng/panel';
|
|
59
|
+
import { PanelModule } from 'primeng/panel';
|
|
60
|
+
import * as i8$1 from 'primeng/table';
|
|
61
|
+
import { TableModule } from 'primeng/table';
|
|
62
|
+
import * as i9$1 from 'primeng/tag';
|
|
63
|
+
import { TagModule } from 'primeng/tag';
|
|
64
|
+
import * as i8$2 from 'primeng/autocomplete';
|
|
65
|
+
import { AutoCompleteModule } from 'primeng/autocomplete';
|
|
66
|
+
import * as i7$1 from 'primeng/datepicker';
|
|
67
|
+
import { DatePickerModule } from 'primeng/datepicker';
|
|
68
|
+
import * as i5$2 from 'primeng/textarea';
|
|
69
|
+
import { TextareaModule } from 'primeng/textarea';
|
|
50
70
|
|
|
51
71
|
/**
|
|
52
72
|
* Brand theme presets built on top of PrimeUIX base presets.
|
|
@@ -57,8 +77,8 @@ import { StyleClassModule } from 'primeng/styleclass';
|
|
|
57
77
|
* Contrast <- @primeuix/themes/nora
|
|
58
78
|
*/
|
|
59
79
|
const brandPrimitives = {
|
|
60
|
-
deepsea: { 50: '#
|
|
61
|
-
gray: { 50: '#
|
|
80
|
+
deepsea: { 50: '#c3c7cb', 100: '#9ea5ac', 200: '#7a838d', 300: '#56626d', 400: '#31404e', 500: '#0d1e2f', 600: '#0b1a28', 700: '#091521', 800: '#07111a', 900: '#050c13', 950: '#03080c' },
|
|
81
|
+
gray: { 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1', 400: '#94a3b8', 500: '#64748b', 600: '#475569', 700: '#334155', 800: '#1e293b', 900: '#0f172a', 950: '#020617' },
|
|
62
82
|
red: { 50: '#f6cac6', 100: '#f0a9a4', 200: '#eb8982', 300: '#e56960', 400: '#e0493e', 500: '#da291c', 600: '#b92318', 700: '#991d14', 800: '#78170f', 900: '#57100b', 950: '#370a07' },
|
|
63
83
|
orange: { 50: '#f9d6c3', 100: '#f6be9f', 200: '#f2a57a', 300: '#ef8d56', 400: '#eb7432', 500: '#e85c0e', 600: '#c54e0c', 700: '#a2400a', 800: '#803308', 900: '#5d2506', 950: '#3a1704' },
|
|
64
84
|
yellow: { 50: '#fff0c5', 100: '#ffe7a1', 200: '#ffdd7e', 300: '#ffd45b', 400: '#ffcb38', 500: '#ffc215', 600: '#d9a512', 700: '#b3880f', 800: '#8c6b0c', 900: '#664e08', 950: '#403105' },
|
|
@@ -72,7 +92,8 @@ const brandPrimitives = {
|
|
|
72
92
|
blue: { 50: '#DEEFFF', 100: '#C9E8FF', 150: '#99D3ED', 200: '#73c3e6', 300: '#4db3df', 400: '#26a2d8', 500: '#0092d1', 600: '#007cb2', 700: '#006692', 800: '#005073', 900: '#003a54', 950: '#002534' },
|
|
73
93
|
darkblue: { 50: '#D0EEFF', 100: '#B7E2F9', 200: '#73abc7', 300: '#4d94b8', 400: '#267da9', 500: '#00669a', 600: '#005783', 700: '#00476c', 800: '#003855', 900: '#00293e', 950: '#001a27' },
|
|
74
94
|
midnight: { 50: '#bfd2dd', 100: '#99b6c8', 200: '#739bb4', 300: '#4d809f', 400: '#26648b', 500: '#004976', 600: '#003e64', 700: '#003353', 800: '#002841', 850: '#001E31', 900: '#001d2f', 950: '#00121e' },
|
|
75
|
-
cherry: { 50: '#e6c7d9', 100: '#d6a5c2', 200: '#c783ab', 300: '#b86294', 400: '#a8407d', 500: '#991e66', 600: '#821a57', 700: '#6b1547', 800: '#541138', 900: '#3d0c29', 950: '#26081a' }
|
|
95
|
+
cherry: { 50: '#e6c7d9', 100: '#d6a5c2', 200: '#c783ab', 300: '#b86294', 400: '#a8407d', 500: '#991e66', 600: '#821a57', 700: '#6b1547', 800: '#541138', 900: '#3d0c29', 950: '#26081a' },
|
|
96
|
+
ai: { 50: '#f0edff', 100: '#e4deff', 200: '#cdc2ff', 300: '#b0a0ff', 400: '#9378ff', 500: '#7c5cfc', 600: '#6a44f0', 700: '#5835d4', 800: '#482dac', 900: '#3b278a', 950: '#24185e' }
|
|
76
97
|
};
|
|
77
98
|
const brandOverrides = {
|
|
78
99
|
primitive: {
|
|
@@ -111,17 +132,17 @@ const brandOverrides = {
|
|
|
111
132
|
light: {
|
|
112
133
|
surface: {
|
|
113
134
|
0: '#ffffff',
|
|
114
|
-
50: '{
|
|
115
|
-
100: '{
|
|
116
|
-
200: '{
|
|
117
|
-
300: '{
|
|
118
|
-
400: '{
|
|
119
|
-
500: '{
|
|
120
|
-
600: '{
|
|
121
|
-
700: '{
|
|
122
|
-
800: '{
|
|
123
|
-
900: '{
|
|
124
|
-
950: '{
|
|
135
|
+
50: '{gray.50}',
|
|
136
|
+
100: '{gray.100}',
|
|
137
|
+
200: '{gray.200}',
|
|
138
|
+
300: '{gray.300}',
|
|
139
|
+
400: '{gray.400}',
|
|
140
|
+
500: '{gray.500}',
|
|
141
|
+
600: '{gray.600}',
|
|
142
|
+
700: '{gray.700}',
|
|
143
|
+
800: '{gray.800}',
|
|
144
|
+
900: '{gray.900}',
|
|
145
|
+
950: '{gray.950}'
|
|
125
146
|
}
|
|
126
147
|
},
|
|
127
148
|
dark: {
|
|
@@ -130,12 +151,12 @@ const brandOverrides = {
|
|
|
130
151
|
50: '{darkblue.50}',
|
|
131
152
|
100: '{darkblue.100}',
|
|
132
153
|
200: '{darkblue.200}',
|
|
133
|
-
300: '{darkblue.
|
|
134
|
-
400: '{
|
|
135
|
-
500: '{
|
|
136
|
-
600: '{darkblue.
|
|
137
|
-
700: '{darkblue.
|
|
138
|
-
800: '{darkblue.
|
|
154
|
+
300: '{darkblue.300}',
|
|
155
|
+
400: '{blue.400}',
|
|
156
|
+
500: '{blue.500}',
|
|
157
|
+
600: '{darkblue.600}',
|
|
158
|
+
700: '{darkblue.700}',
|
|
159
|
+
800: '{darkblue.800}',
|
|
139
160
|
900: '{darkblue.900}',
|
|
140
161
|
950: '{darkblue.950}'
|
|
141
162
|
}
|
|
@@ -143,6 +164,12 @@ const brandOverrides = {
|
|
|
143
164
|
}
|
|
144
165
|
},
|
|
145
166
|
components: {
|
|
167
|
+
accordion: {
|
|
168
|
+
root: { transitionDuration: '{transition.duration}' },
|
|
169
|
+
panel: { borderWidth: '0' },
|
|
170
|
+
header: { background: 'transparent', padding: '0 0 0 0' },
|
|
171
|
+
content: { background: 'transparent' }
|
|
172
|
+
},
|
|
146
173
|
button: {
|
|
147
174
|
colorScheme: {
|
|
148
175
|
light: {
|
|
@@ -171,11 +198,106 @@ const brandOverrides = {
|
|
|
171
198
|
}
|
|
172
199
|
}
|
|
173
200
|
},
|
|
201
|
+
// Tab active/hover backgrounds are set in _tabs.scss via sidebar
|
|
202
|
+
// `--d-menuitem-*` tokens (not expressible in the preset). Only structural
|
|
203
|
+
// properties that _tabs.scss does NOT override belong here.
|
|
204
|
+
tabs: {
|
|
205
|
+
tablist: {
|
|
206
|
+
background: 'transparent',
|
|
207
|
+
borderWidth: '0 0 1px 0'
|
|
208
|
+
},
|
|
209
|
+
tab: {
|
|
210
|
+
background: 'transparent',
|
|
211
|
+
borderColor: 'transparent',
|
|
212
|
+
activeBorderColor: 'transparent',
|
|
213
|
+
borderWidth: '0',
|
|
214
|
+
padding: '0.5rem 1rem',
|
|
215
|
+
margin: '0 0 0.5rem 0'
|
|
216
|
+
},
|
|
217
|
+
tabpanel: {
|
|
218
|
+
background: 'transparent',
|
|
219
|
+
padding: '0'
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
dataview: {
|
|
223
|
+
header: {
|
|
224
|
+
background: 'transparent',
|
|
225
|
+
borderWidth: '0',
|
|
226
|
+
padding: '0'
|
|
227
|
+
},
|
|
228
|
+
content: {
|
|
229
|
+
background: 'transparent',
|
|
230
|
+
padding: '0'
|
|
231
|
+
}
|
|
232
|
+
},
|
|
174
233
|
paginator: {
|
|
175
234
|
root: {
|
|
176
235
|
background: 'transparent'
|
|
177
236
|
}
|
|
178
237
|
},
|
|
238
|
+
fileupload: {
|
|
239
|
+
root: {
|
|
240
|
+
background: 'transparent'
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
panel: {
|
|
244
|
+
root: {
|
|
245
|
+
background: 'transparent',
|
|
246
|
+
borderColor: 'transparent',
|
|
247
|
+
borderRadius: '0'
|
|
248
|
+
},
|
|
249
|
+
header: {
|
|
250
|
+
background: 'transparent',
|
|
251
|
+
padding: '0',
|
|
252
|
+
borderWidth: '0'
|
|
253
|
+
},
|
|
254
|
+
toggleableHeader: {
|
|
255
|
+
padding: '0'
|
|
256
|
+
},
|
|
257
|
+
title: {
|
|
258
|
+
fontWeight: '700'
|
|
259
|
+
},
|
|
260
|
+
content: {
|
|
261
|
+
padding: '0'
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
card: {
|
|
265
|
+
root: {
|
|
266
|
+
shadow: 'none',
|
|
267
|
+
borderRadius: '{border.radius.xl}'
|
|
268
|
+
},
|
|
269
|
+
body: {
|
|
270
|
+
padding: '1.25rem',
|
|
271
|
+
gap: '1rem'
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
avatar: {
|
|
275
|
+
root: {
|
|
276
|
+
borderRadius: '9999px',
|
|
277
|
+
fontSize: '0.875rem'
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
drawer: {
|
|
281
|
+
content: { padding: '1.25rem' }
|
|
282
|
+
},
|
|
283
|
+
inputtext: {
|
|
284
|
+
root: {
|
|
285
|
+
borderRadius: '{border.radius.xl}',
|
|
286
|
+
paddingY: '0.5rem'
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
divider: {
|
|
290
|
+
horizontal: {
|
|
291
|
+
margin: '0',
|
|
292
|
+
padding: '0',
|
|
293
|
+
content: { padding: '0 0.5rem' }
|
|
294
|
+
},
|
|
295
|
+
vertical: {
|
|
296
|
+
margin: '0',
|
|
297
|
+
padding: '0',
|
|
298
|
+
content: { padding: '0.5rem 0' }
|
|
299
|
+
}
|
|
300
|
+
},
|
|
179
301
|
tag: {
|
|
180
302
|
root: {
|
|
181
303
|
padding: '0.25rem 0.5rem',
|
|
@@ -185,22 +307,47 @@ const brandOverrides = {
|
|
|
185
307
|
light: {
|
|
186
308
|
secondary: { color: '{surface.800}' },
|
|
187
309
|
success: { color: '{green.800}' },
|
|
188
|
-
active: { color: '{green.800}' },
|
|
189
|
-
inactive: { color: '{gray.800}' },
|
|
190
310
|
info: { color: '{blue.800}' },
|
|
191
311
|
warn: { color: '{orange.800}' },
|
|
192
|
-
|
|
312
|
+
danger: { color: '{red.800}' }
|
|
193
313
|
},
|
|
194
314
|
dark: {
|
|
195
315
|
secondary: { color: '{surface.100}' },
|
|
196
316
|
success: { color: '{green.100}' },
|
|
197
|
-
active: { color: '{green.100}' },
|
|
198
317
|
info: { color: '{blue.100}' },
|
|
199
|
-
inactive: { color: '{gray.100}' },
|
|
200
318
|
warn: { color: '{orange.100}' },
|
|
201
|
-
|
|
319
|
+
danger: { color: '{red.100}' }
|
|
202
320
|
}
|
|
203
321
|
}
|
|
322
|
+
},
|
|
323
|
+
toolbar: {
|
|
324
|
+
root: {
|
|
325
|
+
background: 'transparent',
|
|
326
|
+
borderColor: 'transparent',
|
|
327
|
+
borderRadius: '0',
|
|
328
|
+
padding: '0',
|
|
329
|
+
gap: '0.5rem'
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
progressbar: {
|
|
333
|
+
root: {
|
|
334
|
+
borderRadius: '{border.radius.lg}',
|
|
335
|
+
height: '0.75rem'
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
message: {
|
|
339
|
+
root: {
|
|
340
|
+
borderRadius: '{border.radius.lg}',
|
|
341
|
+
borderWidth: '0 0 0 4px'
|
|
342
|
+
},
|
|
343
|
+
content: {
|
|
344
|
+
padding: '0.75rem 1rem',
|
|
345
|
+
gap: '0.5rem'
|
|
346
|
+
},
|
|
347
|
+
text: {
|
|
348
|
+
fontSize: '0.875rem',
|
|
349
|
+
fontWeight: '500'
|
|
350
|
+
}
|
|
204
351
|
}
|
|
205
352
|
}
|
|
206
353
|
};
|
|
@@ -390,6 +537,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
390
537
|
}]
|
|
391
538
|
}], ctorParameters: () => [] });
|
|
392
539
|
|
|
540
|
+
class FooterService {
|
|
541
|
+
content = signal(null, ...(ngDevMode ? [{ debugName: "content" }] : []));
|
|
542
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FooterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
543
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FooterService, providedIn: 'root' });
|
|
544
|
+
}
|
|
545
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FooterService, decorators: [{
|
|
546
|
+
type: Injectable,
|
|
547
|
+
args: [{ providedIn: 'root' }]
|
|
548
|
+
}] });
|
|
549
|
+
|
|
393
550
|
class AppBreadcrumb {
|
|
394
551
|
router;
|
|
395
552
|
_breadcrumbs$ = new BehaviorSubject([]);
|
|
@@ -462,11 +619,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
462
619
|
class AppConfigurator {
|
|
463
620
|
simple = false;
|
|
464
621
|
location = 'app';
|
|
465
|
-
router = inject(Router);
|
|
466
622
|
config = inject(PrimeNG);
|
|
467
623
|
layoutService = inject(LayoutService);
|
|
468
624
|
platformId = inject(PLATFORM_ID);
|
|
469
|
-
primeng = inject(PrimeNG);
|
|
470
625
|
presetKeys = Object.keys(brandPresets);
|
|
471
626
|
themeOptions = [
|
|
472
627
|
{ name: 'Light', value: false },
|
|
@@ -494,42 +649,10 @@ class AppConfigurator {
|
|
|
494
649
|
];
|
|
495
650
|
}
|
|
496
651
|
}
|
|
497
|
-
surfaces = [
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
0: '#ffffff',
|
|
502
|
-
50: '#e5e6e6',
|
|
503
|
-
100: '#d5d6d7',
|
|
504
|
-
200: '#c6c7c8',
|
|
505
|
-
300: '#b6b8b9',
|
|
506
|
-
400: '#a7a8aa',
|
|
507
|
-
500: '#97999b',
|
|
508
|
-
600: '#808284',
|
|
509
|
-
700: '#6a6b6d',
|
|
510
|
-
800: '#535455',
|
|
511
|
-
900: '#3c3d3e',
|
|
512
|
-
950: '#262627'
|
|
513
|
-
}
|
|
514
|
-
},
|
|
515
|
-
{
|
|
516
|
-
name: 'darkblue',
|
|
517
|
-
palette: {
|
|
518
|
-
0: '#ffffff',
|
|
519
|
-
50: '#D0EEFF',
|
|
520
|
-
100: '#B7E2F9',
|
|
521
|
-
200: '#73abc7',
|
|
522
|
-
300: '#73abc7',
|
|
523
|
-
400: '#4d94b8',
|
|
524
|
-
500: '#267da9',
|
|
525
|
-
600: '#00669a',
|
|
526
|
-
700: '#005783',
|
|
527
|
-
800: '#00476c',
|
|
528
|
-
900: '#00293e',
|
|
529
|
-
950: '#001a27'
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
];
|
|
652
|
+
surfaces = ['gray', 'darkblue'].map(name => ({
|
|
653
|
+
name,
|
|
654
|
+
palette: { 0: '#ffffff', ...brandPrimitives[name] }
|
|
655
|
+
}));
|
|
533
656
|
selectedPrimaryColor = computed(() => {
|
|
534
657
|
return this.layoutService.layoutConfig().primary;
|
|
535
658
|
}, ...(ngDevMode ? [{ debugName: "selectedPrimaryColor" }] : []));
|
|
@@ -795,12 +918,12 @@ class AppConfigurator {
|
|
|
795
918
|
</div>
|
|
796
919
|
<div *ngIf="!simple && location === 'app'" class="flex flex-col gap-2">
|
|
797
920
|
<span class="text-lg text-muted-color font-semibold">Card Style</span>
|
|
798
|
-
<p-selectbutton [ngModel]="cardStyle()" (ngModelChange)="onCardStyleChange($event)" [options]="cardStyleOptions" optionLabel="name" optionValue="value" [allowEmpty]="false"
|
|
921
|
+
<p-selectbutton [ngModel]="cardStyle()" (ngModelChange)="onCardStyleChange($event)" [options]="cardStyleOptions" optionLabel="name" optionValue="value" [allowEmpty]="false" />
|
|
799
922
|
</div>
|
|
800
923
|
|
|
801
924
|
<div *ngIf="!simple && location === 'app'" class="flex flex-col gap-2">
|
|
802
925
|
<span class="text-lg text-muted-color font-semibold">Menu Theme</span>
|
|
803
|
-
<p-selectbutton [ngModel]="menuTheme()" (ngModelChange)="onMenuThemeChange($event)" [options]="menuThemeOptions" optionLabel="name" optionValue="value" [allowEmpty]="false"
|
|
926
|
+
<p-selectbutton [ngModel]="menuTheme()" (ngModelChange)="onMenuThemeChange($event)" [options]="menuThemeOptions" optionLabel="name" optionValue="value" [allowEmpty]="false" />
|
|
804
927
|
</div>
|
|
805
928
|
|
|
806
929
|
<div *ngIf="!simple && location === 'app'">
|
|
@@ -818,30 +941,16 @@ class AppConfigurator {
|
|
|
818
941
|
</div>
|
|
819
942
|
</div>
|
|
820
943
|
<div class="flex">
|
|
821
|
-
<div class="flex items-center gap-2 w-6/12">
|
|
822
|
-
<p-radiobutton name="menuMode" value="overlay" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('overlay')" inputId="overlay"></p-radiobutton>
|
|
823
|
-
<label for="overlay">Overlay</label>
|
|
824
|
-
</div>
|
|
825
944
|
<div class="flex items-center gap-2 w-6/12">
|
|
826
945
|
<p-radiobutton name="menuMode" value="slim" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('slim')" inputId="slim"></p-radiobutton>
|
|
827
946
|
<label for="slim">Slim</label>
|
|
828
947
|
</div>
|
|
829
|
-
</div>
|
|
830
|
-
<div class="flex">
|
|
831
948
|
<div class="flex items-center gap-2 w-6/12">
|
|
832
949
|
<p-radiobutton name="menuMode" value="compact" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('compact')" inputId="compact"></p-radiobutton>
|
|
833
950
|
<label for="compact">Compact</label>
|
|
834
951
|
</div>
|
|
835
|
-
<div class="flex items-center gap-2 w-6/12">
|
|
836
|
-
<p-radiobutton name="menuMode" value="reveal" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('reveal')" inputId="reveal"></p-radiobutton>
|
|
837
|
-
<label for="reveal">Reveal</label>
|
|
838
|
-
</div>
|
|
839
952
|
</div>
|
|
840
953
|
<div class="flex">
|
|
841
|
-
<div class="flex items-center gap-2 w-6/12">
|
|
842
|
-
<p-radiobutton name="menuMode" value="drawer" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('drawer')" inputId="drawer"></p-radiobutton>
|
|
843
|
-
<label for="drawer">Drawer</label>
|
|
844
|
-
</div>
|
|
845
954
|
<div class="flex items-center gap-2 w-6/12">
|
|
846
955
|
<p-radiobutton name="menuMode" value="horizontal" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('horizontal')" inputId="horizontal"></p-radiobutton>
|
|
847
956
|
<label for="horizontal">Horizontal</label>
|
|
@@ -852,13 +961,13 @@ class AppConfigurator {
|
|
|
852
961
|
</div>
|
|
853
962
|
</div>
|
|
854
963
|
</p-drawer>
|
|
855
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type:
|
|
964
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i3.SelectButton, selector: "p-selectButton, p-selectbutton, p-select-button", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "styleClass", "ariaLabelledBy", "dataKey", "autofocus", "size", "fluid"], outputs: ["onOptionClick", "onChange"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i4.Drawer, selector: "p-drawer", inputs: ["appendTo", "motionOptions", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "ngmodule", type: RadioButtonModule }, { kind: "component", type: i5.RadioButton, selector: "p-radioButton, p-radiobutton, p-radio-button", inputs: ["value", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "styleClass", "autofocus", "binary", "variant", "size"], outputs: ["onClick", "onFocus", "onBlur"] }] });
|
|
856
965
|
}
|
|
857
966
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppConfigurator, decorators: [{
|
|
858
967
|
type: Component,
|
|
859
968
|
args: [{
|
|
860
969
|
selector: 'app-configurator',
|
|
861
|
-
imports: [CommonModule, FormsModule, SelectButtonModule, DrawerModule,
|
|
970
|
+
imports: [CommonModule, FormsModule, SelectButtonModule, DrawerModule, RadioButtonModule],
|
|
862
971
|
template: `
|
|
863
972
|
<p-drawer [(visible)]="configSidebarVisible" position="right" [transitionOptions]="'.3s cubic-bezier(0, 0, 0.2, 1)'" styleClass="layout-config-sidebar w-80" header="Settings" appendTo="body">
|
|
864
973
|
<div class="flex flex-col gap-6">
|
|
@@ -913,12 +1022,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
913
1022
|
</div>
|
|
914
1023
|
<div *ngIf="!simple && location === 'app'" class="flex flex-col gap-2">
|
|
915
1024
|
<span class="text-lg text-muted-color font-semibold">Card Style</span>
|
|
916
|
-
<p-selectbutton [ngModel]="cardStyle()" (ngModelChange)="onCardStyleChange($event)" [options]="cardStyleOptions" optionLabel="name" optionValue="value" [allowEmpty]="false"
|
|
1025
|
+
<p-selectbutton [ngModel]="cardStyle()" (ngModelChange)="onCardStyleChange($event)" [options]="cardStyleOptions" optionLabel="name" optionValue="value" [allowEmpty]="false" />
|
|
917
1026
|
</div>
|
|
918
1027
|
|
|
919
1028
|
<div *ngIf="!simple && location === 'app'" class="flex flex-col gap-2">
|
|
920
1029
|
<span class="text-lg text-muted-color font-semibold">Menu Theme</span>
|
|
921
|
-
<p-selectbutton [ngModel]="menuTheme()" (ngModelChange)="onMenuThemeChange($event)" [options]="menuThemeOptions" optionLabel="name" optionValue="value" [allowEmpty]="false"
|
|
1030
|
+
<p-selectbutton [ngModel]="menuTheme()" (ngModelChange)="onMenuThemeChange($event)" [options]="menuThemeOptions" optionLabel="name" optionValue="value" [allowEmpty]="false" />
|
|
922
1031
|
</div>
|
|
923
1032
|
|
|
924
1033
|
<div *ngIf="!simple && location === 'app'">
|
|
@@ -936,30 +1045,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
936
1045
|
</div>
|
|
937
1046
|
</div>
|
|
938
1047
|
<div class="flex">
|
|
939
|
-
<div class="flex items-center gap-2 w-6/12">
|
|
940
|
-
<p-radiobutton name="menuMode" value="overlay" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('overlay')" inputId="overlay"></p-radiobutton>
|
|
941
|
-
<label for="overlay">Overlay</label>
|
|
942
|
-
</div>
|
|
943
1048
|
<div class="flex items-center gap-2 w-6/12">
|
|
944
1049
|
<p-radiobutton name="menuMode" value="slim" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('slim')" inputId="slim"></p-radiobutton>
|
|
945
1050
|
<label for="slim">Slim</label>
|
|
946
1051
|
</div>
|
|
947
|
-
</div>
|
|
948
|
-
<div class="flex">
|
|
949
1052
|
<div class="flex items-center gap-2 w-6/12">
|
|
950
1053
|
<p-radiobutton name="menuMode" value="compact" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('compact')" inputId="compact"></p-radiobutton>
|
|
951
1054
|
<label for="compact">Compact</label>
|
|
952
1055
|
</div>
|
|
953
|
-
<div class="flex items-center gap-2 w-6/12">
|
|
954
|
-
<p-radiobutton name="menuMode" value="reveal" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('reveal')" inputId="reveal"></p-radiobutton>
|
|
955
|
-
<label for="reveal">Reveal</label>
|
|
956
|
-
</div>
|
|
957
1056
|
</div>
|
|
958
1057
|
<div class="flex">
|
|
959
|
-
<div class="flex items-center gap-2 w-6/12">
|
|
960
|
-
<p-radiobutton name="menuMode" value="drawer" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('drawer')" inputId="drawer"></p-radiobutton>
|
|
961
|
-
<label for="drawer">Drawer</label>
|
|
962
|
-
</div>
|
|
963
1058
|
<div class="flex items-center gap-2 w-6/12">
|
|
964
1059
|
<p-radiobutton name="menuMode" value="horizontal" [ngModel]="menuMode()" (ngModelChange)="setMenuMode('horizontal')" inputId="horizontal"></p-radiobutton>
|
|
965
1060
|
<label for="horizontal">Horizontal</label>
|
|
@@ -979,26 +1074,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
979
1074
|
type: Input
|
|
980
1075
|
}], cardStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "cardStyle", required: false }] }, { type: i0.Output, args: ["cardStyleChange"] }] } });
|
|
981
1076
|
|
|
982
|
-
class AppFooter {
|
|
983
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppFooter, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
984
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: AppFooter, isStandalone: true, selector: "[app-footer]", ngImport: i0, template: `
|
|
985
|
-
<footer class="layout-footer">
|
|
986
|
-
<span class="footer-copyright">© UNOPS 2026</span>
|
|
987
|
-
</footer>
|
|
988
|
-
`, isInline: true });
|
|
989
|
-
}
|
|
990
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppFooter, decorators: [{
|
|
991
|
-
type: Component,
|
|
992
|
-
args: [{
|
|
993
|
-
selector: '[app-footer]',
|
|
994
|
-
template: `
|
|
995
|
-
<footer class="layout-footer">
|
|
996
|
-
<span class="footer-copyright">© UNOPS 2026</span>
|
|
997
|
-
</footer>
|
|
998
|
-
`
|
|
999
|
-
}]
|
|
1000
|
-
}] });
|
|
1001
|
-
|
|
1002
1077
|
class AppRightMenu {
|
|
1003
1078
|
layoutService = inject(LayoutService);
|
|
1004
1079
|
cards = [
|
|
@@ -1020,7 +1095,7 @@ class AppRightMenu {
|
|
|
1020
1095
|
<div class="flex flex-col mt-7">
|
|
1021
1096
|
<div class="flex gap-6">
|
|
1022
1097
|
<div class="flex flex-col items-center">
|
|
1023
|
-
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-
|
|
1098
|
+
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-subtle">
|
|
1024
1099
|
<i class="pi pi-dollar text-blue-600 text-2xl!"></i>
|
|
1025
1100
|
</span>
|
|
1026
1101
|
<span class="min-h-14 w-px bg-(--surface-border)"></span>
|
|
@@ -1032,7 +1107,7 @@ class AppRightMenu {
|
|
|
1032
1107
|
</div>
|
|
1033
1108
|
<div class="flex gap-6">
|
|
1034
1109
|
<div class="flex flex-col items-center">
|
|
1035
|
-
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-
|
|
1110
|
+
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-subtle">
|
|
1036
1111
|
<i class="pi pi-download text-orange-600 text-2xl!"></i>
|
|
1037
1112
|
</span>
|
|
1038
1113
|
<span class="min-h-14 w-px bg-(--surface-border)"></span>
|
|
@@ -1044,7 +1119,7 @@ class AppRightMenu {
|
|
|
1044
1119
|
</div>
|
|
1045
1120
|
<div class="flex gap-6">
|
|
1046
1121
|
<div class="flex flex-col items-center">
|
|
1047
|
-
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-
|
|
1122
|
+
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-subtle">
|
|
1048
1123
|
<i class="pi pi-question-circle text-violet-600 text-2xl!"></i>
|
|
1049
1124
|
</span>
|
|
1050
1125
|
<span class="min-h-14 w-px bg-(--surface-border)"></span>
|
|
@@ -1056,7 +1131,7 @@ class AppRightMenu {
|
|
|
1056
1131
|
</div>
|
|
1057
1132
|
<div class="flex gap-6">
|
|
1058
1133
|
<div class="flex flex-col items-center">
|
|
1059
|
-
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-
|
|
1134
|
+
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-subtle">
|
|
1060
1135
|
<i class="pi pi-comment text-blue-600 text-2xl!"></i>
|
|
1061
1136
|
</span>
|
|
1062
1137
|
</div>
|
|
@@ -1082,7 +1157,7 @@ class AppRightMenu {
|
|
|
1082
1157
|
<p class="body-small mt-1 text-left">Track your ongoing shipments to customers.</p>
|
|
1083
1158
|
<img class="w-full h-full max-h-60 object-cover border border-surface rounded-2xl mt-4" src="layout/images/sidebar-right/staticmap.png" alt="unops-ng_ux" />
|
|
1084
1159
|
</div>
|
|
1085
|
-
</p-drawer>`, isInline: true, dependencies: [{ kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i4.Drawer, selector: "p-drawer", inputs: ["appendTo", "motionOptions", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i2.Divider, selector: "p-divider", inputs: ["styleClass", "layout", "type", "align"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type:
|
|
1160
|
+
</p-drawer>`, isInline: true, dependencies: [{ kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i4.Drawer, selector: "p-drawer", inputs: ["appendTo", "motionOptions", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i2.Divider, selector: "p-divider", inputs: ["styleClass", "layout", "type", "align"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2$1.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }] });
|
|
1086
1161
|
}
|
|
1087
1162
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppRightMenu, decorators: [{
|
|
1088
1163
|
type: Component,
|
|
@@ -1095,7 +1170,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
1095
1170
|
<div class="flex flex-col mt-7">
|
|
1096
1171
|
<div class="flex gap-6">
|
|
1097
1172
|
<div class="flex flex-col items-center">
|
|
1098
|
-
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-
|
|
1173
|
+
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-subtle">
|
|
1099
1174
|
<i class="pi pi-dollar text-blue-600 text-2xl!"></i>
|
|
1100
1175
|
</span>
|
|
1101
1176
|
<span class="min-h-14 w-px bg-(--surface-border)"></span>
|
|
@@ -1107,7 +1182,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
1107
1182
|
</div>
|
|
1108
1183
|
<div class="flex gap-6">
|
|
1109
1184
|
<div class="flex flex-col items-center">
|
|
1110
|
-
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-
|
|
1185
|
+
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-subtle">
|
|
1111
1186
|
<i class="pi pi-download text-orange-600 text-2xl!"></i>
|
|
1112
1187
|
</span>
|
|
1113
1188
|
<span class="min-h-14 w-px bg-(--surface-border)"></span>
|
|
@@ -1119,7 +1194,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
1119
1194
|
</div>
|
|
1120
1195
|
<div class="flex gap-6">
|
|
1121
1196
|
<div class="flex flex-col items-center">
|
|
1122
|
-
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-
|
|
1197
|
+
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-subtle">
|
|
1123
1198
|
<i class="pi pi-question-circle text-violet-600 text-2xl!"></i>
|
|
1124
1199
|
</span>
|
|
1125
1200
|
<span class="min-h-14 w-px bg-(--surface-border)"></span>
|
|
@@ -1131,7 +1206,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
1131
1206
|
</div>
|
|
1132
1207
|
<div class="flex gap-6">
|
|
1133
1208
|
<div class="flex flex-col items-center">
|
|
1134
|
-
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-
|
|
1209
|
+
<span class="w-14 h-14 flex items-center justify-center border border-surface rounded-xl shadow-subtle">
|
|
1135
1210
|
<i class="pi pi-comment text-blue-600 text-2xl!"></i>
|
|
1136
1211
|
</span>
|
|
1137
1212
|
</div>
|
|
@@ -1173,21 +1248,21 @@ class AppSearch {
|
|
|
1173
1248
|
this.layoutService.layoutState.update((prev) => ({ ...prev, searchBarActive: _val }));
|
|
1174
1249
|
}
|
|
1175
1250
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppSearch, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1176
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: AppSearch, isStandalone: true, selector: "[app-search]", ngImport: i0, template: ` <p-dialog [(visible)]="searchBarActive" [breakpoints]="{ '
|
|
1251
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: AppSearch, isStandalone: true, selector: "[app-search]", ngImport: i0, template: ` <p-dialog [(visible)]="searchBarActive" [breakpoints]="{ '1024px': '75vw', '780px': '90vw' }" modal dismissableMask styleClass="w-1/2 search-container">
|
|
1177
1252
|
<ng-template #headless>
|
|
1178
1253
|
<div class="w-full">
|
|
1179
1254
|
<i class="pi pi-search"></i>
|
|
1180
1255
|
<input pInputText type="text" [pAutoFocus]="true" class="p-inputtext search-input" placeholder="Search" (keydown.enter)="toggleSearchBar()" />
|
|
1181
1256
|
</div>
|
|
1182
1257
|
</ng-template>
|
|
1183
|
-
</p-dialog>`, isInline: true, dependencies: [{ kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1$
|
|
1258
|
+
</p-dialog>`, isInline: true, dependencies: [{ kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1$3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: AutoFocusModule }, { kind: "directive", type: i3$2.AutoFocus, selector: "[pAutoFocus]", inputs: ["pAutoFocus"] }] });
|
|
1184
1259
|
}
|
|
1185
1260
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppSearch, decorators: [{
|
|
1186
1261
|
type: Component,
|
|
1187
1262
|
args: [{
|
|
1188
1263
|
selector: '[app-search]',
|
|
1189
1264
|
imports: [DialogModule, InputTextModule, AutoFocusModule],
|
|
1190
|
-
template: ` <p-dialog [(visible)]="searchBarActive" [breakpoints]="{ '
|
|
1265
|
+
template: ` <p-dialog [(visible)]="searchBarActive" [breakpoints]="{ '1024px': '75vw', '780px': '90vw' }" modal dismissableMask styleClass="w-1/2 search-container">
|
|
1191
1266
|
<ng-template #headless>
|
|
1192
1267
|
<div class="w-full">
|
|
1193
1268
|
<i class="pi pi-search"></i>
|
|
@@ -1198,6 +1273,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
1198
1273
|
}]
|
|
1199
1274
|
}] });
|
|
1200
1275
|
|
|
1276
|
+
class FooterMainComponent {
|
|
1277
|
+
/** When true, always shows the default copyright — ignores FooterService content. */
|
|
1278
|
+
copyrightOnly = input(false, ...(ngDevMode ? [{ debugName: "copyrightOnly" }] : []));
|
|
1279
|
+
footerService = inject(FooterService);
|
|
1280
|
+
copyrightYear = new Date().getFullYear();
|
|
1281
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FooterMainComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1282
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: FooterMainComponent, isStandalone: true, selector: "ux-footer-main", inputs: { copyrightOnly: { classPropertyName: "copyrightOnly", publicName: "copyrightOnly", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "ux-footer-main" }, ngImport: i0, template: `
|
|
1283
|
+
<div class="footer-inner">
|
|
1284
|
+
@if (copyrightOnly()) {
|
|
1285
|
+
<span>© UNOPS {{ copyrightYear }}</span>
|
|
1286
|
+
} @else if (footerService.content(); as tpl) {
|
|
1287
|
+
<ng-container [ngTemplateOutlet]="tpl" />
|
|
1288
|
+
}
|
|
1289
|
+
</div>
|
|
1290
|
+
`, isInline: true, styles: [":host{flex-shrink:0;display:flex;align-items:center;height:3rem;background:var(--p-primary-50);font-size:var(--font-size-xs, .75rem);line-height:1.2;color:var(--p-text-color)}:host-context(:root[class*=\"app-dark\"]){background:var(--p-primary-950);color:var(--p-surface-100)}:host(.footer-sticky){position:sticky;bottom:0;z-index:10}.footer-inner{width:100%;max-width:1540px;margin-inline:auto;padding:1rem}@media screen and (min-width:780px){.footer-inner{padding:1rem 3rem}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1291
|
+
}
|
|
1292
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FooterMainComponent, decorators: [{
|
|
1293
|
+
type: Component,
|
|
1294
|
+
args: [{ selector: 'ux-footer-main', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet], host: { class: 'ux-footer-main' }, template: `
|
|
1295
|
+
<div class="footer-inner">
|
|
1296
|
+
@if (copyrightOnly()) {
|
|
1297
|
+
<span>© UNOPS {{ copyrightYear }}</span>
|
|
1298
|
+
} @else if (footerService.content(); as tpl) {
|
|
1299
|
+
<ng-container [ngTemplateOutlet]="tpl" />
|
|
1300
|
+
}
|
|
1301
|
+
</div>
|
|
1302
|
+
`, styles: [":host{flex-shrink:0;display:flex;align-items:center;height:3rem;background:var(--p-primary-50);font-size:var(--font-size-xs, .75rem);line-height:1.2;color:var(--p-text-color)}:host-context(:root[class*=\"app-dark\"]){background:var(--p-primary-950);color:var(--p-surface-100)}:host(.footer-sticky){position:sticky;bottom:0;z-index:10}.footer-inner{width:100%;max-width:1540px;margin-inline:auto;padding:1rem}@media screen and (min-width:780px){.footer-inner{padding:1rem 3rem}}\n"] }]
|
|
1303
|
+
}], propDecorators: { copyrightOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyrightOnly", required: false }] }] } });
|
|
1304
|
+
|
|
1201
1305
|
class AppMenuitem {
|
|
1202
1306
|
layoutService = inject(LayoutService);
|
|
1203
1307
|
router = inject(Router);
|
|
@@ -1677,19 +1781,24 @@ class AppTopbar {
|
|
|
1677
1781
|
<i class="pi pi-bars"></i>
|
|
1678
1782
|
</button>
|
|
1679
1783
|
<div class="topbar-left">
|
|
1680
|
-
<
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
<
|
|
1691
|
-
|
|
1692
|
-
|
|
1784
|
+
<div class="topbar-sidebar-section">
|
|
1785
|
+
<button
|
|
1786
|
+
type="button"
|
|
1787
|
+
class="topbar-menu-toggle"
|
|
1788
|
+
[class.active]="isSidebarPinned()"
|
|
1789
|
+
[attr.aria-label]="isSidebarPinned() ? 'Collapse sidebar' : 'Expand sidebar'"
|
|
1790
|
+
(click)="toggleSidebarPin()"
|
|
1791
|
+
>
|
|
1792
|
+
<i class="pi pi-bars"></i>
|
|
1793
|
+
</button>
|
|
1794
|
+
<a class="topbar-logo" [routerLink]="['/']">
|
|
1795
|
+
<img [src]="desktopLogo()" [attr.alt]="mobileLogoConfig.alt" />
|
|
1796
|
+
</a>
|
|
1797
|
+
<span class="topbar-logo-separator"></span>
|
|
1798
|
+
</div>
|
|
1799
|
+
</div>
|
|
1800
|
+
|
|
1801
|
+
<div class="topbar-main">
|
|
1693
1802
|
<div app-breadcrumb></div>
|
|
1694
1803
|
@if (searchActive()) {
|
|
1695
1804
|
<div class="flex items-center gap-2 ml-auto">
|
|
@@ -1702,14 +1811,8 @@ class AppTopbar {
|
|
|
1702
1811
|
</button>
|
|
1703
1812
|
</div>
|
|
1704
1813
|
}
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
<a class="mobile-logo" [routerLink]="['/landing']">
|
|
1708
|
-
<img [src]="mobileLogo()" [attr.alt]="mobileLogoConfig.alt" />
|
|
1709
|
-
</a>
|
|
1710
|
-
|
|
1711
|
-
<div class="topbar-right">
|
|
1712
|
-
<ul class="topbar-menu">
|
|
1814
|
+
<div class="topbar-right">
|
|
1815
|
+
<ul class="topbar-menu">
|
|
1713
1816
|
<li class="right-sidebar-item" [class.hidden]="searchActive()">
|
|
1714
1817
|
<a class="right-sidebar-button" aria-label="Open search" (click)="openSearch()">
|
|
1715
1818
|
<i class="pi pi-search"></i>
|
|
@@ -1730,11 +1833,11 @@ class AppTopbar {
|
|
|
1730
1833
|
<i class="pi pi-bell"></i>
|
|
1731
1834
|
</a>
|
|
1732
1835
|
<div
|
|
1733
|
-
class="list-none m-0 rounded-2xl border border-surface fixed sm:absolute bg-surface-0 dark:bg-surface-900 overflow-hidden hidden origin-top w-[calc(100vw-2rem)] sm:w-88 mt-2 z-50 top-auto left-4 sm:left-auto sm:right-0 shadow-
|
|
1836
|
+
class="list-none m-0 rounded-2xl border border-surface fixed sm:absolute bg-surface-0 dark:bg-surface-900 overflow-hidden hidden origin-top w-[calc(100vw-2rem)] sm:w-88 mt-2 z-50 top-auto left-4 sm:left-auto sm:right-0 shadow-flyout"
|
|
1734
1837
|
>
|
|
1735
1838
|
<div class="p-4 flex items-center justify-between border-b border-surface">
|
|
1736
1839
|
<span class="label-small text-surface-950 dark:text-surface-0">Notifications</span>
|
|
1737
|
-
<button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-
|
|
1840
|
+
<button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-subtle transition-all">Mark all as read</button>
|
|
1738
1841
|
</div>
|
|
1739
1842
|
<div class="flex items-center border-b border-surface">
|
|
1740
1843
|
@for (item of notificationsBars(); track item.id; let i = $index) {
|
|
@@ -1784,7 +1887,7 @@ class AppTopbar {
|
|
|
1784
1887
|
</svg>
|
|
1785
1888
|
</a>
|
|
1786
1889
|
<div
|
|
1787
|
-
class="list-none p-2 m-0 rounded-2xl border border-surface overflow-hidden fixed sm:absolute bg-surface-0 dark:bg-surface-900 hidden origin-top w-44 mt-2 right-4 sm:right-0 z-999 top-auto shadow-
|
|
1890
|
+
class="list-none p-2 m-0 rounded-2xl border border-surface overflow-hidden fixed sm:absolute bg-surface-0 dark:bg-surface-900 hidden origin-top w-44 mt-2 right-4 sm:right-0 z-999 top-auto shadow-flyout"
|
|
1788
1891
|
>
|
|
1789
1892
|
<ul class="flex flex-col gap-1">
|
|
1790
1893
|
@for (lang of languages(); track lang.code) {
|
|
@@ -1810,7 +1913,7 @@ class AppTopbar {
|
|
|
1810
1913
|
</a>
|
|
1811
1914
|
<div
|
|
1812
1915
|
#profilePanel
|
|
1813
|
-
class="list-none p-2 m-0 rounded-2xl border border-surface overflow-hidden fixed sm:absolute bg-surface-0 dark:bg-surface-900 origin-top w-52 mt-2 right-4 sm:right-0 z-999 top-auto shadow-
|
|
1916
|
+
class="list-none p-2 m-0 rounded-2xl border border-surface overflow-hidden fixed sm:absolute bg-surface-0 dark:bg-surface-900 origin-top w-52 mt-2 right-4 sm:right-0 z-999 top-auto shadow-flyout"
|
|
1814
1917
|
[class.hidden]="!profileMenuOpen()"
|
|
1815
1918
|
[class.animate-scalein]="profileMenuOpen()"
|
|
1816
1919
|
>
|
|
@@ -1861,7 +1964,7 @@ class AppTopbar {
|
|
|
1861
1964
|
</a>
|
|
1862
1965
|
</li>
|
|
1863
1966
|
<li>
|
|
1864
|
-
<a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="profileMenuOpen.set(false)">
|
|
1967
|
+
<a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="profileMenuOpen.set(false); onConfigButtonClick()">
|
|
1865
1968
|
<i class="pi pi-cog"></i>
|
|
1866
1969
|
<span>Settings</span>
|
|
1867
1970
|
</a>
|
|
@@ -1887,9 +1990,14 @@ class AppTopbar {
|
|
|
1887
1990
|
</ul>
|
|
1888
1991
|
</div>
|
|
1889
1992
|
</li>
|
|
1890
|
-
|
|
1993
|
+
</ul>
|
|
1994
|
+
</div>
|
|
1891
1995
|
</div>
|
|
1892
|
-
|
|
1996
|
+
|
|
1997
|
+
<a class="mobile-logo" [routerLink]="['/']">
|
|
1998
|
+
<img [src]="mobileLogo()" [attr.alt]="mobileLogoConfig.alt" />
|
|
1999
|
+
</a>
|
|
2000
|
+
</div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "directive", type: i3$4.StyleClass, selector: "[pStyleClass]", inputs: ["pStyleClass", "enterFromClass", "enterActiveClass", "enterToClass", "leaveFromClass", "leaveActiveClass", "leaveToClass", "hideOnOutsideClick", "toggleClass", "hideOnEscape", "hideOnResize", "resizeSelector"] }, { kind: "component", type: AppBreadcrumb, selector: "[app-breadcrumb]" }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i5$1.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i6.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i4$2.Ripple, selector: "[pRipple]" }, { kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i8.Badge, selector: "p-badge", inputs: ["styleClass", "badgeSize", "size", "severity", "value", "badgeDisabled"] }, { kind: "ngmodule", type: OverlayBadgeModule }, { kind: "component", type: i9.OverlayBadge, selector: "p-overlayBadge, p-overlay-badge, p-overlaybadge", inputs: ["styleClass", "style", "badgeSize", "severity", "value", "badgeDisabled", "size"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i10.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }] });
|
|
1893
2001
|
}
|
|
1894
2002
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppTopbar, decorators: [{
|
|
1895
2003
|
type: Component,
|
|
@@ -1901,19 +2009,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
1901
2009
|
<i class="pi pi-bars"></i>
|
|
1902
2010
|
</button>
|
|
1903
2011
|
<div class="topbar-left">
|
|
1904
|
-
<
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
<
|
|
1915
|
-
|
|
1916
|
-
|
|
2012
|
+
<div class="topbar-sidebar-section">
|
|
2013
|
+
<button
|
|
2014
|
+
type="button"
|
|
2015
|
+
class="topbar-menu-toggle"
|
|
2016
|
+
[class.active]="isSidebarPinned()"
|
|
2017
|
+
[attr.aria-label]="isSidebarPinned() ? 'Collapse sidebar' : 'Expand sidebar'"
|
|
2018
|
+
(click)="toggleSidebarPin()"
|
|
2019
|
+
>
|
|
2020
|
+
<i class="pi pi-bars"></i>
|
|
2021
|
+
</button>
|
|
2022
|
+
<a class="topbar-logo" [routerLink]="['/']">
|
|
2023
|
+
<img [src]="desktopLogo()" [attr.alt]="mobileLogoConfig.alt" />
|
|
2024
|
+
</a>
|
|
2025
|
+
<span class="topbar-logo-separator"></span>
|
|
2026
|
+
</div>
|
|
2027
|
+
</div>
|
|
2028
|
+
|
|
2029
|
+
<div class="topbar-main">
|
|
1917
2030
|
<div app-breadcrumb></div>
|
|
1918
2031
|
@if (searchActive()) {
|
|
1919
2032
|
<div class="flex items-center gap-2 ml-auto">
|
|
@@ -1926,14 +2039,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
1926
2039
|
</button>
|
|
1927
2040
|
</div>
|
|
1928
2041
|
}
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
<a class="mobile-logo" [routerLink]="['/landing']">
|
|
1932
|
-
<img [src]="mobileLogo()" [attr.alt]="mobileLogoConfig.alt" />
|
|
1933
|
-
</a>
|
|
1934
|
-
|
|
1935
|
-
<div class="topbar-right">
|
|
1936
|
-
<ul class="topbar-menu">
|
|
2042
|
+
<div class="topbar-right">
|
|
2043
|
+
<ul class="topbar-menu">
|
|
1937
2044
|
<li class="right-sidebar-item" [class.hidden]="searchActive()">
|
|
1938
2045
|
<a class="right-sidebar-button" aria-label="Open search" (click)="openSearch()">
|
|
1939
2046
|
<i class="pi pi-search"></i>
|
|
@@ -1954,11 +2061,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
1954
2061
|
<i class="pi pi-bell"></i>
|
|
1955
2062
|
</a>
|
|
1956
2063
|
<div
|
|
1957
|
-
class="list-none m-0 rounded-2xl border border-surface fixed sm:absolute bg-surface-0 dark:bg-surface-900 overflow-hidden hidden origin-top w-[calc(100vw-2rem)] sm:w-88 mt-2 z-50 top-auto left-4 sm:left-auto sm:right-0 shadow-
|
|
2064
|
+
class="list-none m-0 rounded-2xl border border-surface fixed sm:absolute bg-surface-0 dark:bg-surface-900 overflow-hidden hidden origin-top w-[calc(100vw-2rem)] sm:w-88 mt-2 z-50 top-auto left-4 sm:left-auto sm:right-0 shadow-flyout"
|
|
1958
2065
|
>
|
|
1959
2066
|
<div class="p-4 flex items-center justify-between border-b border-surface">
|
|
1960
2067
|
<span class="label-small text-surface-950 dark:text-surface-0">Notifications</span>
|
|
1961
|
-
<button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-
|
|
2068
|
+
<button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-subtle transition-all">Mark all as read</button>
|
|
1962
2069
|
</div>
|
|
1963
2070
|
<div class="flex items-center border-b border-surface">
|
|
1964
2071
|
@for (item of notificationsBars(); track item.id; let i = $index) {
|
|
@@ -2008,7 +2115,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2008
2115
|
</svg>
|
|
2009
2116
|
</a>
|
|
2010
2117
|
<div
|
|
2011
|
-
class="list-none p-2 m-0 rounded-2xl border border-surface overflow-hidden fixed sm:absolute bg-surface-0 dark:bg-surface-900 hidden origin-top w-44 mt-2 right-4 sm:right-0 z-999 top-auto shadow-
|
|
2118
|
+
class="list-none p-2 m-0 rounded-2xl border border-surface overflow-hidden fixed sm:absolute bg-surface-0 dark:bg-surface-900 hidden origin-top w-44 mt-2 right-4 sm:right-0 z-999 top-auto shadow-flyout"
|
|
2012
2119
|
>
|
|
2013
2120
|
<ul class="flex flex-col gap-1">
|
|
2014
2121
|
@for (lang of languages(); track lang.code) {
|
|
@@ -2034,7 +2141,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2034
2141
|
</a>
|
|
2035
2142
|
<div
|
|
2036
2143
|
#profilePanel
|
|
2037
|
-
class="list-none p-2 m-0 rounded-2xl border border-surface overflow-hidden fixed sm:absolute bg-surface-0 dark:bg-surface-900 origin-top w-52 mt-2 right-4 sm:right-0 z-999 top-auto shadow-
|
|
2144
|
+
class="list-none p-2 m-0 rounded-2xl border border-surface overflow-hidden fixed sm:absolute bg-surface-0 dark:bg-surface-900 origin-top w-52 mt-2 right-4 sm:right-0 z-999 top-auto shadow-flyout"
|
|
2038
2145
|
[class.hidden]="!profileMenuOpen()"
|
|
2039
2146
|
[class.animate-scalein]="profileMenuOpen()"
|
|
2040
2147
|
>
|
|
@@ -2085,7 +2192,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2085
2192
|
</a>
|
|
2086
2193
|
</li>
|
|
2087
2194
|
<li>
|
|
2088
|
-
<a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="profileMenuOpen.set(false)">
|
|
2195
|
+
<a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="profileMenuOpen.set(false); onConfigButtonClick()">
|
|
2089
2196
|
<i class="pi pi-cog"></i>
|
|
2090
2197
|
<span>Settings</span>
|
|
2091
2198
|
</a>
|
|
@@ -2111,8 +2218,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2111
2218
|
</ul>
|
|
2112
2219
|
</div>
|
|
2113
2220
|
</li>
|
|
2114
|
-
|
|
2221
|
+
</ul>
|
|
2222
|
+
</div>
|
|
2115
2223
|
</div>
|
|
2224
|
+
|
|
2225
|
+
<a class="mobile-logo" [routerLink]="['/']">
|
|
2226
|
+
<img [src]="mobileLogo()" [attr.alt]="mobileLogoConfig.alt" />
|
|
2227
|
+
</a>
|
|
2116
2228
|
</div>`
|
|
2117
2229
|
}]
|
|
2118
2230
|
}], propDecorators: { menuButton: [{
|
|
@@ -2132,7 +2244,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2132
2244
|
args: ['document:click', ['$event']]
|
|
2133
2245
|
}] } });
|
|
2134
2246
|
|
|
2135
|
-
const BREAKPOINT =
|
|
2247
|
+
const BREAKPOINT = 1024;
|
|
2136
2248
|
class AppSidebar {
|
|
2137
2249
|
layoutService = inject(LayoutService);
|
|
2138
2250
|
router = inject(Router);
|
|
@@ -2339,22 +2451,28 @@ class AppSidebar {
|
|
|
2339
2451
|
}
|
|
2340
2452
|
}
|
|
2341
2453
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppSidebar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2342
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
2343
|
-
<div #menuContainer class="layout-menu-container" (scroll)="onMenuScroll()">
|
|
2454
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: AppSidebar, isStandalone: true, selector: "[app-sidebar]", viewQueries: [{ propertyName: "menuContainer", first: true, predicate: ["menuContainer"], descendants: true }, { propertyName: "sidebarRef", first: true, predicate: ["sidebarRef"], descendants: true }], ngImport: i0, template: `<nav class="layout-sidebar" aria-label="Main navigation" (mouseleave)="onMouseLeave()">
|
|
2455
|
+
<div #menuContainer class="layout-menu-container min-h-0 grow" (scroll)="onMenuScroll()">
|
|
2344
2456
|
<div app-menu></div>
|
|
2345
2457
|
</div>
|
|
2458
|
+
@if (!isHorizontal()) {
|
|
2459
|
+
<ux-footer-main [copyrightOnly]="true" role="contentinfo" />
|
|
2460
|
+
}
|
|
2346
2461
|
<div app-topbar *ngIf="isHorizontal()"></div>
|
|
2347
|
-
</nav>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: AppMenu, selector: "[app-menu]" }, { kind: "ngmodule", type: RouterModule }, { kind: "component", type: AppTopbar, selector: "[app-topbar]", inputs: ["selectedNotificationBar"], outputs: ["selectedNotificationBarChange"] }] });
|
|
2462
|
+
</nav>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: AppMenu, selector: "[app-menu]" }, { kind: "ngmodule", type: RouterModule }, { kind: "component", type: AppTopbar, selector: "[app-topbar]", inputs: ["selectedNotificationBar"], outputs: ["selectedNotificationBarChange"] }, { kind: "component", type: FooterMainComponent, selector: "ux-footer-main", inputs: ["copyrightOnly"] }] });
|
|
2348
2463
|
}
|
|
2349
2464
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppSidebar, decorators: [{
|
|
2350
2465
|
type: Component,
|
|
2351
2466
|
args: [{
|
|
2352
2467
|
selector: '[app-sidebar]',
|
|
2353
|
-
imports: [CommonModule, AppMenu, RouterModule, AppTopbar],
|
|
2468
|
+
imports: [CommonModule, AppMenu, RouterModule, AppTopbar, FooterMainComponent],
|
|
2354
2469
|
template: `<nav class="layout-sidebar" aria-label="Main navigation" (mouseleave)="onMouseLeave()">
|
|
2355
|
-
<div #menuContainer class="layout-menu-container" (scroll)="onMenuScroll()">
|
|
2470
|
+
<div #menuContainer class="layout-menu-container min-h-0 grow" (scroll)="onMenuScroll()">
|
|
2356
2471
|
<div app-menu></div>
|
|
2357
2472
|
</div>
|
|
2473
|
+
@if (!isHorizontal()) {
|
|
2474
|
+
<ux-footer-main [copyrightOnly]="true" role="contentinfo" />
|
|
2475
|
+
}
|
|
2358
2476
|
<div app-topbar *ngIf="isHorizontal()"></div>
|
|
2359
2477
|
</nav>`
|
|
2360
2478
|
}]
|
|
@@ -2368,6 +2486,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2368
2486
|
|
|
2369
2487
|
class AppLayout {
|
|
2370
2488
|
layoutService = inject(LayoutService);
|
|
2489
|
+
elRef = inject(ElementRef);
|
|
2371
2490
|
constructor() {
|
|
2372
2491
|
effect(() => {
|
|
2373
2492
|
const state = this.layoutService.layoutState();
|
|
@@ -2378,6 +2497,11 @@ class AppLayout {
|
|
|
2378
2497
|
document.body.classList.remove('blocked-scroll');
|
|
2379
2498
|
}
|
|
2380
2499
|
});
|
|
2500
|
+
inject(Router).events.pipe(filter((e) => e instanceof NavigationEnd), takeUntilDestroyed()).subscribe(() => {
|
|
2501
|
+
const wrapper = this.elRef.nativeElement.querySelector('.layout-content-wrapper');
|
|
2502
|
+
if (wrapper)
|
|
2503
|
+
wrapper.scrollTop = 0;
|
|
2504
|
+
});
|
|
2381
2505
|
}
|
|
2382
2506
|
containerClass = computed(() => {
|
|
2383
2507
|
const layoutConfig = this.layoutService.layoutConfig();
|
|
@@ -2410,21 +2534,21 @@ class AppLayout {
|
|
|
2410
2534
|
<div app-breadcrumb></div>
|
|
2411
2535
|
<router-outlet></router-outlet>
|
|
2412
2536
|
</main>
|
|
2413
|
-
<div app-footer></div>
|
|
2414
2537
|
</div>
|
|
2538
|
+
<ux-footer-main class="footer-sticky" />
|
|
2415
2539
|
</div>
|
|
2416
2540
|
</div>
|
|
2417
2541
|
<app-configurator />
|
|
2418
2542
|
<div app-search></div>
|
|
2419
2543
|
<div app-rightmenu></div>
|
|
2420
2544
|
<div class="layout-mask"></div>
|
|
2421
|
-
</div> `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AppTopbar, selector: "[app-topbar]", inputs: ["selectedNotificationBar"], outputs: ["selectedNotificationBarChange"] }, { kind: "component", type: AppSidebar, selector: "[app-sidebar]" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: AppConfigurator, selector: "app-configurator", inputs: ["simple", "location", "cardStyle"], outputs: ["cardStyleChange"] }, { kind: "component", type: AppBreadcrumb, selector: "[app-breadcrumb]" }, { kind: "component", type:
|
|
2545
|
+
</div> `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AppTopbar, selector: "[app-topbar]", inputs: ["selectedNotificationBar"], outputs: ["selectedNotificationBarChange"] }, { kind: "component", type: AppSidebar, selector: "[app-sidebar]" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: AppConfigurator, selector: "app-configurator", inputs: ["simple", "location", "cardStyle"], outputs: ["cardStyleChange"] }, { kind: "component", type: AppBreadcrumb, selector: "[app-breadcrumb]" }, { kind: "component", type: FooterMainComponent, selector: "ux-footer-main", inputs: ["copyrightOnly"] }, { kind: "component", type: AppSearch, selector: "[app-search]" }, { kind: "component", type: AppRightMenu, selector: "[app-rightmenu]" }] });
|
|
2422
2546
|
}
|
|
2423
2547
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppLayout, decorators: [{
|
|
2424
2548
|
type: Component,
|
|
2425
2549
|
args: [{
|
|
2426
2550
|
selector: 'app-layout',
|
|
2427
|
-
imports: [CommonModule, AppTopbar, AppSidebar, RouterModule, AppConfigurator, AppBreadcrumb,
|
|
2551
|
+
imports: [CommonModule, AppTopbar, AppSidebar, RouterModule, AppConfigurator, AppBreadcrumb, FooterMainComponent, AppSearch, AppRightMenu],
|
|
2428
2552
|
template: `<div class="layout-wrapper" [ngClass]="containerClass()">
|
|
2429
2553
|
<div app-topbar></div>
|
|
2430
2554
|
<div class="layout-body">
|
|
@@ -2435,8 +2559,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2435
2559
|
<div app-breadcrumb></div>
|
|
2436
2560
|
<router-outlet></router-outlet>
|
|
2437
2561
|
</main>
|
|
2438
|
-
<div app-footer></div>
|
|
2439
2562
|
</div>
|
|
2563
|
+
<ux-footer-main class="footer-sticky" />
|
|
2440
2564
|
</div>
|
|
2441
2565
|
</div>
|
|
2442
2566
|
<app-configurator />
|
|
@@ -2447,6 +2571,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2447
2571
|
}]
|
|
2448
2572
|
}], ctorParameters: () => [] });
|
|
2449
2573
|
|
|
2574
|
+
class AppFooter {
|
|
2575
|
+
layoutService = inject(LayoutService);
|
|
2576
|
+
copyrightYear = new Date().getFullYear();
|
|
2577
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppFooter, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2578
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: AppFooter, isStandalone: true, selector: "[app-footer]", ngImport: i0, template: `
|
|
2579
|
+
@if (layoutService.isHorizontal()) {
|
|
2580
|
+
<footer class="layout-footer">
|
|
2581
|
+
<span class="footer-copyright">© UNOPS {{ copyrightYear }}</span>
|
|
2582
|
+
</footer>
|
|
2583
|
+
}
|
|
2584
|
+
`, isInline: true });
|
|
2585
|
+
}
|
|
2586
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AppFooter, decorators: [{
|
|
2587
|
+
type: Component,
|
|
2588
|
+
args: [{
|
|
2589
|
+
selector: '[app-footer]',
|
|
2590
|
+
template: `
|
|
2591
|
+
@if (layoutService.isHorizontal()) {
|
|
2592
|
+
<footer class="layout-footer">
|
|
2593
|
+
<span class="footer-copyright">© UNOPS {{ copyrightYear }}</span>
|
|
2594
|
+
</footer>
|
|
2595
|
+
}
|
|
2596
|
+
`
|
|
2597
|
+
}]
|
|
2598
|
+
}] });
|
|
2599
|
+
|
|
2450
2600
|
class AuthLayout {
|
|
2451
2601
|
layoutService = inject(LayoutService);
|
|
2452
2602
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AuthLayout, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
@@ -2532,7 +2682,7 @@ class AiCardBgComponent {
|
|
|
2532
2682
|
/>
|
|
2533
2683
|
</svg>
|
|
2534
2684
|
<ng-content />
|
|
2535
|
-
`, isInline: true, styles: [":host{--ux-ai-bg-from:
|
|
2685
|
+
`, isInline: true, styles: [":host{--ux-ai-bg-from: var(--color-ai-50);--ux-ai-bg-to: var(--color-cherry-50);--ux-ai-fg-from: var(--color-ai-200);--ux-ai-fg-to: var(--color-cherry-100);position:relative;overflow:hidden;isolation:isolate;contain:paint;animation:ux-ai-bg-move 5s ease-in-out infinite;will-change:background-color}:host-context([class*=\"app-dark\"]){--ux-ai-bg-from: var(--color-ai-950);--ux-ai-bg-to: var(--color-cherry-950);--ux-ai-fg-from: var(--color-ai-900);--ux-ai-fg-to: var(--color-cherry-900)}:host>:not(svg){position:relative;z-index:1}:host svg.ux-ai-card-bg__svg{position:absolute;inset:0;z-index:0;height:100%;width:100%;max-height:100%;overflow:hidden;pointer-events:none}.ux-ai-fg{will-change:fill;animation:ux-ai-fg-move 6s ease-in-out infinite}.ux-ai-fg--1{animation-delay:0s}.ux-ai-fg--2{animation-delay:2s}.ux-ai-fg--3{animation-delay:4s}@keyframes ux-ai-bg-move{0%,to{background-color:var(--ux-ai-bg-from)}50%{background-color:var(--ux-ai-bg-to)}}@keyframes ux-ai-fg-move{0%,to{fill:var(--ux-ai-fg-from)}50%{fill:var(--ux-ai-fg-to)}}@media(prefers-reduced-motion:reduce){:host{animation:none;background-color:var(--ux-ai-bg-from)}.ux-ai-fg{animation:none;fill:var(--ux-ai-fg-from)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2536
2686
|
}
|
|
2537
2687
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AiCardBgComponent, decorators: [{
|
|
2538
2688
|
type: Component,
|
|
@@ -2581,9 +2731,1220 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2581
2731
|
/>
|
|
2582
2732
|
</svg>
|
|
2583
2733
|
<ng-content />
|
|
2584
|
-
`, styles: [":host{--ux-ai-bg-from:
|
|
2734
|
+
`, styles: [":host{--ux-ai-bg-from: var(--color-ai-50);--ux-ai-bg-to: var(--color-cherry-50);--ux-ai-fg-from: var(--color-ai-200);--ux-ai-fg-to: var(--color-cherry-100);position:relative;overflow:hidden;isolation:isolate;contain:paint;animation:ux-ai-bg-move 5s ease-in-out infinite;will-change:background-color}:host-context([class*=\"app-dark\"]){--ux-ai-bg-from: var(--color-ai-950);--ux-ai-bg-to: var(--color-cherry-950);--ux-ai-fg-from: var(--color-ai-900);--ux-ai-fg-to: var(--color-cherry-900)}:host>:not(svg){position:relative;z-index:1}:host svg.ux-ai-card-bg__svg{position:absolute;inset:0;z-index:0;height:100%;width:100%;max-height:100%;overflow:hidden;pointer-events:none}.ux-ai-fg{will-change:fill;animation:ux-ai-fg-move 6s ease-in-out infinite}.ux-ai-fg--1{animation-delay:0s}.ux-ai-fg--2{animation-delay:2s}.ux-ai-fg--3{animation-delay:4s}@keyframes ux-ai-bg-move{0%,to{background-color:var(--ux-ai-bg-from)}50%{background-color:var(--ux-ai-bg-to)}}@keyframes ux-ai-fg-move{0%,to{fill:var(--ux-ai-fg-from)}50%{fill:var(--ux-ai-fg-to)}}@media(prefers-reduced-motion:reduce){:host{animation:none;background-color:var(--ux-ai-bg-from)}.ux-ai-fg{animation:none;fill:var(--ux-ai-fg-from)}}\n"] }]
|
|
2585
2735
|
}] });
|
|
2586
2736
|
|
|
2737
|
+
class AiInsightsCardComponent {
|
|
2738
|
+
title = input.required(...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2739
|
+
insights = input.required(...(ngDevMode ? [{ debugName: "insights" }] : []));
|
|
2740
|
+
searchPlaceholder = input('Search AI insights...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : []));
|
|
2741
|
+
actionClick = output();
|
|
2742
|
+
expanded = signal(false, ...(ngDevMode ? [{ debugName: "expanded" }] : []));
|
|
2743
|
+
searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
|
|
2744
|
+
filteredInsights = computed(() => {
|
|
2745
|
+
const query = this.searchQuery().trim().toLowerCase();
|
|
2746
|
+
if (!query)
|
|
2747
|
+
return this.insights();
|
|
2748
|
+
return this.insights().filter(i => i.title.toLowerCase().includes(query) ||
|
|
2749
|
+
i.description.toLowerCase().includes(query));
|
|
2750
|
+
}, ...(ngDevMode ? [{ debugName: "filteredInsights" }] : []));
|
|
2751
|
+
perPage = signal(this.calcPerPage(), ...(ngDevMode ? [{ debugName: "perPage" }] : []));
|
|
2752
|
+
page = signal(0, ...(ngDevMode ? [{ debugName: "page" }] : []));
|
|
2753
|
+
first = computed(() => this.page() * this.perPage(), ...(ngDevMode ? [{ debugName: "first" }] : []));
|
|
2754
|
+
paginatedInsights = computed(() => {
|
|
2755
|
+
const all = this.filteredInsights();
|
|
2756
|
+
return all.slice(this.first(), this.first() + this.perPage());
|
|
2757
|
+
}, ...(ngDevMode ? [{ debugName: "paginatedInsights" }] : []));
|
|
2758
|
+
destroyRef = inject(DestroyRef);
|
|
2759
|
+
ngOnInit() {
|
|
2760
|
+
const onResize = () => this.perPage.set(this.calcPerPage());
|
|
2761
|
+
window.addEventListener('resize', onResize);
|
|
2762
|
+
this.destroyRef.onDestroy(() => window.removeEventListener('resize', onResize));
|
|
2763
|
+
}
|
|
2764
|
+
calcPerPage() {
|
|
2765
|
+
const shellOffset = 12 * 16;
|
|
2766
|
+
const cardChrome = 160 + 72;
|
|
2767
|
+
const insightCardHeight = 150;
|
|
2768
|
+
const available = (typeof window !== 'undefined' ? window.innerHeight : 900) - shellOffset - cardChrome;
|
|
2769
|
+
return Math.max(1, Math.floor(available / insightCardHeight));
|
|
2770
|
+
}
|
|
2771
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AiInsightsCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2772
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: AiInsightsCardComponent, isStandalone: true, selector: "ux-ai-insights-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, insights: { classPropertyName: "insights", publicName: "insights", isSignal: true, isRequired: true, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick" }, host: { properties: { "class.ux-ai-expanded": "expanded()" }, classAttribute: "ux-ai-insights-card block border border-blue-100 dark:border-midnight-400 rounded-2xl shadow-sm overflow-hidden transition-all duration-300 flex flex-col" }, ngImport: i0, template: `
|
|
2773
|
+
<ux-ai-card-bg class="flex flex-col flex-1 p-4">
|
|
2774
|
+
<div class="motion-safe:animate-enter-liquid [animation-delay:80ms] flex flex-col flex-1">
|
|
2775
|
+
<div class="flex items-center justify-between cursor-pointer shrink-0 pr-2" (click)="expanded.set(!expanded())">
|
|
2776
|
+
<div class="flex items-center gap-3">
|
|
2777
|
+
<div class="w-[34px] h-[34px] rounded-[10px] flex items-center justify-center shrink-0">
|
|
2778
|
+
<i class="pi pi-sparkles text-ai-600 dark:text-ai-300"></i>
|
|
2779
|
+
</div>
|
|
2780
|
+
<div class="flex flex-col">
|
|
2781
|
+
<h4 class="title-h4 text-left text-deepsea-500 dark:text-surface-0">{{ title() }}</h4>
|
|
2782
|
+
<span class="text-midnight-700 dark:text-surface-100 text-sm font-medium leading-tight">{{ insights().length }} insights available for your review</span>
|
|
2783
|
+
</div>
|
|
2784
|
+
</div>
|
|
2785
|
+
<i class="pi text-sm text-darkblue-500 dark:text-surface-0" [ngClass]="expanded() ? 'pi-chevron-up' : 'pi-chevron-down'"></i>
|
|
2786
|
+
</div>
|
|
2787
|
+
|
|
2788
|
+
<div class="expand-body" [class.expand-body--open]="expanded()">
|
|
2789
|
+
<div class="expand-body__inner">
|
|
2790
|
+
<div class="flex flex-col gap-4 mt-4">
|
|
2791
|
+
<div class="bg-white/60 dark:bg-surface-800/60 border border-white dark:border-surface-700 rounded-[14px] shadow-sm flex items-center gap-4 px-4 py-2.5 shrink-0">
|
|
2792
|
+
<i class="pi pi-search text-surface-500 dark:text-surface-300 text-sm"></i>
|
|
2793
|
+
<input
|
|
2794
|
+
type="text"
|
|
2795
|
+
[ngModel]="searchQuery()"
|
|
2796
|
+
(ngModelChange)="searchQuery.set($event); page.set(0)"
|
|
2797
|
+
[placeholder]="searchPlaceholder()"
|
|
2798
|
+
class="bg-transparent border-none outline-none flex-1 text-sm font-medium text-deepsea-500 dark:text-surface-0 placeholder:text-surface-700 dark:placeholder:text-surface-300"
|
|
2799
|
+
/>
|
|
2800
|
+
</div>
|
|
2801
|
+
|
|
2802
|
+
<div class="flex flex-col gap-3">
|
|
2803
|
+
@for (insight of paginatedInsights(); track insight.id) {
|
|
2804
|
+
<div class="bg-white/70 dark:bg-surface-800/70 border border-white/50 dark:border-surface-700/50 rounded-[14px] shadow-sm p-4 flex gap-3 items-start shrink-0">
|
|
2805
|
+
<i class="pi mt-0.5" [ngClass]="[insight.icon, insight.iconColor]"></i>
|
|
2806
|
+
<div class="flex flex-col gap-2 flex-1 min-w-0">
|
|
2807
|
+
<div class="flex flex-col gap-1">
|
|
2808
|
+
<span class="text-midnight-500 dark:text-surface-0 text-sm font-bold leading-[21px]">{{ insight.title }}</span>
|
|
2809
|
+
<p class="text-midnight-400 dark:text-surface-300 text-sm leading-normal">{{ insight.description }}</p>
|
|
2810
|
+
</div>
|
|
2811
|
+
<button
|
|
2812
|
+
class="flex items-center gap-1.5 text-darkblue-500 dark:text-primary-400 text-sm font-semibold cursor-pointer hover:underline bg-transparent border-none p-0 w-fit"
|
|
2813
|
+
(click)="actionClick.emit(insight)"
|
|
2814
|
+
>
|
|
2815
|
+
{{ insight.actionLabel }}
|
|
2816
|
+
<i class="pi pi-arrow-right text-xs"></i>
|
|
2817
|
+
</button>
|
|
2818
|
+
</div>
|
|
2819
|
+
</div>
|
|
2820
|
+
}
|
|
2821
|
+
</div>
|
|
2822
|
+
|
|
2823
|
+
<div class="shrink-0 w-full border-t border-white/50 dark:border-surface-700/50 pt-2 mt-1 relative z-[1] bg-transparent">
|
|
2824
|
+
<p-paginator
|
|
2825
|
+
[rows]="perPage()"
|
|
2826
|
+
[totalRecords]="filteredInsights().length"
|
|
2827
|
+
[first]="first()"
|
|
2828
|
+
(onPageChange)="page.set($event.page ?? 0)"
|
|
2829
|
+
[pageLinkSize]="3"
|
|
2830
|
+
styleClass="w-full"
|
|
2831
|
+
[pt]="{ root: { class: 'justify-center' } }"
|
|
2832
|
+
/>
|
|
2833
|
+
</div>
|
|
2834
|
+
</div>
|
|
2835
|
+
</div>
|
|
2836
|
+
</div>
|
|
2837
|
+
</div>
|
|
2838
|
+
</ux-ai-card-bg>
|
|
2839
|
+
`, isInline: true, styles: [":host{display:flex}\n"], dependencies: [{ kind: "component", type: AiCardBgComponent, selector: "ux-ai-card-bg" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i2$2.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first", "appendTo"], outputs: ["onPageChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2840
|
+
}
|
|
2841
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AiInsightsCardComponent, decorators: [{
|
|
2842
|
+
type: Component,
|
|
2843
|
+
args: [{ selector: 'ux-ai-insights-card', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AiCardBgComponent, FormsModule, NgClass, PaginatorModule], host: {
|
|
2844
|
+
class: 'ux-ai-insights-card block border border-blue-100 dark:border-midnight-400 rounded-2xl shadow-sm overflow-hidden transition-all duration-300 flex flex-col',
|
|
2845
|
+
'[class.ux-ai-expanded]': 'expanded()'
|
|
2846
|
+
}, template: `
|
|
2847
|
+
<ux-ai-card-bg class="flex flex-col flex-1 p-4">
|
|
2848
|
+
<div class="motion-safe:animate-enter-liquid [animation-delay:80ms] flex flex-col flex-1">
|
|
2849
|
+
<div class="flex items-center justify-between cursor-pointer shrink-0 pr-2" (click)="expanded.set(!expanded())">
|
|
2850
|
+
<div class="flex items-center gap-3">
|
|
2851
|
+
<div class="w-[34px] h-[34px] rounded-[10px] flex items-center justify-center shrink-0">
|
|
2852
|
+
<i class="pi pi-sparkles text-ai-600 dark:text-ai-300"></i>
|
|
2853
|
+
</div>
|
|
2854
|
+
<div class="flex flex-col">
|
|
2855
|
+
<h4 class="title-h4 text-left text-deepsea-500 dark:text-surface-0">{{ title() }}</h4>
|
|
2856
|
+
<span class="text-midnight-700 dark:text-surface-100 text-sm font-medium leading-tight">{{ insights().length }} insights available for your review</span>
|
|
2857
|
+
</div>
|
|
2858
|
+
</div>
|
|
2859
|
+
<i class="pi text-sm text-darkblue-500 dark:text-surface-0" [ngClass]="expanded() ? 'pi-chevron-up' : 'pi-chevron-down'"></i>
|
|
2860
|
+
</div>
|
|
2861
|
+
|
|
2862
|
+
<div class="expand-body" [class.expand-body--open]="expanded()">
|
|
2863
|
+
<div class="expand-body__inner">
|
|
2864
|
+
<div class="flex flex-col gap-4 mt-4">
|
|
2865
|
+
<div class="bg-white/60 dark:bg-surface-800/60 border border-white dark:border-surface-700 rounded-[14px] shadow-sm flex items-center gap-4 px-4 py-2.5 shrink-0">
|
|
2866
|
+
<i class="pi pi-search text-surface-500 dark:text-surface-300 text-sm"></i>
|
|
2867
|
+
<input
|
|
2868
|
+
type="text"
|
|
2869
|
+
[ngModel]="searchQuery()"
|
|
2870
|
+
(ngModelChange)="searchQuery.set($event); page.set(0)"
|
|
2871
|
+
[placeholder]="searchPlaceholder()"
|
|
2872
|
+
class="bg-transparent border-none outline-none flex-1 text-sm font-medium text-deepsea-500 dark:text-surface-0 placeholder:text-surface-700 dark:placeholder:text-surface-300"
|
|
2873
|
+
/>
|
|
2874
|
+
</div>
|
|
2875
|
+
|
|
2876
|
+
<div class="flex flex-col gap-3">
|
|
2877
|
+
@for (insight of paginatedInsights(); track insight.id) {
|
|
2878
|
+
<div class="bg-white/70 dark:bg-surface-800/70 border border-white/50 dark:border-surface-700/50 rounded-[14px] shadow-sm p-4 flex gap-3 items-start shrink-0">
|
|
2879
|
+
<i class="pi mt-0.5" [ngClass]="[insight.icon, insight.iconColor]"></i>
|
|
2880
|
+
<div class="flex flex-col gap-2 flex-1 min-w-0">
|
|
2881
|
+
<div class="flex flex-col gap-1">
|
|
2882
|
+
<span class="text-midnight-500 dark:text-surface-0 text-sm font-bold leading-[21px]">{{ insight.title }}</span>
|
|
2883
|
+
<p class="text-midnight-400 dark:text-surface-300 text-sm leading-normal">{{ insight.description }}</p>
|
|
2884
|
+
</div>
|
|
2885
|
+
<button
|
|
2886
|
+
class="flex items-center gap-1.5 text-darkblue-500 dark:text-primary-400 text-sm font-semibold cursor-pointer hover:underline bg-transparent border-none p-0 w-fit"
|
|
2887
|
+
(click)="actionClick.emit(insight)"
|
|
2888
|
+
>
|
|
2889
|
+
{{ insight.actionLabel }}
|
|
2890
|
+
<i class="pi pi-arrow-right text-xs"></i>
|
|
2891
|
+
</button>
|
|
2892
|
+
</div>
|
|
2893
|
+
</div>
|
|
2894
|
+
}
|
|
2895
|
+
</div>
|
|
2896
|
+
|
|
2897
|
+
<div class="shrink-0 w-full border-t border-white/50 dark:border-surface-700/50 pt-2 mt-1 relative z-[1] bg-transparent">
|
|
2898
|
+
<p-paginator
|
|
2899
|
+
[rows]="perPage()"
|
|
2900
|
+
[totalRecords]="filteredInsights().length"
|
|
2901
|
+
[first]="first()"
|
|
2902
|
+
(onPageChange)="page.set($event.page ?? 0)"
|
|
2903
|
+
[pageLinkSize]="3"
|
|
2904
|
+
styleClass="w-full"
|
|
2905
|
+
[pt]="{ root: { class: 'justify-center' } }"
|
|
2906
|
+
/>
|
|
2907
|
+
</div>
|
|
2908
|
+
</div>
|
|
2909
|
+
</div>
|
|
2910
|
+
</div>
|
|
2911
|
+
</div>
|
|
2912
|
+
</ux-ai-card-bg>
|
|
2913
|
+
`, styles: [":host{display:flex}\n"] }]
|
|
2914
|
+
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], insights: [{ type: i0.Input, args: [{ isSignal: true, alias: "insights", required: true }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }] } });
|
|
2915
|
+
|
|
2916
|
+
class CompletionStepsComponent {
|
|
2917
|
+
title = input('Completion Steps', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2918
|
+
steps = input([], ...(ngDevMode ? [{ debugName: "steps" }] : []));
|
|
2919
|
+
mandatory = input({ filled: 0, total: 0 }, ...(ngDevMode ? [{ debugName: "mandatory" }] : []));
|
|
2920
|
+
optional = input({ filled: 0, total: 0 }, ...(ngDevMode ? [{ debugName: "optional" }] : []));
|
|
2921
|
+
totalRecords = input(0, ...(ngDevMode ? [{ debugName: "totalRecords" }] : []));
|
|
2922
|
+
interactive = input(false, ...(ngDevMode ? [{ debugName: "interactive" }] : []));
|
|
2923
|
+
emptyTitle = input('No progress tracked yet', ...(ngDevMode ? [{ debugName: "emptyTitle" }] : []));
|
|
2924
|
+
emptyDescription = input('Progress is calculated automatically as you fill in the opportunity sections. Each dot represents a required or optional field — mandatory fields (bordered red) must be completed before submission.', ...(ngDevMode ? [{ debugName: "emptyDescription" }] : []));
|
|
2925
|
+
stepClick = output();
|
|
2926
|
+
dotStyles = {
|
|
2927
|
+
mandatoryFilled: { bg: 'bg-green-200 dark:bg-green-700', text: 'text-green-800 dark:text-green-50', icon: 'pi', iconClass: 'pi-check' },
|
|
2928
|
+
optionalFilled: { bg: 'bg-blue-200 dark:bg-blue-700', text: 'text-blue-800 dark:text-blue-50', icon: 'material', iconClass: 'info_i' },
|
|
2929
|
+
mandatoryMissing: { bg: 'bg-transparent border-2 border-red-400 dark:border-red-500', text: 'text-red-500 dark:text-red-400', icon: 'pi', iconClass: 'pi-plus' },
|
|
2930
|
+
optionalMissing: { bg: 'bg-transparent border-2 border-surface-300 dark:border-surface-600', text: 'text-surface-500 dark:text-surface-400', icon: 'material', iconClass: 'info_i' }
|
|
2931
|
+
};
|
|
2932
|
+
filledTotal = computed(() => this.mandatory().filled + this.optional().filled, ...(ngDevMode ? [{ debugName: "filledTotal" }] : []));
|
|
2933
|
+
empty = computed(() => this.filledTotal() === 0, ...(ngDevMode ? [{ debugName: "empty" }] : []));
|
|
2934
|
+
legendMandatoryBg = computed(() => this.mandatory().filled > 0 ? this.dotStyles.mandatoryFilled.bg : this.dotStyles.mandatoryMissing.bg, ...(ngDevMode ? [{ debugName: "legendMandatoryBg" }] : []));
|
|
2935
|
+
legendOptionalBg = computed(() => this.optional().filled > 0 ? this.dotStyles.optionalFilled.bg : this.dotStyles.optionalMissing.bg, ...(ngDevMode ? [{ debugName: "legendOptionalBg" }] : []));
|
|
2936
|
+
getDotStyle(step) {
|
|
2937
|
+
if (step.filled)
|
|
2938
|
+
return step.type === 'mandatory' ? this.dotStyles.mandatoryFilled : this.dotStyles.optionalFilled;
|
|
2939
|
+
return step.type === 'mandatory' ? this.dotStyles.mandatoryMissing : this.dotStyles.optionalMissing;
|
|
2940
|
+
}
|
|
2941
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: CompletionStepsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2942
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: CompletionStepsComponent, isStandalone: true, selector: "ux-completion-steps", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: false, transformFunction: null }, mandatory: { classPropertyName: "mandatory", publicName: "mandatory", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, emptyTitle: { classPropertyName: "emptyTitle", publicName: "emptyTitle", isSignal: true, isRequired: false, transformFunction: null }, emptyDescription: { classPropertyName: "emptyDescription", publicName: "emptyDescription", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stepClick: "stepClick" }, host: { classAttribute: "block" }, ngImport: i0, template: `
|
|
2943
|
+
<div class="card flex flex-col gap-4">
|
|
2944
|
+
<div class="flex items-center justify-between">
|
|
2945
|
+
<div class="flex items-center gap-3">
|
|
2946
|
+
<div class="flex flex-col">
|
|
2947
|
+
<span class="text-xs font-semibold text-surface-600 dark:text-surface-300 uppercase tracking-wide">{{ title() }}</span>
|
|
2948
|
+
</div>
|
|
2949
|
+
</div>
|
|
2950
|
+
<span class="text-2xl font-bold" [class]="filledTotal() > 0 ? 'text-surface-900 dark:text-surface-0' : 'text-surface-500 dark:text-surface-400'">{{ filledTotal() }}/{{ totalRecords() }}</span>
|
|
2951
|
+
</div>
|
|
2952
|
+
|
|
2953
|
+
<div class="flex items-center gap-1 flex-wrap">
|
|
2954
|
+
@for (step of steps(); track $index) {
|
|
2955
|
+
<span class="inline-flex items-center justify-center w-6 h-6 rounded-full"
|
|
2956
|
+
[class.cursor-pointer]="interactive()"
|
|
2957
|
+
[class]="getDotStyle(step).bg"
|
|
2958
|
+
[pTooltip]="step.name + (step.filled ? '' : ' (missing)')" tooltipPosition="top"
|
|
2959
|
+
(click)="interactive() && stepClick.emit($index)">
|
|
2960
|
+
@if (getDotStyle(step).icon === 'pi') {
|
|
2961
|
+
<i class="pi text-[3px]" [class]="getDotStyle(step).iconClass + ' ' + getDotStyle(step).text"></i>
|
|
2962
|
+
} @else if (getDotStyle(step).icon === 'material') {
|
|
2963
|
+
<span class="material-symbols-outlined leading-none" style="font-size:20px;transform:scale(0.9)" [class]="getDotStyle(step).text">{{ getDotStyle(step).iconClass }}</span>
|
|
2964
|
+
} @else {
|
|
2965
|
+
<span class="text-sm font-black leading-none" [class]="getDotStyle(step).text">!</span>
|
|
2966
|
+
}
|
|
2967
|
+
</span>
|
|
2968
|
+
}
|
|
2969
|
+
</div>
|
|
2970
|
+
|
|
2971
|
+
<div class="flex flex-wrap items-center gap-x-6 gap-y-2 mt-1">
|
|
2972
|
+
<div class="flex items-center gap-2">
|
|
2973
|
+
<span class="inline-block w-4 h-4 rounded-full shrink-0" [class]="legendMandatoryBg()"></span>
|
|
2974
|
+
<span class="text-sm text-surface-600 dark:text-surface-300">Mandatory:</span>
|
|
2975
|
+
<span class="text-sm font-semibold text-surface-900 dark:text-surface-0">{{ mandatory().filled }}/{{ mandatory().total }}</span>
|
|
2976
|
+
</div>
|
|
2977
|
+
<div class="flex items-center gap-2">
|
|
2978
|
+
<span class="inline-block w-4 h-4 rounded-full shrink-0" [class]="legendOptionalBg()"></span>
|
|
2979
|
+
<span class="text-sm text-surface-600 dark:text-surface-300">Optional:</span>
|
|
2980
|
+
<span class="text-sm font-semibold text-surface-900 dark:text-surface-0">{{ optional().filled }}/{{ optional().total }}</span>
|
|
2981
|
+
</div>
|
|
2982
|
+
<div class="flex items-center gap-2">
|
|
2983
|
+
<span class="text-sm text-surface-600 dark:text-surface-300">Total:</span>
|
|
2984
|
+
<span class="text-sm font-semibold text-surface-900 dark:text-surface-0">{{ totalRecords() }}</span>
|
|
2985
|
+
</div>
|
|
2986
|
+
</div>
|
|
2987
|
+
|
|
2988
|
+
@if (empty()) {
|
|
2989
|
+
<div class="empty-state">
|
|
2990
|
+
<i class="pi pi-chart-bar text-3xl text-surface-500 dark:text-surface-400"></i>
|
|
2991
|
+
<span class="empty-state-title">{{ emptyTitle() }}</span>
|
|
2992
|
+
<span class="empty-state-desc">{{ emptyDescription() }}</span>
|
|
2993
|
+
</div>
|
|
2994
|
+
}
|
|
2995
|
+
</div>
|
|
2996
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2997
|
+
}
|
|
2998
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: CompletionStepsComponent, decorators: [{
|
|
2999
|
+
type: Component,
|
|
3000
|
+
args: [{
|
|
3001
|
+
selector: 'ux-completion-steps',
|
|
3002
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3003
|
+
imports: [TooltipModule],
|
|
3004
|
+
host: { class: 'block' },
|
|
3005
|
+
template: `
|
|
3006
|
+
<div class="card flex flex-col gap-4">
|
|
3007
|
+
<div class="flex items-center justify-between">
|
|
3008
|
+
<div class="flex items-center gap-3">
|
|
3009
|
+
<div class="flex flex-col">
|
|
3010
|
+
<span class="text-xs font-semibold text-surface-600 dark:text-surface-300 uppercase tracking-wide">{{ title() }}</span>
|
|
3011
|
+
</div>
|
|
3012
|
+
</div>
|
|
3013
|
+
<span class="text-2xl font-bold" [class]="filledTotal() > 0 ? 'text-surface-900 dark:text-surface-0' : 'text-surface-500 dark:text-surface-400'">{{ filledTotal() }}/{{ totalRecords() }}</span>
|
|
3014
|
+
</div>
|
|
3015
|
+
|
|
3016
|
+
<div class="flex items-center gap-1 flex-wrap">
|
|
3017
|
+
@for (step of steps(); track $index) {
|
|
3018
|
+
<span class="inline-flex items-center justify-center w-6 h-6 rounded-full"
|
|
3019
|
+
[class.cursor-pointer]="interactive()"
|
|
3020
|
+
[class]="getDotStyle(step).bg"
|
|
3021
|
+
[pTooltip]="step.name + (step.filled ? '' : ' (missing)')" tooltipPosition="top"
|
|
3022
|
+
(click)="interactive() && stepClick.emit($index)">
|
|
3023
|
+
@if (getDotStyle(step).icon === 'pi') {
|
|
3024
|
+
<i class="pi text-[3px]" [class]="getDotStyle(step).iconClass + ' ' + getDotStyle(step).text"></i>
|
|
3025
|
+
} @else if (getDotStyle(step).icon === 'material') {
|
|
3026
|
+
<span class="material-symbols-outlined leading-none" style="font-size:20px;transform:scale(0.9)" [class]="getDotStyle(step).text">{{ getDotStyle(step).iconClass }}</span>
|
|
3027
|
+
} @else {
|
|
3028
|
+
<span class="text-sm font-black leading-none" [class]="getDotStyle(step).text">!</span>
|
|
3029
|
+
}
|
|
3030
|
+
</span>
|
|
3031
|
+
}
|
|
3032
|
+
</div>
|
|
3033
|
+
|
|
3034
|
+
<div class="flex flex-wrap items-center gap-x-6 gap-y-2 mt-1">
|
|
3035
|
+
<div class="flex items-center gap-2">
|
|
3036
|
+
<span class="inline-block w-4 h-4 rounded-full shrink-0" [class]="legendMandatoryBg()"></span>
|
|
3037
|
+
<span class="text-sm text-surface-600 dark:text-surface-300">Mandatory:</span>
|
|
3038
|
+
<span class="text-sm font-semibold text-surface-900 dark:text-surface-0">{{ mandatory().filled }}/{{ mandatory().total }}</span>
|
|
3039
|
+
</div>
|
|
3040
|
+
<div class="flex items-center gap-2">
|
|
3041
|
+
<span class="inline-block w-4 h-4 rounded-full shrink-0" [class]="legendOptionalBg()"></span>
|
|
3042
|
+
<span class="text-sm text-surface-600 dark:text-surface-300">Optional:</span>
|
|
3043
|
+
<span class="text-sm font-semibold text-surface-900 dark:text-surface-0">{{ optional().filled }}/{{ optional().total }}</span>
|
|
3044
|
+
</div>
|
|
3045
|
+
<div class="flex items-center gap-2">
|
|
3046
|
+
<span class="text-sm text-surface-600 dark:text-surface-300">Total:</span>
|
|
3047
|
+
<span class="text-sm font-semibold text-surface-900 dark:text-surface-0">{{ totalRecords() }}</span>
|
|
3048
|
+
</div>
|
|
3049
|
+
</div>
|
|
3050
|
+
|
|
3051
|
+
@if (empty()) {
|
|
3052
|
+
<div class="empty-state">
|
|
3053
|
+
<i class="pi pi-chart-bar text-3xl text-surface-500 dark:text-surface-400"></i>
|
|
3054
|
+
<span class="empty-state-title">{{ emptyTitle() }}</span>
|
|
3055
|
+
<span class="empty-state-desc">{{ emptyDescription() }}</span>
|
|
3056
|
+
</div>
|
|
3057
|
+
}
|
|
3058
|
+
</div>
|
|
3059
|
+
`
|
|
3060
|
+
}]
|
|
3061
|
+
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: false }] }], mandatory: [{ type: i0.Input, args: [{ isSignal: true, alias: "mandatory", required: false }] }], optional: [{ type: i0.Input, args: [{ isSignal: true, alias: "optional", required: false }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], emptyTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyTitle", required: false }] }], emptyDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyDescription", required: false }] }], stepClick: [{ type: i0.Output, args: ["stepClick"] }] } });
|
|
3062
|
+
|
|
3063
|
+
/**
|
|
3064
|
+
* Structural directive that marks a template as content for a specific tab
|
|
3065
|
+
* inside `<ux-detail-layout>`.
|
|
3066
|
+
*
|
|
3067
|
+
* Usage: `<ng-template uxDetailTab="overview">...content...</ng-template>`
|
|
3068
|
+
*/
|
|
3069
|
+
class DetailTabDirective {
|
|
3070
|
+
templateRef;
|
|
3071
|
+
uxDetailTab = input.required(...(ngDevMode ? [{ debugName: "uxDetailTab" }] : []));
|
|
3072
|
+
constructor(templateRef) {
|
|
3073
|
+
this.templateRef = templateRef;
|
|
3074
|
+
}
|
|
3075
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DetailTabDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
3076
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.8", type: DetailTabDirective, isStandalone: true, selector: "[uxDetailTab]", inputs: { uxDetailTab: { classPropertyName: "uxDetailTab", publicName: "uxDetailTab", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
3077
|
+
}
|
|
3078
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DetailTabDirective, decorators: [{
|
|
3079
|
+
type: Directive,
|
|
3080
|
+
args: [{ selector: '[uxDetailTab]' }]
|
|
3081
|
+
}], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { uxDetailTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "uxDetailTab", required: true }] }] } });
|
|
3082
|
+
/**
|
|
3083
|
+
* Reusable detail-page layout shell: sticky header, tabbed main column,
|
|
3084
|
+
* and a persistent right sidebar (typically for AI insights).
|
|
3085
|
+
*
|
|
3086
|
+
* All styling derives from the active PrimeNG brand preset (BrandSoft / BrandCrisp /
|
|
3087
|
+
* BrandContrast) via `--p-*` CSS variables and Tailwind `surface-*` / `primary-*`
|
|
3088
|
+
* utilities (resolved by `tailwindcss-primeui`). No hardcoded colors.
|
|
3089
|
+
*
|
|
3090
|
+
* ```html
|
|
3091
|
+
* <ux-detail-layout [tabs]="myTabs" [(activeTab)]="currentTab">
|
|
3092
|
+
* <ng-container ux-detail-header>
|
|
3093
|
+
* ...sticky header content...
|
|
3094
|
+
* </ng-container>
|
|
3095
|
+
*
|
|
3096
|
+
* <ng-template uxDetailTab="overview">...tab 1...</ng-template>
|
|
3097
|
+
* <ng-template uxDetailTab="scope">...tab 2...</ng-template>
|
|
3098
|
+
*
|
|
3099
|
+
* <ng-container ux-detail-sidebar>
|
|
3100
|
+
* <!-- Use ng-container so children become direct children of the
|
|
3101
|
+
* library's flex container and inherit the gap spacing. -->
|
|
3102
|
+
* ...right sidebar (AI card, documents, etc.)...
|
|
3103
|
+
* </ng-container>
|
|
3104
|
+
*
|
|
3105
|
+
* </ux-detail-layout>
|
|
3106
|
+
* ```
|
|
3107
|
+
*/
|
|
3108
|
+
class DetailLayoutComponent {
|
|
3109
|
+
/** Tab definitions for the main content area. */
|
|
3110
|
+
tabs = input.required(...(ngDevMode ? [{ debugName: "tabs" }] : []));
|
|
3111
|
+
/** Currently active tab value (two-way bindable). */
|
|
3112
|
+
activeTab = model('', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
|
|
3113
|
+
/** Options for the mobile tab dropdown. */
|
|
3114
|
+
tabOptions = computed(() => this.tabs().map(t => ({ label: t.label, value: t.value })), ...(ngDevMode ? [{ debugName: "tabOptions" }] : []));
|
|
3115
|
+
/** True when there is only a single tab, making the tab bar redundant. */
|
|
3116
|
+
singleTab = computed(() => this.tabs().length <= 1, ...(ngDevMode ? [{ debugName: "singleTab" }] : []));
|
|
3117
|
+
/** True when viewport is below the lg breakpoint (1024px). */
|
|
3118
|
+
isMobile = signal(false, ...(ngDevMode ? [{ debugName: "isMobile" }] : []));
|
|
3119
|
+
/** True once the scrollable body has been scrolled past the threshold. */
|
|
3120
|
+
scrolled = signal(false, ...(ngDevMode ? [{ debugName: "scrolled" }] : []));
|
|
3121
|
+
constructor() {
|
|
3122
|
+
if (isPlatformBrowser(inject(PLATFORM_ID))) {
|
|
3123
|
+
const mql = window.matchMedia('(max-width: 1023px)');
|
|
3124
|
+
this.isMobile.set(mql.matches);
|
|
3125
|
+
const handler = (e) => this.isMobile.set(e.matches);
|
|
3126
|
+
mql.addEventListener('change', handler);
|
|
3127
|
+
inject(DestroyRef).onDestroy(() => mql.removeEventListener('change', handler));
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
/** Tab content templates provided by the consumer. */
|
|
3131
|
+
tabTemplates;
|
|
3132
|
+
getTabTemplate(value) {
|
|
3133
|
+
const match = this.tabTemplates?.find(t => t.uxDetailTab() === value);
|
|
3134
|
+
return match?.templateRef ?? null;
|
|
3135
|
+
}
|
|
3136
|
+
onScroll(event) {
|
|
3137
|
+
const el = event.target;
|
|
3138
|
+
this.scrolled.set(el.scrollTop > 10);
|
|
3139
|
+
}
|
|
3140
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DetailLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3141
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: DetailLayoutComponent, isStandalone: true, selector: "ux-detail-layout", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: true, transformFunction: null }, activeTab: { classPropertyName: "activeTab", publicName: "activeTab", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeTab: "activeTabChange" }, host: { classAttribute: "ux-detail-layout" }, queries: [{ propertyName: "tabTemplates", predicate: DetailTabDirective }], ngImport: i0, template: `
|
|
3142
|
+
<div class="flex flex-col flex-1 min-h-0">
|
|
3143
|
+
|
|
3144
|
+
<!-- Sticky header (projected) -->
|
|
3145
|
+
<div class="ux-dl__header flex-shrink-0 z-10">
|
|
3146
|
+
<div>
|
|
3147
|
+
<ng-content select="[ux-detail-header]" />
|
|
3148
|
+
</div>
|
|
3149
|
+
<div class="ux-dl__header-meta" [class.ux-dl__header-meta--hidden]="scrolled()">
|
|
3150
|
+
<ng-content select="[ux-detail-header-meta]" />
|
|
3151
|
+
</div>
|
|
3152
|
+
</div>
|
|
3153
|
+
|
|
3154
|
+
<!-- p-tabs wraps tablist + scrollable panels for state binding -->
|
|
3155
|
+
<p-tabs class="flex flex-col flex-1 min-h-0" [value]="activeTab()" (valueChange)="activeTab.set($event + '')">
|
|
3156
|
+
|
|
3157
|
+
@if (!singleTab()) {
|
|
3158
|
+
<!-- Mobile: dropdown selector -->
|
|
3159
|
+
@if (isMobile()) {
|
|
3160
|
+
<div class="ux-dl__mobile-tabs">
|
|
3161
|
+
<p-select
|
|
3162
|
+
[options]="tabOptions()"
|
|
3163
|
+
[ngModel]="activeTab()"
|
|
3164
|
+
(ngModelChange)="activeTab.set($event)"
|
|
3165
|
+
optionLabel="label"
|
|
3166
|
+
optionValue="value"
|
|
3167
|
+
styleClass="w-full ux-dl__mobile-select"
|
|
3168
|
+
/>
|
|
3169
|
+
</div>
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
<!-- Desktop: horizontal tab bar (outside scroll → stays fixed below header) -->
|
|
3173
|
+
<p-tablist
|
|
3174
|
+
class="flex-shrink-0 ux-dl__tablist"
|
|
3175
|
+
[style.display]="isMobile() ? 'none' : null"
|
|
3176
|
+
[pt]="{ content: { class: 'w-full' }, tabList: { class: 'w-full pl-8 p-0' } }"
|
|
3177
|
+
>
|
|
3178
|
+
@for (tab of tabs(); track tab.value) {
|
|
3179
|
+
<p-tab [value]="tab.value" [pt]="{ root: { class: 'flex-1 justify-center' } }">
|
|
3180
|
+
@if (tab.icon) {
|
|
3181
|
+
<i [class]="tab.icon" class="mr-2 text-sm"></i>
|
|
3182
|
+
}
|
|
3183
|
+
{{ tab.label }}
|
|
3184
|
+
</p-tab>
|
|
3185
|
+
}
|
|
3186
|
+
</p-tablist>
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
<!-- Scrollable body (only content scrolls, tabs stay above) -->
|
|
3190
|
+
<div class="flex flex-col flex-1 min-h-0 overflow-y-auto overflow-x-hidden ux-dl__scroll"
|
|
3191
|
+
(scroll)="onScroll($event)">
|
|
3192
|
+
|
|
3193
|
+
<!-- Content + Sidebar row -->
|
|
3194
|
+
<div class="flex flex-col lg:flex-row items-start gap-6 w-full py-4 lg:py-6">
|
|
3195
|
+
|
|
3196
|
+
<!-- Main column: tab panels -->
|
|
3197
|
+
<div class="w-full flex-1 min-w-0 flex flex-col gap-6">
|
|
3198
|
+
<p-tabpanels>
|
|
3199
|
+
@for (tab of tabs(); track tab.value) {
|
|
3200
|
+
<p-tabpanel [value]="tab.value">
|
|
3201
|
+
<div class="flex flex-col gap-6">
|
|
3202
|
+
@if (getTabTemplate(tab.value); as tmpl) {
|
|
3203
|
+
<ng-container [ngTemplateOutlet]="tmpl" />
|
|
3204
|
+
}
|
|
3205
|
+
</div>
|
|
3206
|
+
</p-tabpanel>
|
|
3207
|
+
}
|
|
3208
|
+
</p-tabpanels>
|
|
3209
|
+
</div>
|
|
3210
|
+
|
|
3211
|
+
<!-- Sidebar -->
|
|
3212
|
+
<aside class="w-full lg:w-[380px] shrink-0 flex flex-col lg:sticky lg:top-4 lg:self-start lg:pb-8">
|
|
3213
|
+
<div class="ux-dl__sidebar-inner w-full">
|
|
3214
|
+
<ng-content select="[ux-detail-sidebar]" />
|
|
3215
|
+
</div>
|
|
3216
|
+
</aside>
|
|
3217
|
+
</div>
|
|
3218
|
+
|
|
3219
|
+
</div>
|
|
3220
|
+
|
|
3221
|
+
</p-tabs>
|
|
3222
|
+
|
|
3223
|
+
</div>
|
|
3224
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;font-family:var(--p-font-family, \"Noto Sans\", sans-serif);background:transparent;color:var(--p-text-color)}.ux-dl__header{background:transparent}.ux-dl__scroll{scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--p-primary-color) 25%,transparent) color-mix(in srgb,var(--p-surface-500) 8%,transparent)}.ux-dl__scroll::-webkit-scrollbar{width:10px;height:10px}.ux-dl__scroll::-webkit-scrollbar-track{background:color-mix(in srgb,var(--p-surface-500) 8%,transparent);border-radius:var(--p-content-border-radius, .375rem)}.ux-dl__scroll::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--p-primary-color) 25%,transparent);border-radius:var(--p-content-border-radius, .375rem)}.ux-dl__scroll::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--p-primary-color) 45%,transparent)}.ux-dl__sidebar-inner{display:flex;flex-direction:column;gap:1.5rem}.ux-dl__header-meta{overflow:hidden;max-height:80px;opacity:1;transition:max-height .25s ease-out,opacity .2s ease-out}.ux-dl__header-meta--hidden{max-height:0;opacity:0}.ux-dl__tablist{display:flex;overflow:hidden;background:var(--p-surface-950);padding-inline:.75rem}@media screen and (min-width:640px){.ux-dl__tablist{padding-inline:1rem}}@media screen and (min-width:1024px){.ux-dl__tablist{padding-inline:1.5rem}}.ux-dl__mobile-tabs{position:sticky;top:0;z-index:5}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: TabsModule }, { kind: "component", type: i4$3.Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: i4$3.TabPanels, selector: "p-tabpanels" }, { kind: "component", type: i4$3.TabPanel, selector: "p-tabpanel", inputs: ["lazy", "value"], outputs: ["valueChange"] }, { kind: "component", type: i4$3.TabList, selector: "p-tablist" }, { kind: "component", type: i4$3.Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3225
|
+
}
|
|
3226
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DetailLayoutComponent, decorators: [{
|
|
3227
|
+
type: Component,
|
|
3228
|
+
args: [{ selector: 'ux-detail-layout', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, SelectModule, TabsModule], host: { class: 'ux-detail-layout' }, template: `
|
|
3229
|
+
<div class="flex flex-col flex-1 min-h-0">
|
|
3230
|
+
|
|
3231
|
+
<!-- Sticky header (projected) -->
|
|
3232
|
+
<div class="ux-dl__header flex-shrink-0 z-10">
|
|
3233
|
+
<div>
|
|
3234
|
+
<ng-content select="[ux-detail-header]" />
|
|
3235
|
+
</div>
|
|
3236
|
+
<div class="ux-dl__header-meta" [class.ux-dl__header-meta--hidden]="scrolled()">
|
|
3237
|
+
<ng-content select="[ux-detail-header-meta]" />
|
|
3238
|
+
</div>
|
|
3239
|
+
</div>
|
|
3240
|
+
|
|
3241
|
+
<!-- p-tabs wraps tablist + scrollable panels for state binding -->
|
|
3242
|
+
<p-tabs class="flex flex-col flex-1 min-h-0" [value]="activeTab()" (valueChange)="activeTab.set($event + '')">
|
|
3243
|
+
|
|
3244
|
+
@if (!singleTab()) {
|
|
3245
|
+
<!-- Mobile: dropdown selector -->
|
|
3246
|
+
@if (isMobile()) {
|
|
3247
|
+
<div class="ux-dl__mobile-tabs">
|
|
3248
|
+
<p-select
|
|
3249
|
+
[options]="tabOptions()"
|
|
3250
|
+
[ngModel]="activeTab()"
|
|
3251
|
+
(ngModelChange)="activeTab.set($event)"
|
|
3252
|
+
optionLabel="label"
|
|
3253
|
+
optionValue="value"
|
|
3254
|
+
styleClass="w-full ux-dl__mobile-select"
|
|
3255
|
+
/>
|
|
3256
|
+
</div>
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
<!-- Desktop: horizontal tab bar (outside scroll → stays fixed below header) -->
|
|
3260
|
+
<p-tablist
|
|
3261
|
+
class="flex-shrink-0 ux-dl__tablist"
|
|
3262
|
+
[style.display]="isMobile() ? 'none' : null"
|
|
3263
|
+
[pt]="{ content: { class: 'w-full' }, tabList: { class: 'w-full pl-8 p-0' } }"
|
|
3264
|
+
>
|
|
3265
|
+
@for (tab of tabs(); track tab.value) {
|
|
3266
|
+
<p-tab [value]="tab.value" [pt]="{ root: { class: 'flex-1 justify-center' } }">
|
|
3267
|
+
@if (tab.icon) {
|
|
3268
|
+
<i [class]="tab.icon" class="mr-2 text-sm"></i>
|
|
3269
|
+
}
|
|
3270
|
+
{{ tab.label }}
|
|
3271
|
+
</p-tab>
|
|
3272
|
+
}
|
|
3273
|
+
</p-tablist>
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
<!-- Scrollable body (only content scrolls, tabs stay above) -->
|
|
3277
|
+
<div class="flex flex-col flex-1 min-h-0 overflow-y-auto overflow-x-hidden ux-dl__scroll"
|
|
3278
|
+
(scroll)="onScroll($event)">
|
|
3279
|
+
|
|
3280
|
+
<!-- Content + Sidebar row -->
|
|
3281
|
+
<div class="flex flex-col lg:flex-row items-start gap-6 w-full py-4 lg:py-6">
|
|
3282
|
+
|
|
3283
|
+
<!-- Main column: tab panels -->
|
|
3284
|
+
<div class="w-full flex-1 min-w-0 flex flex-col gap-6">
|
|
3285
|
+
<p-tabpanels>
|
|
3286
|
+
@for (tab of tabs(); track tab.value) {
|
|
3287
|
+
<p-tabpanel [value]="tab.value">
|
|
3288
|
+
<div class="flex flex-col gap-6">
|
|
3289
|
+
@if (getTabTemplate(tab.value); as tmpl) {
|
|
3290
|
+
<ng-container [ngTemplateOutlet]="tmpl" />
|
|
3291
|
+
}
|
|
3292
|
+
</div>
|
|
3293
|
+
</p-tabpanel>
|
|
3294
|
+
}
|
|
3295
|
+
</p-tabpanels>
|
|
3296
|
+
</div>
|
|
3297
|
+
|
|
3298
|
+
<!-- Sidebar -->
|
|
3299
|
+
<aside class="w-full lg:w-[380px] shrink-0 flex flex-col lg:sticky lg:top-4 lg:self-start lg:pb-8">
|
|
3300
|
+
<div class="ux-dl__sidebar-inner w-full">
|
|
3301
|
+
<ng-content select="[ux-detail-sidebar]" />
|
|
3302
|
+
</div>
|
|
3303
|
+
</aside>
|
|
3304
|
+
</div>
|
|
3305
|
+
|
|
3306
|
+
</div>
|
|
3307
|
+
|
|
3308
|
+
</p-tabs>
|
|
3309
|
+
|
|
3310
|
+
</div>
|
|
3311
|
+
`, styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;font-family:var(--p-font-family, \"Noto Sans\", sans-serif);background:transparent;color:var(--p-text-color)}.ux-dl__header{background:transparent}.ux-dl__scroll{scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--p-primary-color) 25%,transparent) color-mix(in srgb,var(--p-surface-500) 8%,transparent)}.ux-dl__scroll::-webkit-scrollbar{width:10px;height:10px}.ux-dl__scroll::-webkit-scrollbar-track{background:color-mix(in srgb,var(--p-surface-500) 8%,transparent);border-radius:var(--p-content-border-radius, .375rem)}.ux-dl__scroll::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--p-primary-color) 25%,transparent);border-radius:var(--p-content-border-radius, .375rem)}.ux-dl__scroll::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--p-primary-color) 45%,transparent)}.ux-dl__sidebar-inner{display:flex;flex-direction:column;gap:1.5rem}.ux-dl__header-meta{overflow:hidden;max-height:80px;opacity:1;transition:max-height .25s ease-out,opacity .2s ease-out}.ux-dl__header-meta--hidden{max-height:0;opacity:0}.ux-dl__tablist{display:flex;overflow:hidden;background:var(--p-surface-950);padding-inline:.75rem}@media screen and (min-width:640px){.ux-dl__tablist{padding-inline:1rem}}@media screen and (min-width:1024px){.ux-dl__tablist{padding-inline:1.5rem}}.ux-dl__mobile-tabs{position:sticky;top:0;z-index:5}\n"] }]
|
|
3312
|
+
}], ctorParameters: () => [], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: true }] }], activeTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTab", required: false }] }, { type: i0.Output, args: ["activeTabChange"] }], tabTemplates: [{
|
|
3313
|
+
type: ContentChildren,
|
|
3314
|
+
args: [DetailTabDirective]
|
|
3315
|
+
}] } });
|
|
3316
|
+
|
|
3317
|
+
/**
|
|
3318
|
+
* Horizontal row of pill-shaped sub-tab buttons. Styling aligns with sidebar menu item
|
|
3319
|
+
* hover/active tokens (`--d-menuitem-*`).
|
|
3320
|
+
*/
|
|
3321
|
+
class PillTabsComponent {
|
|
3322
|
+
items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
3323
|
+
activeValue = model('', ...(ngDevMode ? [{ debugName: "activeValue" }] : []));
|
|
3324
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: PillTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3325
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: PillTabsComponent, isStandalone: true, selector: "ux-pill-tabs", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, activeValue: { classPropertyName: "activeValue", publicName: "activeValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeValue: "activeValueChange" }, host: { classAttribute: "ux-pill-tabs block" }, ngImport: i0, template: `
|
|
3326
|
+
<div class="ux-pill-tabs__row" role="tablist">
|
|
3327
|
+
@for (item of items(); track item.value) {
|
|
3328
|
+
<button
|
|
3329
|
+
type="button"
|
|
3330
|
+
class="ux-pill-tabs__btn"
|
|
3331
|
+
role="tab"
|
|
3332
|
+
[attr.aria-selected]="activeValue() === item.value"
|
|
3333
|
+
[class.ux-pill-tabs__btn--active]="activeValue() === item.value"
|
|
3334
|
+
(click)="activeValue.set(item.value)"
|
|
3335
|
+
>
|
|
3336
|
+
{{ item.label }}
|
|
3337
|
+
</button>
|
|
3338
|
+
}
|
|
3339
|
+
</div>
|
|
3340
|
+
`, isInline: true, styles: [".ux-pill-tabs__row{display:flex;flex-wrap:wrap;gap:.5rem}.ux-pill-tabs__btn{border-radius:9999px;padding:.375rem .875rem;font-size:var(--p-font-size, .875rem);font-weight:600;font-family:inherit;cursor:pointer;transition:all .15s ease;border:1px solid var(--p-primary-800);background:transparent;color:var(--p-text-muted-color)}:host-context(.app-dark) .ux-pill-tabs__btn:not(.ux-pill-tabs__btn--active){border-color:var(--p-surface-700)}.ux-pill-tabs__btn:hover:not(.ux-pill-tabs__btn--active){background:var(--d-menuitem-hover-bg);color:var(--p-primary-950)}:host-context(.app-dark) .ux-pill-tabs__btn:hover:not(.ux-pill-tabs__btn--active){color:var(--p-primary-200)}.ux-pill-tabs__btn--active{background:var(--p-primary-200);border-color:transparent;color:var(--p-primary-950)}:host-context(.app-dark) .ux-pill-tabs__btn--active{color:var(--p-primary-950)}.ux-pill-tabs__btn:focus{outline:none;box-shadow:none}.ux-pill-tabs__btn:focus-visible{outline:none;box-shadow:var(--d-menuitem-focus-shadow)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3341
|
+
}
|
|
3342
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: PillTabsComponent, decorators: [{
|
|
3343
|
+
type: Component,
|
|
3344
|
+
args: [{ selector: 'ux-pill-tabs', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'ux-pill-tabs block' }, template: `
|
|
3345
|
+
<div class="ux-pill-tabs__row" role="tablist">
|
|
3346
|
+
@for (item of items(); track item.value) {
|
|
3347
|
+
<button
|
|
3348
|
+
type="button"
|
|
3349
|
+
class="ux-pill-tabs__btn"
|
|
3350
|
+
role="tab"
|
|
3351
|
+
[attr.aria-selected]="activeValue() === item.value"
|
|
3352
|
+
[class.ux-pill-tabs__btn--active]="activeValue() === item.value"
|
|
3353
|
+
(click)="activeValue.set(item.value)"
|
|
3354
|
+
>
|
|
3355
|
+
{{ item.label }}
|
|
3356
|
+
</button>
|
|
3357
|
+
}
|
|
3358
|
+
</div>
|
|
3359
|
+
`, styles: [".ux-pill-tabs__row{display:flex;flex-wrap:wrap;gap:.5rem}.ux-pill-tabs__btn{border-radius:9999px;padding:.375rem .875rem;font-size:var(--p-font-size, .875rem);font-weight:600;font-family:inherit;cursor:pointer;transition:all .15s ease;border:1px solid var(--p-primary-800);background:transparent;color:var(--p-text-muted-color)}:host-context(.app-dark) .ux-pill-tabs__btn:not(.ux-pill-tabs__btn--active){border-color:var(--p-surface-700)}.ux-pill-tabs__btn:hover:not(.ux-pill-tabs__btn--active){background:var(--d-menuitem-hover-bg);color:var(--p-primary-950)}:host-context(.app-dark) .ux-pill-tabs__btn:hover:not(.ux-pill-tabs__btn--active){color:var(--p-primary-200)}.ux-pill-tabs__btn--active{background:var(--p-primary-200);border-color:transparent;color:var(--p-primary-950)}:host-context(.app-dark) .ux-pill-tabs__btn--active{color:var(--p-primary-950)}.ux-pill-tabs__btn:focus{outline:none;box-shadow:none}.ux-pill-tabs__btn:focus-visible{outline:none;box-shadow:var(--d-menuitem-focus-shadow)}\n"] }]
|
|
3360
|
+
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], activeValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeValue", required: false }] }, { type: i0.Output, args: ["activeValueChange"] }] } });
|
|
3361
|
+
|
|
3362
|
+
class DocumentsCardComponent {
|
|
3363
|
+
documents = input([], ...(ngDevMode ? [{ debugName: "documents" }] : []));
|
|
3364
|
+
rows = input(5, ...(ngDevMode ? [{ debugName: "rows" }] : []));
|
|
3365
|
+
expanded = signal(false, ...(ngDevMode ? [{ debugName: "expanded" }] : []));
|
|
3366
|
+
activeFilter = signal('All Files', ...(ngDevMode ? [{ debugName: "activeFilter" }] : []));
|
|
3367
|
+
searchQuery = model('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
|
|
3368
|
+
fileTypes = computed(() => {
|
|
3369
|
+
const types = [...new Set(this.documents().map(d => d.type))];
|
|
3370
|
+
types.sort();
|
|
3371
|
+
return types;
|
|
3372
|
+
}, ...(ngDevMode ? [{ debugName: "fileTypes" }] : []));
|
|
3373
|
+
filterOptions = computed(() => ['All Files', ...this.fileTypes(), 'Other'], ...(ngDevMode ? [{ debugName: "filterOptions" }] : []));
|
|
3374
|
+
pillTabItems = computed(() => this.filterOptions().map(f => ({ value: f, label: f })), ...(ngDevMode ? [{ debugName: "pillTabItems" }] : []));
|
|
3375
|
+
summary = computed(() => {
|
|
3376
|
+
const docs = this.documents();
|
|
3377
|
+
const count = docs.length;
|
|
3378
|
+
if (count === 0)
|
|
3379
|
+
return 'No files attached';
|
|
3380
|
+
const types = this.fileTypes();
|
|
3381
|
+
const fileWord = count === 1 ? 'file' : 'files';
|
|
3382
|
+
if (types.length === 0)
|
|
3383
|
+
return `${count} ${fileWord} attached`;
|
|
3384
|
+
return `${count} ${fileWord} · ${types.join(', ')}`;
|
|
3385
|
+
}, ...(ngDevMode ? [{ debugName: "summary" }] : []));
|
|
3386
|
+
filtered = computed(() => {
|
|
3387
|
+
let docs = this.documents();
|
|
3388
|
+
const query = this.searchQuery().trim().toLowerCase();
|
|
3389
|
+
if (query) {
|
|
3390
|
+
docs = docs.filter(d => d.fileName.toLowerCase().includes(query) || d.owner.toLowerCase().includes(query));
|
|
3391
|
+
}
|
|
3392
|
+
const filter = this.activeFilter();
|
|
3393
|
+
if (filter === 'All Files')
|
|
3394
|
+
return docs;
|
|
3395
|
+
if (filter === 'Other') {
|
|
3396
|
+
const knownTypes = this.fileTypes();
|
|
3397
|
+
return docs.filter(d => !knownTypes.includes(d.type));
|
|
3398
|
+
}
|
|
3399
|
+
return docs.filter(d => d.type === filter);
|
|
3400
|
+
}, ...(ngDevMode ? [{ debugName: "filtered" }] : []));
|
|
3401
|
+
menuItems = [];
|
|
3402
|
+
onMenuToggle(event, _doc, menu) {
|
|
3403
|
+
this.menuItems = [
|
|
3404
|
+
{ label: 'Preview', icon: 'pi pi-eye' },
|
|
3405
|
+
{ label: 'Share', icon: 'pi pi-share-alt' },
|
|
3406
|
+
{ separator: true },
|
|
3407
|
+
{ label: 'Delete', icon: 'pi pi-trash', styleClass: 'text-red-500' }
|
|
3408
|
+
];
|
|
3409
|
+
menu.toggle(event);
|
|
3410
|
+
}
|
|
3411
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DocumentsCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3412
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: DocumentsCardComponent, isStandalone: true, selector: "ux-documents-card", inputs: { documents: { classPropertyName: "documents", publicName: "documents", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, searchQuery: { classPropertyName: "searchQuery", publicName: "searchQuery", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchQuery: "searchQueryChange" }, host: { classAttribute: "ux-documents-card block" }, ngImport: i0, template: `
|
|
3413
|
+
<div class="card flex flex-col overflow-hidden">
|
|
3414
|
+
<p-panel [toggleable]="true" [collapsed]="!expanded()" (collapsedChange)="expanded.set(!$event)" toggler="header">
|
|
3415
|
+
<ng-template #headericons let-collapsed>
|
|
3416
|
+
<i class="pi text-sm text-darkblue-500 dark:text-surface-0" [ngClass]="collapsed ? 'pi-chevron-down' : 'pi-chevron-up'"></i>
|
|
3417
|
+
</ng-template>
|
|
3418
|
+
<ng-template #header>
|
|
3419
|
+
<div class="flex items-center gap-3 flex-1">
|
|
3420
|
+
<div class="w-[34px] h-[34px] rounded-[10px] flex items-center justify-center shrink-0">
|
|
3421
|
+
<i class="pi pi-folder text-deepsea-500 dark:text-surface-0"></i>
|
|
3422
|
+
</div>
|
|
3423
|
+
<div class="flex flex-col">
|
|
3424
|
+
<h4 class="title-h4 text-left text-deepsea-500 dark:text-surface-0">Documents</h4>
|
|
3425
|
+
<span class="text-surface-500 dark:text-surface-300 text-sm font-medium leading-tight">{{ summary() }}</span>
|
|
3426
|
+
</div>
|
|
3427
|
+
</div>
|
|
3428
|
+
</ng-template>
|
|
3429
|
+
<div class="flex flex-col gap-4 pt-4">
|
|
3430
|
+
<ux-pill-tabs [items]="pillTabItems()" [(activeValue)]="activeFilter" />
|
|
3431
|
+
|
|
3432
|
+
<p-iconfield>
|
|
3433
|
+
<p-inputicon class="pi pi-search" />
|
|
3434
|
+
<input pInputText [(ngModel)]="searchQuery" placeholder="Search documents" class="w-full" />
|
|
3435
|
+
</p-iconfield>
|
|
3436
|
+
|
|
3437
|
+
@if (filtered().length > 0) {
|
|
3438
|
+
<p-table
|
|
3439
|
+
[value]="filtered()"
|
|
3440
|
+
[paginator]="true"
|
|
3441
|
+
[rows]="rows()"
|
|
3442
|
+
sortMode="multiple"
|
|
3443
|
+
styleClass="flex flex-col rounded-2xl overflow-hidden [&>[data-pc-section=paginatorcontainer]]:border-0! [&>[data-pc-section=paginatorcontainer]]:mt-auto [&_[data-pc-name=pcpaginator]]:rounded-none!"
|
|
3444
|
+
tableStyleClass="w-full table-fixed"
|
|
3445
|
+
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink"
|
|
3446
|
+
>
|
|
3447
|
+
<ng-template #header>
|
|
3448
|
+
<tr>
|
|
3449
|
+
<th pSortableColumn="fileName" class="w-1/2">File Name <p-sortIcon field="fileName" /></th>
|
|
3450
|
+
<th pSortableColumn="type" class="w-1/4">Type <p-sortIcon field="type" /></th>
|
|
3451
|
+
<th class="w-1/4">Actions</th>
|
|
3452
|
+
</tr>
|
|
3453
|
+
</ng-template>
|
|
3454
|
+
<ng-template #body let-doc>
|
|
3455
|
+
<tr>
|
|
3456
|
+
<td>
|
|
3457
|
+
<div class="flex items-center gap-3 py-1 min-w-0">
|
|
3458
|
+
<i class="pi text-xl text-surface-600 dark:text-surface-300 shrink-0" [ngClass]="doc.icon"></i>
|
|
3459
|
+
<span class="text-surface-700 dark:text-surface-100 text-sm truncate">{{ doc.fileName }}</span>
|
|
3460
|
+
</div>
|
|
3461
|
+
</td>
|
|
3462
|
+
<td>
|
|
3463
|
+
<p-tag [value]="doc.type" styleClass="px-2 py-1" />
|
|
3464
|
+
</td>
|
|
3465
|
+
<td>
|
|
3466
|
+
<div class="flex items-center gap-1">
|
|
3467
|
+
<p-button icon="pi pi-download" [rounded]="true" [text]="true" size="small" severity="secondary" styleClass="cursor-pointer" ariaLabel="Download" />
|
|
3468
|
+
<p-button icon="pi pi-ellipsis-h" [rounded]="true" [text]="true" size="small" severity="secondary" styleClass="cursor-pointer" ariaLabel="More options" (onClick)="onMenuToggle($event, doc, docMenu)" />
|
|
3469
|
+
<p-menu #docMenu [model]="menuItems" [popup]="true" styleClass="w-48" appendTo="body" />
|
|
3470
|
+
</div>
|
|
3471
|
+
</td>
|
|
3472
|
+
</tr>
|
|
3473
|
+
</ng-template>
|
|
3474
|
+
</p-table>
|
|
3475
|
+
} @else {
|
|
3476
|
+
<div class="flex flex-col items-center gap-3 py-8 text-center">
|
|
3477
|
+
<i class="pi pi-folder-open text-3xl text-surface-300 dark:text-surface-500"></i>
|
|
3478
|
+
<span class="text-surface-600 dark:text-surface-300 text-sm">No documents to show</span>
|
|
3479
|
+
</div>
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
<p-fileupload
|
|
3483
|
+
name="documents[]"
|
|
3484
|
+
[multiple]="true"
|
|
3485
|
+
maxFileSize="10000000"
|
|
3486
|
+
mode="advanced"
|
|
3487
|
+
[auto]="false"
|
|
3488
|
+
chooseLabel="Upload File"
|
|
3489
|
+
chooseIcon="pi pi-upload"
|
|
3490
|
+
[showUploadButton]="false"
|
|
3491
|
+
[showCancelButton]="false"
|
|
3492
|
+
[pt]="{ root: { class: 'bg-transparent' }, header: { class: 'bg-transparent' }, content: { class: 'bg-transparent' } }"
|
|
3493
|
+
>
|
|
3494
|
+
<ng-template #header let-chooseCallback="chooseCallback">
|
|
3495
|
+
<div class="flex items-center gap-2 w-full">
|
|
3496
|
+
<p-button icon="pi pi-upload" label="Upload File" (onClick)="chooseCallback()" />
|
|
3497
|
+
<p-button icon="pi pi-link" label="Share Link" [outlined]="true" styleClass="!text-primary-600 !border-primary-600" />
|
|
3498
|
+
</div>
|
|
3499
|
+
</ng-template>
|
|
3500
|
+
<ng-template #empty>
|
|
3501
|
+
<div class="flex flex-col items-center gap-2 py-4">
|
|
3502
|
+
<i class="pi pi-cloud-upload text-2xl text-surface-400 dark:text-surface-300"></i>
|
|
3503
|
+
<span class="text-surface-500 dark:text-surface-100 text-sm">Drag and drop files here</span>
|
|
3504
|
+
</div>
|
|
3505
|
+
</ng-template>
|
|
3506
|
+
</p-fileupload>
|
|
3507
|
+
</div>
|
|
3508
|
+
</p-panel>
|
|
3509
|
+
</div>
|
|
3510
|
+
`, isInline: true, styles: [""], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2$1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i3$5.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i5$1.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i6.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: MenuModule }, { kind: "component", type: i7.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex", "appendTo", "motionOptions"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i8$1.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i8$1.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i8$1.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i9$1.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: PillTabsComponent, selector: "ux-pill-tabs", inputs: ["items", "activeValue"], outputs: ["activeValueChange"] }, { kind: "ngmodule", type: PanelModule }, { kind: "component", type: i10$1.Panel, selector: "p-panel", inputs: ["id", "toggleable", "header", "collapsed", "styleClass", "iconPos", "showHeader", "toggler", "transitionOptions", "toggleButtonProps", "motionOptions"], outputs: ["collapsedChange", "onBeforeToggle", "onAfterToggle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3511
|
+
}
|
|
3512
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DocumentsCardComponent, decorators: [{
|
|
3513
|
+
type: Component,
|
|
3514
|
+
args: [{ selector: 'ux-documents-card', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass, FormsModule, ButtonModule, FileUploadModule, IconFieldModule, InputIconModule, InputTextModule, MenuModule, TableModule, TagModule, PillTabsComponent, PanelModule], host: { class: 'ux-documents-card block' }, template: `
|
|
3515
|
+
<div class="card flex flex-col overflow-hidden">
|
|
3516
|
+
<p-panel [toggleable]="true" [collapsed]="!expanded()" (collapsedChange)="expanded.set(!$event)" toggler="header">
|
|
3517
|
+
<ng-template #headericons let-collapsed>
|
|
3518
|
+
<i class="pi text-sm text-darkblue-500 dark:text-surface-0" [ngClass]="collapsed ? 'pi-chevron-down' : 'pi-chevron-up'"></i>
|
|
3519
|
+
</ng-template>
|
|
3520
|
+
<ng-template #header>
|
|
3521
|
+
<div class="flex items-center gap-3 flex-1">
|
|
3522
|
+
<div class="w-[34px] h-[34px] rounded-[10px] flex items-center justify-center shrink-0">
|
|
3523
|
+
<i class="pi pi-folder text-deepsea-500 dark:text-surface-0"></i>
|
|
3524
|
+
</div>
|
|
3525
|
+
<div class="flex flex-col">
|
|
3526
|
+
<h4 class="title-h4 text-left text-deepsea-500 dark:text-surface-0">Documents</h4>
|
|
3527
|
+
<span class="text-surface-500 dark:text-surface-300 text-sm font-medium leading-tight">{{ summary() }}</span>
|
|
3528
|
+
</div>
|
|
3529
|
+
</div>
|
|
3530
|
+
</ng-template>
|
|
3531
|
+
<div class="flex flex-col gap-4 pt-4">
|
|
3532
|
+
<ux-pill-tabs [items]="pillTabItems()" [(activeValue)]="activeFilter" />
|
|
3533
|
+
|
|
3534
|
+
<p-iconfield>
|
|
3535
|
+
<p-inputicon class="pi pi-search" />
|
|
3536
|
+
<input pInputText [(ngModel)]="searchQuery" placeholder="Search documents" class="w-full" />
|
|
3537
|
+
</p-iconfield>
|
|
3538
|
+
|
|
3539
|
+
@if (filtered().length > 0) {
|
|
3540
|
+
<p-table
|
|
3541
|
+
[value]="filtered()"
|
|
3542
|
+
[paginator]="true"
|
|
3543
|
+
[rows]="rows()"
|
|
3544
|
+
sortMode="multiple"
|
|
3545
|
+
styleClass="flex flex-col rounded-2xl overflow-hidden [&>[data-pc-section=paginatorcontainer]]:border-0! [&>[data-pc-section=paginatorcontainer]]:mt-auto [&_[data-pc-name=pcpaginator]]:rounded-none!"
|
|
3546
|
+
tableStyleClass="w-full table-fixed"
|
|
3547
|
+
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink"
|
|
3548
|
+
>
|
|
3549
|
+
<ng-template #header>
|
|
3550
|
+
<tr>
|
|
3551
|
+
<th pSortableColumn="fileName" class="w-1/2">File Name <p-sortIcon field="fileName" /></th>
|
|
3552
|
+
<th pSortableColumn="type" class="w-1/4">Type <p-sortIcon field="type" /></th>
|
|
3553
|
+
<th class="w-1/4">Actions</th>
|
|
3554
|
+
</tr>
|
|
3555
|
+
</ng-template>
|
|
3556
|
+
<ng-template #body let-doc>
|
|
3557
|
+
<tr>
|
|
3558
|
+
<td>
|
|
3559
|
+
<div class="flex items-center gap-3 py-1 min-w-0">
|
|
3560
|
+
<i class="pi text-xl text-surface-600 dark:text-surface-300 shrink-0" [ngClass]="doc.icon"></i>
|
|
3561
|
+
<span class="text-surface-700 dark:text-surface-100 text-sm truncate">{{ doc.fileName }}</span>
|
|
3562
|
+
</div>
|
|
3563
|
+
</td>
|
|
3564
|
+
<td>
|
|
3565
|
+
<p-tag [value]="doc.type" styleClass="px-2 py-1" />
|
|
3566
|
+
</td>
|
|
3567
|
+
<td>
|
|
3568
|
+
<div class="flex items-center gap-1">
|
|
3569
|
+
<p-button icon="pi pi-download" [rounded]="true" [text]="true" size="small" severity="secondary" styleClass="cursor-pointer" ariaLabel="Download" />
|
|
3570
|
+
<p-button icon="pi pi-ellipsis-h" [rounded]="true" [text]="true" size="small" severity="secondary" styleClass="cursor-pointer" ariaLabel="More options" (onClick)="onMenuToggle($event, doc, docMenu)" />
|
|
3571
|
+
<p-menu #docMenu [model]="menuItems" [popup]="true" styleClass="w-48" appendTo="body" />
|
|
3572
|
+
</div>
|
|
3573
|
+
</td>
|
|
3574
|
+
</tr>
|
|
3575
|
+
</ng-template>
|
|
3576
|
+
</p-table>
|
|
3577
|
+
} @else {
|
|
3578
|
+
<div class="flex flex-col items-center gap-3 py-8 text-center">
|
|
3579
|
+
<i class="pi pi-folder-open text-3xl text-surface-300 dark:text-surface-500"></i>
|
|
3580
|
+
<span class="text-surface-600 dark:text-surface-300 text-sm">No documents to show</span>
|
|
3581
|
+
</div>
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3584
|
+
<p-fileupload
|
|
3585
|
+
name="documents[]"
|
|
3586
|
+
[multiple]="true"
|
|
3587
|
+
maxFileSize="10000000"
|
|
3588
|
+
mode="advanced"
|
|
3589
|
+
[auto]="false"
|
|
3590
|
+
chooseLabel="Upload File"
|
|
3591
|
+
chooseIcon="pi pi-upload"
|
|
3592
|
+
[showUploadButton]="false"
|
|
3593
|
+
[showCancelButton]="false"
|
|
3594
|
+
[pt]="{ root: { class: 'bg-transparent' }, header: { class: 'bg-transparent' }, content: { class: 'bg-transparent' } }"
|
|
3595
|
+
>
|
|
3596
|
+
<ng-template #header let-chooseCallback="chooseCallback">
|
|
3597
|
+
<div class="flex items-center gap-2 w-full">
|
|
3598
|
+
<p-button icon="pi pi-upload" label="Upload File" (onClick)="chooseCallback()" />
|
|
3599
|
+
<p-button icon="pi pi-link" label="Share Link" [outlined]="true" styleClass="!text-primary-600 !border-primary-600" />
|
|
3600
|
+
</div>
|
|
3601
|
+
</ng-template>
|
|
3602
|
+
<ng-template #empty>
|
|
3603
|
+
<div class="flex flex-col items-center gap-2 py-4">
|
|
3604
|
+
<i class="pi pi-cloud-upload text-2xl text-surface-400 dark:text-surface-300"></i>
|
|
3605
|
+
<span class="text-surface-500 dark:text-surface-100 text-sm">Drag and drop files here</span>
|
|
3606
|
+
</div>
|
|
3607
|
+
</ng-template>
|
|
3608
|
+
</p-fileupload>
|
|
3609
|
+
</div>
|
|
3610
|
+
</p-panel>
|
|
3611
|
+
</div>
|
|
3612
|
+
` }]
|
|
3613
|
+
}], propDecorators: { documents: [{ type: i0.Input, args: [{ isSignal: true, alias: "documents", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], searchQuery: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchQuery", required: false }] }, { type: i0.Output, args: ["searchQueryChange"] }] } });
|
|
3614
|
+
|
|
3615
|
+
class UxSelectComponent {
|
|
3616
|
+
options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
3617
|
+
optionLabel = input('label', ...(ngDevMode ? [{ debugName: "optionLabel" }] : []));
|
|
3618
|
+
optionValue = input('value', ...(ngDevMode ? [{ debugName: "optionValue" }] : []));
|
|
3619
|
+
optionGroupLabel = input('label', ...(ngDevMode ? [{ debugName: "optionGroupLabel" }] : []));
|
|
3620
|
+
optionGroupChildren = input('items', ...(ngDevMode ? [{ debugName: "optionGroupChildren" }] : []));
|
|
3621
|
+
placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
3622
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
3623
|
+
filter = input(false, ...(ngDevMode ? [{ debugName: "filter" }] : []));
|
|
3624
|
+
showClear = input(false, ...(ngDevMode ? [{ debugName: "showClear" }] : []));
|
|
3625
|
+
emptyMessage = input('No results found', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : []));
|
|
3626
|
+
group = input(false, ...(ngDevMode ? [{ debugName: "group" }] : []));
|
|
3627
|
+
styleClass = input('', ...(ngDevMode ? [{ debugName: "styleClass" }] : []));
|
|
3628
|
+
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
3629
|
+
onChange = output();
|
|
3630
|
+
onFilter = output();
|
|
3631
|
+
resolvedStyleClass = computed(() => {
|
|
3632
|
+
const base = 'ux-select__inner';
|
|
3633
|
+
const extra = this.styleClass();
|
|
3634
|
+
return extra ? `${base} ${extra}` : base;
|
|
3635
|
+
}, ...(ngDevMode ? [{ debugName: "resolvedStyleClass" }] : []));
|
|
3636
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: UxSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3637
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.8", type: UxSelectComponent, isStandalone: true, selector: "ux-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, optionGroupLabel: { classPropertyName: "optionGroupLabel", publicName: "optionGroupLabel", isSignal: true, isRequired: false, transformFunction: null }, optionGroupChildren: { classPropertyName: "optionGroupChildren", publicName: "optionGroupChildren", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onChange: "onChange", onFilter: "onFilter" }, host: { classAttribute: "ux-select" }, ngImport: i0, template: `
|
|
3638
|
+
<p-select
|
|
3639
|
+
[options]="options()"
|
|
3640
|
+
[optionLabel]="optionLabel()"
|
|
3641
|
+
[optionValue]="optionValue()"
|
|
3642
|
+
[optionGroupLabel]="optionGroupLabel()"
|
|
3643
|
+
[optionGroupChildren]="optionGroupChildren()"
|
|
3644
|
+
[placeholder]="placeholder()"
|
|
3645
|
+
[disabled]="disabled()"
|
|
3646
|
+
[filter]="filter()"
|
|
3647
|
+
[showClear]="showClear()"
|
|
3648
|
+
[emptyMessage]="emptyMessage()"
|
|
3649
|
+
[group]="group()"
|
|
3650
|
+
[ngModel]="value()"
|
|
3651
|
+
(ngModelChange)="value.set($event)"
|
|
3652
|
+
(onChange)="onChange.emit($event)"
|
|
3653
|
+
(onFilter)="onFilter.emit($event)"
|
|
3654
|
+
[styleClass]="resolvedStyleClass()"
|
|
3655
|
+
/>
|
|
3656
|
+
`, isInline: true, styles: [":host :deep .p-select{border-radius:var(--p-content-border-radius, .375rem);font-family:var(--p-font-family, \"Noto Sans\", sans-serif);font-size:var(--font-size-sm, .875rem);transition:border-color .15s ease,box-shadow .15s ease;padding:.5rem 1.5rem}:host :deep .p-select:not(.p-disabled):hover{border-color:var(--p-primary-400)}:host :deep .p-select:not(.p-disabled).p-focus{border-color:var(--p-primary-500);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-500) 20%,transparent)}:host :deep .p-select-label{font-size:var(--font-size-sm, .875rem);color:var(--p-text-color)}:host :deep .p-select-label.p-placeholder{color:var(--p-text-muted-color)}:host :deep .p-select-dropdown{color:var(--p-text-muted-color)}:host-context(:root[class*=\"app-dark\"]) :deep .p-select:not(.p-disabled):hover{border-color:var(--p-primary-300)}:host-context(:root[class*=\"app-dark\"]) :deep .p-select:not(.p-disabled).p-focus{border-color:var(--p-primary-400);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-400) 25%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3657
|
+
}
|
|
3658
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: UxSelectComponent, decorators: [{
|
|
3659
|
+
type: Component,
|
|
3660
|
+
args: [{ selector: 'ux-select', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule, SelectModule], host: { class: 'ux-select' }, template: `
|
|
3661
|
+
<p-select
|
|
3662
|
+
[options]="options()"
|
|
3663
|
+
[optionLabel]="optionLabel()"
|
|
3664
|
+
[optionValue]="optionValue()"
|
|
3665
|
+
[optionGroupLabel]="optionGroupLabel()"
|
|
3666
|
+
[optionGroupChildren]="optionGroupChildren()"
|
|
3667
|
+
[placeholder]="placeholder()"
|
|
3668
|
+
[disabled]="disabled()"
|
|
3669
|
+
[filter]="filter()"
|
|
3670
|
+
[showClear]="showClear()"
|
|
3671
|
+
[emptyMessage]="emptyMessage()"
|
|
3672
|
+
[group]="group()"
|
|
3673
|
+
[ngModel]="value()"
|
|
3674
|
+
(ngModelChange)="value.set($event)"
|
|
3675
|
+
(onChange)="onChange.emit($event)"
|
|
3676
|
+
(onFilter)="onFilter.emit($event)"
|
|
3677
|
+
[styleClass]="resolvedStyleClass()"
|
|
3678
|
+
/>
|
|
3679
|
+
`, styles: [":host :deep .p-select{border-radius:var(--p-content-border-radius, .375rem);font-family:var(--p-font-family, \"Noto Sans\", sans-serif);font-size:var(--font-size-sm, .875rem);transition:border-color .15s ease,box-shadow .15s ease;padding:.5rem 1.5rem}:host :deep .p-select:not(.p-disabled):hover{border-color:var(--p-primary-400)}:host :deep .p-select:not(.p-disabled).p-focus{border-color:var(--p-primary-500);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-500) 20%,transparent)}:host :deep .p-select-label{font-size:var(--font-size-sm, .875rem);color:var(--p-text-color)}:host :deep .p-select-label.p-placeholder{color:var(--p-text-muted-color)}:host :deep .p-select-dropdown{color:var(--p-text-muted-color)}:host-context(:root[class*=\"app-dark\"]) :deep .p-select:not(.p-disabled):hover{border-color:var(--p-primary-300)}:host-context(:root[class*=\"app-dark\"]) :deep .p-select:not(.p-disabled).p-focus{border-color:var(--p-primary-400);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-400) 25%,transparent)}\n"] }]
|
|
3680
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], optionGroupLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionGroupLabel", required: false }] }], optionGroupChildren: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionGroupChildren", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], showClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClear", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], group: [{ type: i0.Input, args: [{ isSignal: true, alias: "group", required: false }] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onChange: [{ type: i0.Output, args: ["onChange"] }], onFilter: [{ type: i0.Output, args: ["onFilter"] }] } });
|
|
3681
|
+
|
|
3682
|
+
class TaskDrawerComponent {
|
|
3683
|
+
visible = model(false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
|
|
3684
|
+
task = input(null, ...(ngDevMode ? [{ debugName: "task" }] : []));
|
|
3685
|
+
mode = input('create', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
3686
|
+
availableMembers = input([
|
|
3687
|
+
{ name: 'Amy Elsner', image: 'amyelsner.png' },
|
|
3688
|
+
{ name: 'Anna Fali', image: 'annafali.png' },
|
|
3689
|
+
{ name: 'Asiya Javayant', image: 'asiyajavayant.png' },
|
|
3690
|
+
{ name: 'Bernardo Dominic', image: 'bernardodominic.png' }
|
|
3691
|
+
], ...(ngDevMode ? [{ debugName: "availableMembers" }] : []));
|
|
3692
|
+
save = output();
|
|
3693
|
+
cancel = output();
|
|
3694
|
+
drawerTitle = computed(() => this.mode() === 'create' ? 'Create New Task' : 'Edit Task', ...(ngDevMode ? [{ debugName: "drawerTitle" }] : []));
|
|
3695
|
+
formData = {
|
|
3696
|
+
id: null,
|
|
3697
|
+
title: '',
|
|
3698
|
+
description: '',
|
|
3699
|
+
status: 'pending',
|
|
3700
|
+
completed: false,
|
|
3701
|
+
startDate: null,
|
|
3702
|
+
endDate: null,
|
|
3703
|
+
members: []
|
|
3704
|
+
};
|
|
3705
|
+
statusOptions = [
|
|
3706
|
+
{ label: 'Pending', value: 'pending' },
|
|
3707
|
+
{ label: 'In Progress', value: 'in-progress' },
|
|
3708
|
+
{ label: 'Completed', value: 'completed' }
|
|
3709
|
+
];
|
|
3710
|
+
filteredMembers = [];
|
|
3711
|
+
ngOnChanges(changes) {
|
|
3712
|
+
if (changes['task']) {
|
|
3713
|
+
const newTask = changes['task'].currentValue;
|
|
3714
|
+
if (newTask) {
|
|
3715
|
+
this.formData = {
|
|
3716
|
+
id: newTask.id,
|
|
3717
|
+
title: newTask.title || '',
|
|
3718
|
+
description: newTask.description || '',
|
|
3719
|
+
status: newTask.status || 'pending',
|
|
3720
|
+
completed: newTask.completed || false,
|
|
3721
|
+
startDate: newTask.startDate ? this.parseDate(newTask.startDate) : null,
|
|
3722
|
+
endDate: newTask.endDate ? this.parseDate(newTask.endDate) : null,
|
|
3723
|
+
members: newTask.members || []
|
|
3724
|
+
};
|
|
3725
|
+
}
|
|
3726
|
+
else {
|
|
3727
|
+
this.resetForm();
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
parseDate(dateStr) {
|
|
3732
|
+
if (!dateStr)
|
|
3733
|
+
return null;
|
|
3734
|
+
const parts = dateStr.split('.');
|
|
3735
|
+
if (parts.length === 3) {
|
|
3736
|
+
return new Date(parseInt(parts[2]), parseInt(parts[1]) - 1, parseInt(parts[0]));
|
|
3737
|
+
}
|
|
3738
|
+
return null;
|
|
3739
|
+
}
|
|
3740
|
+
resetForm() {
|
|
3741
|
+
this.formData = {
|
|
3742
|
+
id: null,
|
|
3743
|
+
title: '',
|
|
3744
|
+
description: '',
|
|
3745
|
+
status: 'pending',
|
|
3746
|
+
completed: false,
|
|
3747
|
+
startDate: null,
|
|
3748
|
+
endDate: null,
|
|
3749
|
+
members: []
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
filterMembers(event) {
|
|
3753
|
+
const members = this.availableMembers();
|
|
3754
|
+
if (!event.query) {
|
|
3755
|
+
this.filteredMembers = members;
|
|
3756
|
+
return;
|
|
3757
|
+
}
|
|
3758
|
+
this.filteredMembers = members.filter(member => member.name?.toLowerCase().includes(event.query.toLowerCase()));
|
|
3759
|
+
}
|
|
3760
|
+
formatDateForSave(date) {
|
|
3761
|
+
if (!date)
|
|
3762
|
+
return null;
|
|
3763
|
+
const d = new Date(date);
|
|
3764
|
+
return `${String(d.getDate()).padStart(2, '0')}.${String(d.getMonth() + 1).padStart(2, '0')}.${d.getFullYear()}`;
|
|
3765
|
+
}
|
|
3766
|
+
handleSave() {
|
|
3767
|
+
const taskData = {
|
|
3768
|
+
id: this.formData.id,
|
|
3769
|
+
title: this.formData.title,
|
|
3770
|
+
description: this.formData.description || null,
|
|
3771
|
+
status: this.formData.status,
|
|
3772
|
+
completed: this.formData.status === 'completed',
|
|
3773
|
+
startDate: this.formatDateForSave(this.formData.startDate),
|
|
3774
|
+
endDate: this.formatDateForSave(this.formData.endDate),
|
|
3775
|
+
members: this.formData.members
|
|
3776
|
+
};
|
|
3777
|
+
this.save.emit(taskData);
|
|
3778
|
+
this.handleCancel();
|
|
3779
|
+
}
|
|
3780
|
+
handleCancel() {
|
|
3781
|
+
this.resetForm();
|
|
3782
|
+
this.cancel.emit();
|
|
3783
|
+
this.visible.set(false);
|
|
3784
|
+
}
|
|
3785
|
+
onHide() {
|
|
3786
|
+
this.handleCancel();
|
|
3787
|
+
}
|
|
3788
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TaskDrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3789
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.8", type: TaskDrawerComponent, isStandalone: true, selector: "ux-task-drawer", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, task: { classPropertyName: "task", publicName: "task", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, availableMembers: { classPropertyName: "availableMembers", publicName: "availableMembers", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange", save: "save", cancel: "cancel" }, host: { classAttribute: "ux-task-drawer" }, usesOnChanges: true, ngImport: i0, template: `
|
|
3790
|
+
<p-drawer [visible]="visible()" position="right" styleClass="w-full! md:w-[420px]!" (onHide)="onHide()" (visibleChange)="visible.set($event)" appendTo="body">
|
|
3791
|
+
<ng-template #header>
|
|
3792
|
+
<div class="flex items-center gap-3">
|
|
3793
|
+
<i class="pi pi-list-check text-xl text-primary-500"></i>
|
|
3794
|
+
<span class="text-surface-900 dark:text-surface-0 font-semibold text-lg">{{ drawerTitle() }}</span>
|
|
3795
|
+
</div>
|
|
3796
|
+
</ng-template>
|
|
3797
|
+
|
|
3798
|
+
<div class="flex flex-col gap-6 p-1">
|
|
3799
|
+
<div class="flex flex-col gap-2">
|
|
3800
|
+
<label for="task-title" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Task Title</label>
|
|
3801
|
+
<input pInputText id="task-title" [(ngModel)]="formData.title" placeholder="Enter task title..." class="w-full" />
|
|
3802
|
+
</div>
|
|
3803
|
+
|
|
3804
|
+
<div class="flex flex-col gap-2">
|
|
3805
|
+
<label for="task-description" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Description</label>
|
|
3806
|
+
<textarea pTextarea id="task-description" [(ngModel)]="formData.description" placeholder="Enter task description..." [rows]="4" class="w-full"></textarea>
|
|
3807
|
+
</div>
|
|
3808
|
+
|
|
3809
|
+
<div class="flex flex-col gap-2">
|
|
3810
|
+
<label for="task-status" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Status</label>
|
|
3811
|
+
<p-select id="task-status" [(ngModel)]="formData.status" [options]="statusOptions" optionLabel="label" optionValue="value" placeholder="Select status" styleClass="w-full" />
|
|
3812
|
+
</div>
|
|
3813
|
+
|
|
3814
|
+
<p-divider styleClass="my-2" />
|
|
3815
|
+
|
|
3816
|
+
<div class="flex flex-col gap-2">
|
|
3817
|
+
<label for="start-date" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Start Date</label>
|
|
3818
|
+
<p-datepicker id="start-date" [(ngModel)]="formData.startDate" dateFormat="dd.mm.yy" placeholder="Select start date" inputStyleClass="w-full" />
|
|
3819
|
+
</div>
|
|
3820
|
+
|
|
3821
|
+
<div class="flex flex-col gap-2">
|
|
3822
|
+
<label for="end-date" class="text-surface-900 dark:text-surface-0 font-medium text-sm">End Date</label>
|
|
3823
|
+
<p-datepicker id="end-date" [(ngModel)]="formData.endDate" dateFormat="dd.mm.yy" placeholder="Select end date" inputStyleClass="w-full" />
|
|
3824
|
+
</div>
|
|
3825
|
+
|
|
3826
|
+
<p-divider styleClass="my-2" />
|
|
3827
|
+
|
|
3828
|
+
<div class="flex flex-col gap-2">
|
|
3829
|
+
<label for="team-members" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Team Members</label>
|
|
3830
|
+
<p-autocomplete
|
|
3831
|
+
id="team-members"
|
|
3832
|
+
[(ngModel)]="formData.members"
|
|
3833
|
+
[suggestions]="filteredMembers"
|
|
3834
|
+
optionLabel="name"
|
|
3835
|
+
[multiple]="true"
|
|
3836
|
+
placeholder="Search team members..."
|
|
3837
|
+
(completeMethod)="filterMembers($event)"
|
|
3838
|
+
styleClass="w-full"
|
|
3839
|
+
>
|
|
3840
|
+
<ng-template #selecteditem let-value>
|
|
3841
|
+
<div class="flex items-center gap-2 bg-surface-50 dark:bg-surface-900 px-2 py-1 rounded">
|
|
3842
|
+
<p-avatar [image]="'demo/images/avatar/' + value.image" shape="circle" styleClass="w-5 h-5 border border-surface-200 dark:border-surface-700" />
|
|
3843
|
+
</div>
|
|
3844
|
+
</ng-template>
|
|
3845
|
+
<ng-template #item let-option>
|
|
3846
|
+
<div class="flex items-center gap-3">
|
|
3847
|
+
<p-avatar [image]="'demo/images/avatar/' + option.image" shape="circle" styleClass="w-8 h-8 border border-surface-200 dark:border-surface-700" />
|
|
3848
|
+
<span class="text-surface-900 dark:text-surface-0 font-medium">{{ option.name }}</span>
|
|
3849
|
+
</div>
|
|
3850
|
+
</ng-template>
|
|
3851
|
+
</p-autocomplete>
|
|
3852
|
+
</div>
|
|
3853
|
+
</div>
|
|
3854
|
+
|
|
3855
|
+
<ng-template #footer>
|
|
3856
|
+
<div class="flex justify-end gap-3 pt-4 border-t border-surface-200 dark:border-surface-700">
|
|
3857
|
+
<p-button label="Cancel" icon="pi pi-times" [outlined]="true" severity="secondary" (onClick)="handleCancel()" styleClass="flex-1" />
|
|
3858
|
+
<p-button [label]="mode() === 'create' ? 'Create Task' : 'Update Task'" [icon]="mode() === 'create' ? 'pi pi-plus' : 'pi pi-check'" (onClick)="handleSave()" styleClass="flex-1" />
|
|
3859
|
+
</div>
|
|
3860
|
+
</ng-template>
|
|
3861
|
+
</p-drawer>
|
|
3862
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2$1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i4.Drawer, selector: "p-drawer", inputs: ["appendTo", "motionOptions", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i5$2.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["pTextareaPT", "pTextareaUnstyled", "autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i7$1.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i8$2.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i2.Divider, selector: "p-divider", inputs: ["styleClass", "layout", "type", "align"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i10.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3863
|
+
}
|
|
3864
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TaskDrawerComponent, decorators: [{
|
|
3865
|
+
type: Component,
|
|
3866
|
+
args: [{
|
|
3867
|
+
selector: 'ux-task-drawer',
|
|
3868
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3869
|
+
imports: [FormsModule, ButtonModule, DrawerModule, InputTextModule, TextareaModule, SelectModule, DatePickerModule, AutoCompleteModule, DividerModule, AvatarModule],
|
|
3870
|
+
host: { class: 'ux-task-drawer' },
|
|
3871
|
+
template: `
|
|
3872
|
+
<p-drawer [visible]="visible()" position="right" styleClass="w-full! md:w-[420px]!" (onHide)="onHide()" (visibleChange)="visible.set($event)" appendTo="body">
|
|
3873
|
+
<ng-template #header>
|
|
3874
|
+
<div class="flex items-center gap-3">
|
|
3875
|
+
<i class="pi pi-list-check text-xl text-primary-500"></i>
|
|
3876
|
+
<span class="text-surface-900 dark:text-surface-0 font-semibold text-lg">{{ drawerTitle() }}</span>
|
|
3877
|
+
</div>
|
|
3878
|
+
</ng-template>
|
|
3879
|
+
|
|
3880
|
+
<div class="flex flex-col gap-6 p-1">
|
|
3881
|
+
<div class="flex flex-col gap-2">
|
|
3882
|
+
<label for="task-title" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Task Title</label>
|
|
3883
|
+
<input pInputText id="task-title" [(ngModel)]="formData.title" placeholder="Enter task title..." class="w-full" />
|
|
3884
|
+
</div>
|
|
3885
|
+
|
|
3886
|
+
<div class="flex flex-col gap-2">
|
|
3887
|
+
<label for="task-description" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Description</label>
|
|
3888
|
+
<textarea pTextarea id="task-description" [(ngModel)]="formData.description" placeholder="Enter task description..." [rows]="4" class="w-full"></textarea>
|
|
3889
|
+
</div>
|
|
3890
|
+
|
|
3891
|
+
<div class="flex flex-col gap-2">
|
|
3892
|
+
<label for="task-status" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Status</label>
|
|
3893
|
+
<p-select id="task-status" [(ngModel)]="formData.status" [options]="statusOptions" optionLabel="label" optionValue="value" placeholder="Select status" styleClass="w-full" />
|
|
3894
|
+
</div>
|
|
3895
|
+
|
|
3896
|
+
<p-divider styleClass="my-2" />
|
|
3897
|
+
|
|
3898
|
+
<div class="flex flex-col gap-2">
|
|
3899
|
+
<label for="start-date" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Start Date</label>
|
|
3900
|
+
<p-datepicker id="start-date" [(ngModel)]="formData.startDate" dateFormat="dd.mm.yy" placeholder="Select start date" inputStyleClass="w-full" />
|
|
3901
|
+
</div>
|
|
3902
|
+
|
|
3903
|
+
<div class="flex flex-col gap-2">
|
|
3904
|
+
<label for="end-date" class="text-surface-900 dark:text-surface-0 font-medium text-sm">End Date</label>
|
|
3905
|
+
<p-datepicker id="end-date" [(ngModel)]="formData.endDate" dateFormat="dd.mm.yy" placeholder="Select end date" inputStyleClass="w-full" />
|
|
3906
|
+
</div>
|
|
3907
|
+
|
|
3908
|
+
<p-divider styleClass="my-2" />
|
|
3909
|
+
|
|
3910
|
+
<div class="flex flex-col gap-2">
|
|
3911
|
+
<label for="team-members" class="text-surface-900 dark:text-surface-0 font-medium text-sm">Team Members</label>
|
|
3912
|
+
<p-autocomplete
|
|
3913
|
+
id="team-members"
|
|
3914
|
+
[(ngModel)]="formData.members"
|
|
3915
|
+
[suggestions]="filteredMembers"
|
|
3916
|
+
optionLabel="name"
|
|
3917
|
+
[multiple]="true"
|
|
3918
|
+
placeholder="Search team members..."
|
|
3919
|
+
(completeMethod)="filterMembers($event)"
|
|
3920
|
+
styleClass="w-full"
|
|
3921
|
+
>
|
|
3922
|
+
<ng-template #selecteditem let-value>
|
|
3923
|
+
<div class="flex items-center gap-2 bg-surface-50 dark:bg-surface-900 px-2 py-1 rounded">
|
|
3924
|
+
<p-avatar [image]="'demo/images/avatar/' + value.image" shape="circle" styleClass="w-5 h-5 border border-surface-200 dark:border-surface-700" />
|
|
3925
|
+
</div>
|
|
3926
|
+
</ng-template>
|
|
3927
|
+
<ng-template #item let-option>
|
|
3928
|
+
<div class="flex items-center gap-3">
|
|
3929
|
+
<p-avatar [image]="'demo/images/avatar/' + option.image" shape="circle" styleClass="w-8 h-8 border border-surface-200 dark:border-surface-700" />
|
|
3930
|
+
<span class="text-surface-900 dark:text-surface-0 font-medium">{{ option.name }}</span>
|
|
3931
|
+
</div>
|
|
3932
|
+
</ng-template>
|
|
3933
|
+
</p-autocomplete>
|
|
3934
|
+
</div>
|
|
3935
|
+
</div>
|
|
3936
|
+
|
|
3937
|
+
<ng-template #footer>
|
|
3938
|
+
<div class="flex justify-end gap-3 pt-4 border-t border-surface-200 dark:border-surface-700">
|
|
3939
|
+
<p-button label="Cancel" icon="pi pi-times" [outlined]="true" severity="secondary" (onClick)="handleCancel()" styleClass="flex-1" />
|
|
3940
|
+
<p-button [label]="mode() === 'create' ? 'Create Task' : 'Update Task'" [icon]="mode() === 'create' ? 'pi pi-plus' : 'pi pi-check'" (onClick)="handleSave()" styleClass="flex-1" />
|
|
3941
|
+
</div>
|
|
3942
|
+
</ng-template>
|
|
3943
|
+
</p-drawer>
|
|
3944
|
+
`
|
|
3945
|
+
}]
|
|
3946
|
+
}], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], task: [{ type: i0.Input, args: [{ isSignal: true, alias: "task", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], availableMembers: [{ type: i0.Input, args: [{ isSignal: true, alias: "availableMembers", required: false }] }], save: [{ type: i0.Output, args: ["save"] }], cancel: [{ type: i0.Output, args: ["cancel"] }] } });
|
|
3947
|
+
|
|
2587
3948
|
/*
|
|
2588
3949
|
* Public API Surface of @unopsitg/ux
|
|
2589
3950
|
*/
|
|
@@ -2592,5 +3953,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
2592
3953
|
* Generated bundle index. Do not edit.
|
|
2593
3954
|
*/
|
|
2594
3955
|
|
|
2595
|
-
export { AiCardBgComponent, AppBreadcrumb, AppConfigurator, AppFooter, AppLayout, AppMenu, AppMenuitem, AppRightMenu, AppSearch, AppSidebar, AppTopbar, AuthLayout, BrandContrast, BrandCrisp, BrandSoft, LayoutService, MENU_MODEL, SIDEBAR_LOGO, TOPBAR_MOBILE_LOGO, brandPresets, brandPrimitives };
|
|
3956
|
+
export { AiCardBgComponent, AiInsightsCardComponent, AppBreadcrumb, AppConfigurator, AppFooter, AppLayout, AppMenu, AppMenuitem, AppRightMenu, AppSearch, AppSidebar, AppTopbar, AuthLayout, BrandContrast, BrandCrisp, BrandSoft, CompletionStepsComponent, DetailLayoutComponent, DetailTabDirective, DocumentsCardComponent, FooterMainComponent, FooterService, LayoutService, MENU_MODEL, PillTabsComponent, SIDEBAR_LOGO, TOPBAR_MOBILE_LOGO, TaskDrawerComponent, UxSelectComponent, brandPresets, brandPrimitives };
|
|
2596
3957
|
//# sourceMappingURL=unopsitg-ux.mjs.map
|