@foxeltech/angular-ui 0.3.0 → 0.4.0

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.
Files changed (54) hide show
  1. package/fesm2022/foxeltech-angular-ui-chart.mjs +392 -0
  2. package/fesm2022/foxeltech-angular-ui-chart.mjs.map +1 -0
  3. package/fesm2022/foxeltech-angular-ui-flow.mjs +38 -0
  4. package/fesm2022/foxeltech-angular-ui-flow.mjs.map +1 -0
  5. package/fesm2022/foxeltech-angular-ui-rich-text.mjs +156 -0
  6. package/fesm2022/foxeltech-angular-ui-rich-text.mjs.map +1 -0
  7. package/fesm2022/foxeltech-angular-ui.mjs +890 -1499
  8. package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
  9. package/fx-icons.svg +97 -0
  10. package/package.json +23 -16
  11. package/src/lib/styles/tailwind.css +0 -1
  12. package/src/lib/ui/components/button/button.component.html +14 -14
  13. package/src/lib/ui/components/checkbox/checkbox.component.html +2 -2
  14. package/src/lib/ui/components/circle-progress-bar/circle-progress-bar.component.html +2 -2
  15. package/src/lib/ui/components/datetime-picker/datetime-picker.component.html +54 -28
  16. package/src/lib/ui/components/datetime-picker/datetime-picker.component.scss +25 -137
  17. package/src/lib/ui/components/dnd-upload/dnd-upload.component.html +3 -3
  18. package/src/lib/ui/components/drawer/drawer.component.html +75 -61
  19. package/src/lib/ui/components/empty-state/empty-state.component.html +2 -2
  20. package/src/lib/ui/components/hero-icon/hero-icon.component.html +10 -9
  21. package/src/lib/ui/components/info-field/info-field.component.html +1 -1
  22. package/src/lib/ui/components/input/input.component.html +6 -6
  23. package/src/lib/ui/components/kanban-board/kanban-board.component.html +1 -1
  24. package/src/lib/ui/components/loading-panel/loading-panel.component.html +53 -53
  25. package/src/lib/ui/components/master-detail/master-detail.component.html +9 -9
  26. package/src/lib/ui/components/menu/menu.component.html +27 -0
  27. package/src/lib/ui/components/radio-button/radio-button.component.html +26 -26
  28. package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.html +3 -3
  29. package/src/lib/ui/components/search-bar/search-bar.component.html +12 -11
  30. package/src/lib/ui/components/section-card/section-card.component.html +1 -1
  31. package/src/lib/ui/components/select/select.component.html +14 -12
  32. package/src/lib/ui/components/skeleton-detail/skeleton-detail.component.html +2 -2
  33. package/src/lib/ui/components/skeleton-list/skeleton-list.component.html +1 -1
  34. package/src/lib/ui/components/skeleton-table-loading/skeleton-table-loading.component.html +5 -5
  35. package/src/lib/ui/components/slider/slider.component.html +22 -20
  36. package/src/lib/ui/components/stat-cards/stat-cards.component.html +1 -1
  37. package/src/lib/ui/components/switch/switch.component.html +1 -1
  38. package/src/lib/ui/components/tab-group/tab-group.component.html +35 -32
  39. package/src/lib/ui/components/table-cell/table-cell.component.html +2 -2
  40. package/src/lib/ui/components/tag/tag.component.html +4 -4
  41. package/src/lib/ui/components/toast/toast.component.html +42 -40
  42. package/src/lib/ui/components/toast-container/toast-container.component.html +1 -0
  43. package/src/lib/ui/components/tree-diagram/tree-diagram.component.html +22 -20
  44. package/tailwind.css +0 -1
  45. package/types/foxeltech-angular-ui-chart.d.ts +53 -0
  46. package/types/foxeltech-angular-ui-flow.d.ts +14 -0
  47. package/types/foxeltech-angular-ui-rich-text.d.ts +35 -0
  48. package/{index.d.ts → types/foxeltech-angular-ui.d.ts} +394 -387
  49. package/src/lib/ui/components/chart/chart.component.html +0 -20
  50. package/src/lib/ui/components/chart/chart.component.scss +0 -49
  51. package/src/lib/ui/components/flow-connection/flow-connection.component.html +0 -10
  52. package/src/lib/ui/components/flow-connection/flow-connection.component.scss +0 -0
  53. package/src/lib/ui/components/rich-text-area/rich-text-area.component.html +0 -3
  54. package/src/lib/ui/components/rich-text-area/rich-text-area.component.scss +0 -18
package/package.json CHANGED
@@ -1,31 +1,25 @@
1
1
  {
2
2
  "name": "@foxeltech/angular-ui",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "peerDependencies": {
9
9
  "tailwindcss": "^4.0.0",
10
- "@angular/common": "^20.3.0",
11
- "@angular/animations": "^20.3.0",
12
- "@angular/core": "^20.3.0",
13
- "@angular/forms": "^20.3.0",
14
- "@angular/material": "^20.2.7",
15
- "@angular/cdk": "^20.2.7",
16
- "lodash": "^4.17.21",
10
+ "@angular/common": "^20.3.0 || ^21.0.0",
11
+ "@angular/animations": "^20.3.0 || ^21.0.0",
12
+ "@angular/core": "^20.3.0 || ^21.0.0",
13
+ "@angular/forms": "^20.3.0 || ^21.0.0",
14
+ "@angular/material": "^20.2.7 || ^21.0.0",
15
+ "@angular/cdk": "^20.2.7 || ^21.0.0",
17
16
  "@ngx-translate/core": "^14.0.0",
18
- "@ngx-translate/http-loader": "^7.0.0",
19
- "moment": "^2.30.1"
17
+ "@ngx-translate/http-loader": "^7.0.0"
20
18
  },
21
19
  "dependencies": {
22
20
  "tslib": "^2.3.0",
23
- "@danielmoncada/angular-datetime-picker": "^20.0.0",
24
- "@danielmoncada/angular-datetime-picker-moment-adapter": "^7.0.1",
25
21
  "echarts": "^6.0.0",
26
22
  "ngx-echarts": "^20.0.2",
27
- "d3": "^7.9.0",
28
- "@dimaslz/ng-heroicons": "^1.19.1",
29
23
  "quill": "^2.0.3",
30
24
  "ngx-vflow": "^1.16.2",
31
25
  "@microsoft/signalr": "^10.0.0"
@@ -43,13 +37,26 @@
43
37
  "default": "./package.json"
44
38
  },
45
39
  ".": {
46
- "types": "./index.d.ts",
40
+ "types": "./types/foxeltech-angular-ui.d.ts",
47
41
  "default": "./fesm2022/foxeltech-angular-ui.mjs"
42
+ },
43
+ "./chart": {
44
+ "types": "./types/foxeltech-angular-ui-chart.d.ts",
45
+ "default": "./fesm2022/foxeltech-angular-ui-chart.mjs"
46
+ },
47
+ "./flow": {
48
+ "types": "./types/foxeltech-angular-ui-flow.d.ts",
49
+ "default": "./fesm2022/foxeltech-angular-ui-flow.mjs"
50
+ },
51
+ "./rich-text": {
52
+ "types": "./types/foxeltech-angular-ui-rich-text.d.ts",
53
+ "default": "./fesm2022/foxeltech-angular-ui-rich-text.mjs"
48
54
  }
49
55
  },
50
56
  "sideEffects": [
51
57
  "*.css"
52
58
  ],
53
59
  "module": "fesm2022/foxeltech-angular-ui.mjs",
54
- "typings": "index.d.ts"
60
+ "typings": "types/foxeltech-angular-ui.d.ts",
61
+ "type": "module"
55
62
  }
@@ -8,7 +8,6 @@
8
8
  @import './components.css' layer(components);
9
9
  @import './dialogs.css' layer(components);
10
10
  @import './animations.css';
11
- @import '@danielmoncada/angular-datetime-picker/assets/style/picker.min.css';
12
11
 
13
12
  html,
14
13
  body {
@@ -1,22 +1,22 @@
1
1
  <button
2
- [attr.type]="type"
3
- [attr.aria-label]="ariaLabel || null"
4
- [attr.aria-busy]="loading || null"
5
- [class]="class"
2
+ [attr.type]="type()"
3
+ [attr.aria-label]="ariaLabel() || null"
4
+ [attr.aria-busy]="loading() || null"
5
+ [class]="class()"
6
6
  [ngClass]="{
7
- 'btn-default': buttonVariant === 'default',
8
- 'btn-primary': buttonVariant === 'primary',
9
- 'btn-success': buttonVariant === 'success',
10
- 'btn-alternative': buttonVariant === 'alternative',
7
+ 'btn-default': buttonVariant() === 'default',
8
+ 'btn-primary': buttonVariant() === 'primary',
9
+ 'btn-success': buttonVariant() === 'success',
10
+ 'btn-alternative': buttonVariant() === 'alternative',
11
11
  }"
12
- [disabled]="disabled || loading"
12
+ [disabled]="disabled() || loading()"
13
13
  (click)="onClick()"
14
14
  >
15
- @if (loading) {
15
+ @if (loading()) {
16
16
  <div class="flex w-full items-center justify-center" aria-hidden="true">
17
17
  <svg
18
18
  [attr.fill]="
19
- buttonVariant !== 'alternative' ? 'rgb(var(--text-primary))' : 'rgb(var(--primary))'
19
+ buttonVariant() !== 'alternative' ? 'rgb(var(--text-primary))' : 'rgb(var(--primary))'
20
20
  "
21
21
  width="20"
22
22
  height="20"
@@ -222,9 +222,9 @@
222
222
  [size]="20"
223
223
  class="flex"
224
224
  [ngClass]="{
225
- 'text-text-inverse': buttonVariant === 'default',
226
- 'text-text-primary': buttonVariant === 'alternative',
227
- 'text-white': buttonVariant === 'primary' || buttonVariant === 'success',
225
+ 'text-text-inverse': buttonVariant() === 'default',
226
+ 'text-text-primary': buttonVariant() === 'alternative',
227
+ 'text-white': buttonVariant() === 'primary' || buttonVariant() === 'success',
228
228
  }"
229
229
  ></fx-ui-hero-icon>
230
230
  }
@@ -15,8 +15,8 @@
15
15
  <span
16
16
  class="relative w-4 h-4 border rounded-full transition-colors duration-150 shrink-0 peer-focus-visible:ring-2 peer-focus-visible:ring-primary/50"
17
17
  [ngClass]="{
18
- 'rounded-full': rounded,
19
- 'rounded-sm': !rounded,
18
+ 'rounded-full': rounded(),
19
+ 'rounded-sm': !rounded(),
20
20
  'border-border-strong bg-transparent': !value,
21
21
  'border-transparent bg-gradient-primary': value,
22
22
  }"
@@ -28,7 +28,7 @@
28
28
  style="transition: stroke-dashoffset 300ms linear"
29
29
  ></circle>
30
30
 
31
- @if(showPercent){
31
+ @if(showPercent()){
32
32
  <text
33
33
  [attr.x]="radius"
34
34
  [attr.y]="radius"
@@ -37,7 +37,7 @@
37
37
  class="text-xs font-medium"
38
38
  fill="currentColor"
39
39
  >
40
- {{ percent }}%
40
+ {{ percent() }}%
41
41
  </text>
42
42
  }
43
43
  </svg>
@@ -2,36 +2,62 @@
2
2
  @if (label) {
3
3
  <label class="txt-field-label" [attr.for]="fieldId">
4
4
  {{ label }}
5
- <span *ngIf="required" class="txt-required" aria-hidden="true">*</span>
5
+ @if (required()) {
6
+ <span class="txt-required" aria-hidden="true">*</span>
7
+ }
6
8
  </label>
7
9
  }
8
10
 
9
- <div class="relative">
10
- <input
11
- [id]="fieldId"
12
- [owlDateTimeTrigger]="picker"
13
- [owlDateTime]="picker"
14
- [placeholder]="placeholder"
15
- [disabled]="disabled"
16
- [min]="minDate"
17
- [max]="maxDate"
18
- (blur)="onBlur()"
19
- [value]="value"
20
- readonly
21
- class="input-default pr-9"
22
- />
23
- <span
24
- [owlDateTimeTrigger]="picker"
25
- class="absolute inset-y-0 right-0 flex items-center pr-2.5 cursor-pointer text-text-placeholder hover:text-text-primary transition-colors"
26
- >
27
- <fx-ui-hero-icon icon="calendar" [size]="20" class="text-text-primary"></fx-ui-hero-icon>
28
- </span>
11
+ <div class="flex gap-normal">
12
+ @if (showDate) {
13
+ <div class="relative flex-1">
14
+ <input
15
+ [id]="fieldId"
16
+ [matDatepicker]="datePicker"
17
+ [placeholder]="placeholder()"
18
+ [disabled]="disabled"
19
+ [min]="min"
20
+ [max]="max"
21
+ [value]="dateValue"
22
+ (dateChange)="onDateChange($event.value)"
23
+ (click)="!disabled && datePicker.open()"
24
+ (blur)="onBlur()"
25
+ readonly
26
+ class="input-default pr-9"
27
+ />
28
+ <span
29
+ (click)="!disabled && datePicker.open()"
30
+ class="absolute inset-y-0 right-0 flex items-center pr-2.5 cursor-pointer text-text-placeholder hover:text-text-primary transition-colors"
31
+ >
32
+ <fx-ui-hero-icon icon="calendar" [size]="20" class="text-text-primary"></fx-ui-hero-icon>
33
+ </span>
34
+ <mat-datepicker #datePicker></mat-datepicker>
35
+ </div>
36
+ }
37
+ @if (showTime) {
38
+ <div class="relative" [class.flex-1]="!showDate" [class.w-32]="showDate">
39
+ <input
40
+ [matTimepicker]="timePicker"
41
+ placeholder="HH:mm"
42
+ [disabled]="disabled"
43
+ [value]="dateValue"
44
+ (valueChange)="onTimeChange($event)"
45
+ (click)="!disabled && timePicker.open()"
46
+ (blur)="onBlur()"
47
+ readonly
48
+ class="input-default pr-9"
49
+ />
50
+ <span
51
+ (click)="!disabled && timePicker.open()"
52
+ class="absolute inset-y-0 right-0 flex items-center pr-2.5 cursor-pointer text-text-placeholder hover:text-text-primary transition-colors"
53
+ >
54
+ <fx-ui-hero-icon icon="clock" [size]="20" class="text-text-primary"></fx-ui-hero-icon>
55
+ </span>
56
+ <mat-timepicker #timePicker></mat-timepicker>
57
+ </div>
58
+ }
29
59
  </div>
30
- <owl-date-time
31
- #picker
32
- [startAt]="startAt"
33
- [pickerType]="type"
34
- (afterPickerClosed)="onValueChange($event)"
35
- ></owl-date-time>
36
- <div *ngIf="invalid" class="txt-invalid">{{ getErrorMessage(label) }}</div>
60
+ @if (invalid) {
61
+ <div class="txt-invalid">{{ getErrorMessage(label) }}</div>
62
+ }
37
63
  </div>
@@ -1,147 +1,35 @@
1
1
  /* Tailwind v4: component styles compile in isolation — @reference pulls in the theme for @apply without re-emitting it. */
2
2
  @reference '../../../styles/tailwind.css';
3
3
 
4
- // ─── Owl DateTime Picker Custom Styles ───────────────────────────────────────
4
+ /* ─── Material date/time picker popups, themed with the fx tokens ──────────
5
+ (Replaces the old Owl picker skin — the popups render in an overlay, so
6
+ everything below is ::ng-deep on the panel classes.) */
5
7
 
6
- // Container
7
- ::ng-deep .owl-dt-container {
8
+ ::ng-deep .mat-datepicker-content,
9
+ ::ng-deep mat-timepicker .mat-timepicker-panel,
10
+ ::ng-deep .mat-timepicker-panel {
8
11
  @apply bg-bg-primary rounded-xl shadow-xl border border-border-default;
9
- width: 320px !important;
10
- }
11
-
12
- // Calendar table base
13
- ::ng-deep .owl-dt-calendar-table {
14
- @apply w-full border-collapse;
15
- }
16
-
17
- // Default cell hover — override red debug color
18
- ::ng-deep .owl-dt-calendar-table :not(.owl-dt-calendar-cell-disabled):hover > .owl-dt-calendar-cell-content:not(.owl-dt-calendar-cell-selected) {
19
- @apply bg-bg-hover;
20
- }
21
-
22
- // ── Current-month cell text color ─────────────────────────────────────────────
23
- // No !important here — lets out-month and disabled !important overrides win.
24
- // A direct declaration still beats the library's inherited rgba(0,0,0,.85).
25
- ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-content {
26
12
  color: rgb(var(--text-primary));
27
- }
28
-
29
- // Selected cell
30
- ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-selected {
31
- background-color: rgb(var(--primary)) !important;
32
- color: #fff !important;
33
- }
34
-
35
- // Today highlight (not selected)
36
- ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-today:not(.owl-dt-calendar-cell-selected) {
37
- border-color: rgb(var(--primary)) !important;
38
- }
39
-
40
- // ── Disabled dates: text-text-placeholder ────────────────────────────────────
41
- // owl-dt-calendar-cell-disabled is on the <td>, content span is a direct child
42
- ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-disabled > .owl-dt-calendar-cell-content {
43
- color: rgb(var(--text-placeholder)) !important;
44
- opacity: 0.6 !important;
45
- cursor: not-allowed;
46
- pointer-events: none;
47
- }
48
-
49
- // ── Other-month dates: text-text-secondary ────────────────────────────────────
50
- // In v20, owl-dt-calendar-cell-out is applied ON the <span.owl-dt-calendar-cell-content>
51
- // itself (via [ngClass]), NOT on the parent <td>. So target it directly.
52
- ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-content.owl-dt-calendar-cell-out {
53
- color: rgb(var(--text-secondary)) !important;
54
- opacity: 0.6 !important;
55
- }
56
-
57
- // ── Timer input ───────────────────────────────────────────────────────────────
58
- ::ng-deep .owl-dt-timer-content .owl-dt-timer-input {
59
- @apply bg-bg-primary border border-border-strong text-text-primary rounded-lg;
60
- }
61
-
62
- // ── Period button (hide arrow) ────────────────────────────────────────────────
63
- ::ng-deep .owl-dt-control-period-button .owl-dt-control-button-arrow {
64
- display: none;
65
- }
66
13
 
67
- // ── Set / Cancel footer buttons ───────────────────────────────────────────────
68
- // Library sets .owl-dt-container-buttons { height: 2em; color: #3f51b5 } — override both
69
- ::ng-deep .owl-dt-container-buttons {
70
- height: auto !important;
71
- color: rgb(var(--text-primary)) !important; // reset inherited primary color on text
72
- display: flex !important;
73
- align-items: center !important;
74
- justify-content: flex-end !important;
75
- gap: 8px;
76
- padding: 8px 12px;
77
- border-top: 1px solid rgb(var(--border-default));
78
- }
79
-
80
- // Both buttons — explicit 32px height so inner height:100% resolves correctly
81
- ::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button {
82
- width: auto !important;
83
- height: 32px !important;
84
- border-radius: 6px !important;
85
- width: 60px !important;
86
- padding-top: 4px !important;
87
- padding-bottom: 4px !important;
88
- font-size: 13px !important;
89
- font-weight: 600 !important;
90
- border: 1px solid rgb(var(--border-default)) !important;
91
- background-color: rgb(var(--bg-primary)) !important;
92
- color: rgb(var(--text-primary)) !important;
93
- cursor: pointer;
94
- transition: opacity 150ms ease;
95
-
96
- &:hover {
97
- background-color: rgb(var(--bg-hover)) !important;
98
- }
99
- }
100
-
101
- // "Set" = last button — primary fill
102
- ::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button:last-child {
103
- background-color: rgb(var(--primary)) !important;
104
- border-color: rgb(var(--primary)) !important;
105
- color: #fff !important;
106
-
14
+ /* Material M3 token overrides so calendar internals follow the theme */
15
+ --mat-datepicker-calendar-container-background-color: rgb(var(--bg-primary));
16
+ --mat-datepicker-calendar-container-text-color: rgb(var(--text-primary));
17
+ --mat-datepicker-calendar-date-text-color: rgb(var(--text-primary));
18
+ --mat-datepicker-calendar-date-selected-state-background-color: rgb(var(--primary));
19
+ --mat-datepicker-calendar-date-selected-state-text-color: #fff;
20
+ --mat-datepicker-calendar-date-today-outline-color: rgb(var(--primary));
21
+ --mat-datepicker-calendar-date-hover-state-background-color: rgb(var(--bg-primary-hover));
22
+ --mat-datepicker-calendar-header-text-color: rgb(var(--text-secondary));
23
+ --mat-datepicker-calendar-period-button-text-color: rgb(var(--text-primary));
24
+ --mat-datepicker-calendar-navigation-button-icon-color: rgb(var(--text-primary));
25
+ --mat-datepicker-calendar-date-disabled-state-text-color: rgb(var(--text-placeholder));
26
+ --mat-timepicker-container-background-color: rgb(var(--bg-primary));
27
+ }
28
+
29
+ ::ng-deep .mat-timepicker-panel .mat-mdc-option {
30
+ color: rgb(var(--text-primary));
107
31
 
108
- &:hover {
109
- opacity: 0.85;
32
+ &:hover:not(.mdc-list-item--disabled) {
33
+ background-color: rgb(var(--bg-primary-hover));
110
34
  }
111
35
  }
112
-
113
- // Inner content: height:100% now resolves against fixed 32px button, and
114
- // background must be transparent so the button's own bg shows through
115
- ::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button .owl-dt-control-button-content {
116
- height: 100% !important;
117
- width: 100% !important;
118
- padding: 0 !important;
119
- background-color: transparent !important;
120
- color: inherit !important;
121
- display: flex !important;
122
- align-items: center !important;
123
- justify-content: center !important;
124
- }
125
-
126
- // ── Header / navigation ───────────────────────────────────────────────────────
127
- ::ng-deep .owl-dt-calendar-control-content .owl-dt-control-button-content {
128
- @apply text-text-primary font-medium;
129
- }
130
-
131
- ::ng-deep .owl-dt-control-arrow-button .owl-dt-control-button-content {
132
- @apply text-text-primary;
133
- }
134
-
135
- ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header {
136
- @apply text-text-secondary;
137
- }
138
-
139
- ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header .owl-dt-weekdays th {
140
- @apply text-text-secondary font-medium;
141
- }
142
-
143
- // ── Popup container border ────────────────────────────────────────────────────
144
- ::ng-deep .owl-dt-inline-container,
145
- ::ng-deep .owl-dt-popup-container {
146
- @apply rounded-xl shadow-lg border border-border-strong;
147
- }
@@ -14,7 +14,7 @@
14
14
  (keydown.enter)="onAreaClick(fileInput, $event)"
15
15
  >
16
16
  <fx-ui-hero-icon
17
- [icon]="icon"
17
+ [icon]="icon()"
18
18
  [size]="40"
19
19
  class="flex dnd-icon"
20
20
  ></fx-ui-hero-icon>
@@ -28,14 +28,14 @@
28
28
  } @else {
29
29
  Any file type
30
30
  }
31
- — Max {{ maxSizeMB }} MB
31
+ — Max {{ maxSizeMB() }} MB
32
32
  </div>
33
33
 
34
34
  <input
35
35
  #fileInput
36
36
  type="file"
37
37
  class="dnd-input"
38
- [attr.multiple]="multiple ? '' : null"
38
+ [attr.multiple]="multiple() ? '' : null"
39
39
  [attr.accept]="accept"
40
40
  (change)="onFileSelected($event)"
41
41
  />
@@ -3,14 +3,14 @@
3
3
  href="/"
4
4
  class="h-[60px]"
5
5
  [ngClass]="{ 'flex items-center justify-center': !isExpanded, 'p-4': isExpanded }"
6
- >
6
+ >
7
7
  @if (logo) {
8
8
  <img
9
9
  [src]="logo"
10
10
  alt="Home"
11
11
  class="h-[20px] w-auto transition-all duration-300 ease-in-out"
12
12
  [ngClass]="{ 'scale-90': !isExpanded, 'ml-5': isExpanded }"
13
- />
13
+ />
14
14
  } @else {
15
15
  <div class="h-[30px] w-auto transition-all duration-300 ease-in-out"></div>
16
16
  }
@@ -18,18 +18,24 @@
18
18
  <div class="drawer-container" [@drawerExpand]="getDrawerState()">
19
19
  <!-- Navigation Items -->
20
20
  <nav class="drawer-nav">
21
- <ng-container *ngFor="let item of items">
21
+ @for (item of items(); track item) {
22
22
  <ng-container
23
23
  *ngTemplateOutlet="drawerItem; context: { $implicit: item, level: 0 }"
24
24
  ></ng-container>
25
- </ng-container>
25
+ }
26
26
  </nav>
27
27
 
28
28
  <!-- Version -->
29
- <div *ngIf="version" class="drawer-version" [matTooltip]="!isExpanded ? version : ''" matTooltipPosition="right">
30
- <span *ngIf="isExpanded">{{ version }}</span>
31
- <span *ngIf="!isExpanded" class="drawer-version-dot"></span>
32
- </div>
29
+ @if (version) {
30
+ <div class="drawer-version" [matTooltip]="!isExpanded ? version : ''" matTooltipPosition="right">
31
+ @if (isExpanded) {
32
+ <span>{{ version }}</span>
33
+ }
34
+ @if (!isExpanded) {
35
+ <span class="drawer-version-dot"></span>
36
+ }
37
+ </div>
38
+ }
33
39
  </div>
34
40
 
35
41
  <!-- Floating Toggle Button on right border -->
@@ -42,7 +48,7 @@
42
48
  [matTooltip]="isExpanded ? 'Collapse' : 'Expand'"
43
49
  matTooltipClass="text-text-primary text-xs font-semibold"
44
50
  matTooltipPosition="right"
45
- >
51
+ >
46
52
  <fx-ui-hero-icon
47
53
  [icon]="isExpanded ? 'chevron-left' : 'chevron-right'"
48
54
  [size]="16"
@@ -55,60 +61,68 @@
55
61
  <ng-template #drawerItem let-item let-level="level">
56
62
  <div class="drawer-item-wrapper">
57
63
  <!-- Item Button/Link -->
58
- <a
59
- *ngIf="item.route && !item.children"
60
- [routerLink]="item.route"
61
- class="drawer-item"
62
- [class.active]="isActiveRoute(item.route)"
63
- [class.has-children]="item.children && item.children.length > 0"
64
- [style.paddingLeft.px]="isExpanded ? 16 + level * 16 : 16"
65
- [matTooltip]="!isExpanded ? item.label : ''"
66
- matTooltipPosition="right"
67
- matTooltipClass="text-text-primary text-xs font-semibold"
68
- (click)="onItemClick(item, $event)"
69
- >
70
- <div class="item-content">
71
- <fx-ui-hero-icon [icon]="item.icon" [size]="20" class="item-icon"></fx-ui-hero-icon>
72
- <span *ngIf="isExpanded" class="item-label">{{ item.label }}</span>
73
- </div>
74
- </a>
64
+ @if (item.route && !item.children) {
65
+ <a
66
+ [routerLink]="item.route"
67
+ class="drawer-item"
68
+ [class.active]="isActiveRoute(item.route)"
69
+ [class.has-children]="item.children && item.children.length > 0"
70
+ [style.paddingLeft.px]="isExpanded ? 16 + level * 16 : 16"
71
+ [matTooltip]="!isExpanded ? item.label : ''"
72
+ matTooltipPosition="right"
73
+ matTooltipClass="text-text-primary text-xs font-semibold"
74
+ (click)="onItemClick(item, $event)"
75
+ >
76
+ <div class="item-content">
77
+ <fx-ui-hero-icon [icon]="item.icon" [size]="20" class="item-icon"></fx-ui-hero-icon>
78
+ @if (isExpanded) {
79
+ <span class="item-label">{{ item.label }}</span>
80
+ }
81
+ </div>
82
+ </a>
83
+ }
75
84
 
76
- <button
77
- *ngIf="!item.route || item.children"
78
- type="button"
79
- class="drawer-item"
80
- [class.active]="isActiveRoute(item.route)"
81
- [class.has-children]="item.children && item.children.length > 0"
82
- [style.paddingLeft.px]="isExpanded ? 16 + level * 16 : 16"
83
- [matTooltip]="!isExpanded ? item.label : ''"
84
- matTooltipPosition="right"
85
- matTooltipClass="text-text-primary text-sm font-semibold"
86
- (click)="onItemClick(item, $event)"
87
- >
88
- <div class="item-content">
89
- <fx-ui-hero-icon [icon]="item.icon" [size]="20" class="item-icon"></fx-ui-hero-icon>
90
- <span *ngIf="isExpanded" class="item-label">{{ item.label }}</span>
91
- <fx-ui-hero-icon
92
- *ngIf="isExpanded && item.children && item.children.length > 0"
93
- [icon]="'chevron-down'"
94
- [size]="16"
95
- class="chevron-icon"
96
- [class.rotated]="isAccordionExpanded(item.id)"
97
- ></fx-ui-hero-icon>
98
- </div>
99
- </button>
85
+ @if (!item.route || item.children) {
86
+ <button
87
+ type="button"
88
+ class="drawer-item"
89
+ [class.active]="isActiveRoute(item.route)"
90
+ [class.has-children]="item.children && item.children.length > 0"
91
+ [style.paddingLeft.px]="isExpanded ? 16 + level * 16 : 16"
92
+ [matTooltip]="!isExpanded ? item.label : ''"
93
+ matTooltipPosition="right"
94
+ matTooltipClass="text-text-primary text-sm font-semibold"
95
+ (click)="onItemClick(item, $event)"
96
+ >
97
+ <div class="item-content">
98
+ <fx-ui-hero-icon [icon]="item.icon" [size]="20" class="item-icon"></fx-ui-hero-icon>
99
+ @if (isExpanded) {
100
+ <span class="item-label">{{ item.label }}</span>
101
+ }
102
+ @if (isExpanded && item.children && item.children.length > 0) {
103
+ <fx-ui-hero-icon
104
+ [icon]="'chevron-down'"
105
+ [size]="16"
106
+ class="chevron-icon"
107
+ [class.rotated]="isAccordionExpanded(item.id)"
108
+ ></fx-ui-hero-icon>
109
+ }
110
+ </div>
111
+ </button>
112
+ }
100
113
 
101
114
  <!-- Accordion Children -->
102
- <div
103
- *ngIf="item.children && item.children.length > 0"
104
- class="accordion-children"
105
- [@accordionExpand]="getAccordionState(item.id)"
106
- >
107
- <ng-container *ngFor="let child of item.children">
108
- <ng-container
109
- *ngTemplateOutlet="drawerItem; context: { $implicit: child, level: level + 1 }"
110
- ></ng-container>
111
- </ng-container>
112
- </div>
115
+ @if (item.children && item.children.length > 0) {
116
+ <div
117
+ class="accordion-children"
118
+ [@accordionExpand]="getAccordionState(item.id)"
119
+ >
120
+ @for (child of item.children; track child) {
121
+ <ng-container
122
+ *ngTemplateOutlet="drawerItem; context: { $implicit: child, level: level + 1 }"
123
+ ></ng-container>
124
+ }
125
+ </div>
126
+ }
113
127
  </div>
114
128
  </ng-template>
@@ -1,9 +1,9 @@
1
1
  <div
2
2
  class="flex flex-col items-center justify-center gap-small w-full"
3
- [style.minHeight]="height"
3
+ [style.minHeight]="height()"
4
4
  >
5
5
  @if (icon) {
6
6
  <fx-ui-hero-icon class="text-text-placeholder" [icon]="icon" [size]="24"></fx-ui-hero-icon>
7
7
  }
8
- <div class="txt-default text-text-placeholder">{{ message }}</div>
8
+ <div class="txt-default text-text-placeholder">{{ message() }}</div>
9
9
  </div>