@foxeltech/angular-ui 0.0.1
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/BeVietnamPro/BeVietnamPro-Bold.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-ExtraLight.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-Light.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-Medium.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-Regular.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-SemiBold.ttf +0 -0
- package/BeVietnamPro/BeVietnamPro-Thin.ttf +0 -0
- package/README.md +3 -0
- package/SpaceMono-Regular.ttf +0 -0
- package/animations.css +130 -0
- package/components.css +480 -0
- package/dialogs.css +70 -0
- package/dm-sans/DMSans-Bold.ttf +0 -0
- package/dm-sans/DMSans-Light.ttf +0 -0
- package/dm-sans/DMSans-Medium.ttf +0 -0
- package/dm-sans/DMSans-Regular.ttf +0 -0
- package/dm-sans/DMSans-SemiBold.ttf +0 -0
- package/dm-sans/DMSans-Thin.ttf +0 -0
- package/fesm2022/foxeltech-angular-ui.mjs +3450 -0
- package/fesm2022/foxeltech-angular-ui.mjs.map +1 -0
- package/fonts.css +125 -0
- package/index.d.ts +1022 -0
- package/orbitron/Orbitron-Bold.ttf +0 -0
- package/orbitron/Orbitron-Medium.ttf +0 -0
- package/orbitron/Orbitron-Regular.ttf +0 -0
- package/orbitron/Orbitron-SemiBold.ttf +0 -0
- package/package.json +56 -0
- package/src/lib/styles/animations.css +130 -0
- package/src/lib/styles/components.css +480 -0
- package/src/lib/styles/dialogs.css +70 -0
- package/src/lib/styles/fonts.css +125 -0
- package/src/lib/styles/tailwind.css +18 -0
- package/src/lib/styles/theme.css +67 -0
- package/src/lib/ui/components/button/button.component.html +223 -0
- package/src/lib/ui/components/chart/chart.component.html +11 -0
- package/src/lib/ui/components/checkbox/checkbox.component.html +42 -0
- package/src/lib/ui/components/circle-progress-bar/circle-progress-bar.component.html +44 -0
- package/src/lib/ui/components/datetime-picker/datetime-picker.component.html +36 -0
- package/src/lib/ui/components/dnd-upload/dnd-upload.component.html +34 -0
- package/src/lib/ui/components/drawer/drawer.component.html +101 -0
- package/src/lib/ui/components/flow-connection/flow-connection.component.html +10 -0
- package/src/lib/ui/components/hero-icon/hero-icon.component.html +8 -0
- package/src/lib/ui/components/input/input.component.css +0 -0
- package/src/lib/ui/components/input/input.component.html +48 -0
- package/src/lib/ui/components/kanban-board/kanban-board.component.html +43 -0
- package/src/lib/ui/components/loading-panel/loading-panel.component.html +51 -0
- package/src/lib/ui/components/radio-button/radio-button.component.css +0 -0
- package/src/lib/ui/components/radio-button/radio-button.component.html +35 -0
- package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.html +34 -0
- package/src/lib/ui/components/rich-text-area/rich-text-area.component.html +3 -0
- package/src/lib/ui/components/search-bar/search-bar.component.html +22 -0
- package/src/lib/ui/components/select/select.component.css +102 -0
- package/src/lib/ui/components/select/select.component.html +42 -0
- package/src/lib/ui/components/skeleton-table-loading/skeleton-table-loading.component.html +21 -0
- package/src/lib/ui/components/slider/slider.component.html +54 -0
- package/src/lib/ui/components/switch/switch.component.html +21 -0
- package/src/lib/ui/components/tab-component/tab.component.html +1 -0
- package/src/lib/ui/components/tab-group/tab-group.component.html +75 -0
- package/src/lib/ui/components/table-cell/table-cell.component.html +7 -0
- package/src/lib/ui/components/tag/tag.component.html +15 -0
- package/src/lib/ui/components/toast/toast.component.html +48 -0
- package/src/lib/ui/components/toast-container/toast-container.component.html +12 -0
- package/src/lib/ui/components/tree-diagram/tree-diagram.component.html +40 -0
- package/src/lib/ui/dialogs/confirmation/confirmation.component.html +17 -0
- package/tailwind-config.d.ts +4 -0
- package/tailwind.config.js +88 -0
- package/tailwind.css +18 -0
- package/theme.css +67 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<div class="drawer-host-wrapper">
|
|
2
|
+
<a href="/" class="h-[60px] p-4">
|
|
3
|
+
@if (logo) {
|
|
4
|
+
<img
|
|
5
|
+
[src]="logo"
|
|
6
|
+
class="h-[20px] w-auto transition-all duration-300 ease-in-out"
|
|
7
|
+
[ngClass]="{ 'scale-90 ml-2': !isExpanded, 'ml-5': isExpanded }"
|
|
8
|
+
/>
|
|
9
|
+
} @else {
|
|
10
|
+
<div class="h-[30px] w-auto transition-all duration-300 ease-in-out"></div>
|
|
11
|
+
}
|
|
12
|
+
</a>
|
|
13
|
+
<div class="drawer-container" [@drawerExpand]="getDrawerState()">
|
|
14
|
+
<!-- Navigation Items -->
|
|
15
|
+
<nav class="drawer-nav">
|
|
16
|
+
<ng-container *ngFor="let item of items">
|
|
17
|
+
<ng-container
|
|
18
|
+
*ngTemplateOutlet="drawerItem; context: { $implicit: item, level: 0 }"
|
|
19
|
+
></ng-container>
|
|
20
|
+
</ng-container>
|
|
21
|
+
</nav>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<!-- Floating Toggle Button on right border -->
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
class="toggle-btn"
|
|
28
|
+
(click)="toggleDrawer()"
|
|
29
|
+
[matTooltip]="isExpanded ? 'Collapse' : 'Expand'"
|
|
30
|
+
matTooltipClass="text-text-primary text-xs font-semibold"
|
|
31
|
+
matTooltipPosition="right"
|
|
32
|
+
>
|
|
33
|
+
<fx-ui-hero-icon
|
|
34
|
+
[icon]="isExpanded ? 'chevron-left' : 'chevron-right'"
|
|
35
|
+
[size]="16"
|
|
36
|
+
class="text-text-primary"
|
|
37
|
+
></fx-ui-hero-icon>
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<!-- Recursive Template for Drawer Items -->
|
|
42
|
+
<ng-template #drawerItem let-item let-level="level">
|
|
43
|
+
<div class="drawer-item-wrapper">
|
|
44
|
+
<!-- Item Button/Link -->
|
|
45
|
+
<a
|
|
46
|
+
*ngIf="item.route && !item.children"
|
|
47
|
+
[routerLink]="item.route"
|
|
48
|
+
class="drawer-item"
|
|
49
|
+
[class.active]="isActiveRoute(item.route)"
|
|
50
|
+
[class.has-children]="item.children && item.children.length > 0"
|
|
51
|
+
[style.paddingLeft.px]="isExpanded ? 16 + level * 16 : 16"
|
|
52
|
+
[matTooltip]="!isExpanded ? item.label : ''"
|
|
53
|
+
matTooltipPosition="right"
|
|
54
|
+
matTooltipClass="text-text-primary text-xs font-semibold"
|
|
55
|
+
(click)="onItemClick(item, $event)"
|
|
56
|
+
>
|
|
57
|
+
<div class="item-content">
|
|
58
|
+
<fx-ui-hero-icon [icon]="item.icon" [size]="20" class="item-icon"></fx-ui-hero-icon>
|
|
59
|
+
<span *ngIf="isExpanded" class="item-label">{{ item.label }}</span>
|
|
60
|
+
</div>
|
|
61
|
+
</a>
|
|
62
|
+
|
|
63
|
+
<button
|
|
64
|
+
*ngIf="!item.route || item.children"
|
|
65
|
+
type="button"
|
|
66
|
+
class="drawer-item"
|
|
67
|
+
[class.active]="isActiveRoute(item.route)"
|
|
68
|
+
[class.has-children]="item.children && item.children.length > 0"
|
|
69
|
+
[style.paddingLeft.px]="isExpanded ? 16 + level * 16 : 16"
|
|
70
|
+
[matTooltip]="!isExpanded ? item.label : ''"
|
|
71
|
+
matTooltipPosition="right"
|
|
72
|
+
matTooltipClass="text-text-primary text-sm font-semibold"
|
|
73
|
+
(click)="onItemClick(item, $event)"
|
|
74
|
+
>
|
|
75
|
+
<div class="item-content">
|
|
76
|
+
<fx-ui-hero-icon [icon]="item.icon" [size]="20" class="item-icon"></fx-ui-hero-icon>
|
|
77
|
+
<span *ngIf="isExpanded" class="item-label">{{ item.label }}</span>
|
|
78
|
+
<fx-ui-hero-icon
|
|
79
|
+
*ngIf="isExpanded && item.children && item.children.length > 0"
|
|
80
|
+
[icon]="'chevron-down'"
|
|
81
|
+
[size]="16"
|
|
82
|
+
class="chevron-icon"
|
|
83
|
+
[class.rotated]="isAccordionExpanded(item.id)"
|
|
84
|
+
></fx-ui-hero-icon>
|
|
85
|
+
</div>
|
|
86
|
+
</button>
|
|
87
|
+
|
|
88
|
+
<!-- Accordion Children -->
|
|
89
|
+
<div
|
|
90
|
+
*ngIf="item.children && item.children.length > 0"
|
|
91
|
+
class="accordion-children"
|
|
92
|
+
[@accordionExpand]="getAccordionState(item.id)"
|
|
93
|
+
>
|
|
94
|
+
<ng-container *ngFor="let child of item.children">
|
|
95
|
+
<ng-container
|
|
96
|
+
*ngTemplateOutlet="drawerItem; context: { $implicit: child, level: level + 1 }"
|
|
97
|
+
></ng-container>
|
|
98
|
+
</ng-container>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</ng-template>
|
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<div class="mb-4 text-left w-full text-text-primary" [class]="class">
|
|
2
|
+
@if(label){<label class="block txt-field-label">
|
|
3
|
+
{{ label }}
|
|
4
|
+
@if (required) {<span class="txt-required">*</span>}
|
|
5
|
+
</label>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
<div class="relative">
|
|
9
|
+
<input
|
|
10
|
+
appTrimOnBlur
|
|
11
|
+
[appTrimOnBlurCollapse]="true"
|
|
12
|
+
[type]="displayType"
|
|
13
|
+
[placeholder]="placeholder"
|
|
14
|
+
[disabled]="disabled"
|
|
15
|
+
[value]="value"
|
|
16
|
+
(input)="onInput($event)"
|
|
17
|
+
(blur)="onBlur()"
|
|
18
|
+
(focus)="onFocus()"
|
|
19
|
+
[attr.maxlength]="maxlength"
|
|
20
|
+
[class]="type === 'otp' ? 'input-otp' : 'input-default'"
|
|
21
|
+
[ngClass]="{
|
|
22
|
+
'input-invalid': invalid,
|
|
23
|
+
'pr-8': type === 'password' || suffixIcon,
|
|
24
|
+
'txt-otp-input': type === 'otp'
|
|
25
|
+
}"
|
|
26
|
+
/>
|
|
27
|
+
<button
|
|
28
|
+
type="button"
|
|
29
|
+
class="absolute inset-y-0 right-2 flex items-center text-text-primary hover:text-text-secondary"
|
|
30
|
+
(click)="onSuffixClick()"
|
|
31
|
+
[disabled]="disabled"
|
|
32
|
+
>
|
|
33
|
+
@if (type === 'password') {
|
|
34
|
+
<i class="material-symbols-outlined text-lg select-none">{{
|
|
35
|
+
showPassword ? 'visibility_off' : 'visibility'
|
|
36
|
+
}}</i>
|
|
37
|
+
} @else if (suffixIcon) {
|
|
38
|
+
<i [class]="iconClass" class="text-lg select-none">{{ suffixIcon }}</i>
|
|
39
|
+
}
|
|
40
|
+
</button>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
@if (invalid){
|
|
44
|
+
<div class="txt-invalid">
|
|
45
|
+
{{ getErrorMessage(label) }}
|
|
46
|
+
</div>
|
|
47
|
+
}
|
|
48
|
+
</div>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<div class="kanban-board">
|
|
2
|
+
<div class="kanban-columns">
|
|
3
|
+
@for (column of columns; track column.id) {
|
|
4
|
+
<div class="kanban-column">
|
|
5
|
+
<div class="kanban-column-header">
|
|
6
|
+
<h3 class="kanban-column-title">{{ column.title }}</h3>
|
|
7
|
+
<span class="kanban-column-count">{{ column.items.length }}</span>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div
|
|
11
|
+
class="kanban-column-content"
|
|
12
|
+
cdkDropList
|
|
13
|
+
[id]="column.id"
|
|
14
|
+
[cdkDropListData]="column.items"
|
|
15
|
+
[cdkDropListConnectedTo]="getColumnIds()"
|
|
16
|
+
(cdkDropListDropped)="onDrop($event, column.id)"
|
|
17
|
+
>
|
|
18
|
+
@for (item of column.items; track $index) {
|
|
19
|
+
<div class="kanban-item" cdkDrag>
|
|
20
|
+
<div class="kanban-item-placeholder" *cdkDragPlaceholder></div>
|
|
21
|
+
|
|
22
|
+
@if (itemTemplate) {
|
|
23
|
+
<ng-container
|
|
24
|
+
*ngTemplateOutlet="itemTemplate; context: { $implicit: item, index: $index }"
|
|
25
|
+
></ng-container>
|
|
26
|
+
} @else {
|
|
27
|
+
<div class="kanban-item-default">
|
|
28
|
+
{{ item }}
|
|
29
|
+
</div>
|
|
30
|
+
}
|
|
31
|
+
</div>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@if (column.items.length === 0) {
|
|
35
|
+
<div class="kanban-column-empty">
|
|
36
|
+
Drop items here
|
|
37
|
+
</div>
|
|
38
|
+
}
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!-- Full-screen glass overlay -->
|
|
2
|
+
<div
|
|
3
|
+
*ngIf="show"
|
|
4
|
+
class="fixed inset-0 z-50 flex items-center justify-center"
|
|
5
|
+
aria-hidden="false"
|
|
6
|
+
role="alert"
|
|
7
|
+
aria-busy="true"
|
|
8
|
+
>
|
|
9
|
+
<div class="absolute inset-0 bg-bg-primary/30 backdrop-blur-xl" aria-hidden="true"></div>
|
|
10
|
+
|
|
11
|
+
<div
|
|
12
|
+
class="relative z-10 flex flex-col items-center gap-4 p-6 rounded-2xl shadow-xl bg-bg-primary/70 border border-border-strong backdrop-bg-primary/70"
|
|
13
|
+
style="min-width: 220px; max-width: 90%"
|
|
14
|
+
>
|
|
15
|
+
<svg fill="rgb(var(--primary))" width="50" height="50" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
16
|
+
<circle cx="4" cy="12" r="0">
|
|
17
|
+
<animate begin="0;spinner_z0Or.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="0;3" fill="freeze"/>
|
|
18
|
+
<animate begin="spinner_OLMs.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="4;12" fill="freeze"/>
|
|
19
|
+
<animate begin="spinner_UHR2.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="12;20" fill="freeze"/>
|
|
20
|
+
<animate id="spinner_lo66" begin="spinner_Aguh.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="3;0" fill="freeze"/>
|
|
21
|
+
<animate id="spinner_z0Or" begin="spinner_lo66.end" attributeName="cx" dur="0.001s" values="20;4" fill="freeze"/>
|
|
22
|
+
</circle>
|
|
23
|
+
<circle cx="4" cy="12" r="3">
|
|
24
|
+
<animate begin="0;spinner_z0Or.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="4;12" fill="freeze"/>
|
|
25
|
+
<animate begin="spinner_OLMs.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="12;20" fill="freeze"/>
|
|
26
|
+
<animate id="spinner_JsnR" begin="spinner_UHR2.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="3;0" fill="freeze"/>
|
|
27
|
+
<animate id="spinner_Aguh" begin="spinner_JsnR.end" attributeName="cx" dur="0.001s" values="20;4" fill="freeze"/>
|
|
28
|
+
<animate begin="spinner_Aguh.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="0;3" fill="freeze"/>
|
|
29
|
+
</circle>
|
|
30
|
+
<circle cx="12" cy="12" r="3">
|
|
31
|
+
<animate begin="0;spinner_z0Or.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="12;20" fill="freeze"/>
|
|
32
|
+
<animate id="spinner_hSjk" begin="spinner_OLMs.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="3;0" fill="freeze"/>
|
|
33
|
+
<animate id="spinner_UHR2" begin="spinner_hSjk.end" attributeName="cx" dur="0.001s" values="20;4" fill="freeze"/>
|
|
34
|
+
<animate begin="spinner_UHR2.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="0;3" fill="freeze"/>
|
|
35
|
+
<animate begin="spinner_Aguh.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="4;12" fill="freeze"/>
|
|
36
|
+
</circle>
|
|
37
|
+
<circle cx="20" cy="12" r="3">
|
|
38
|
+
<animate id="spinner_4v5M" begin="0;spinner_z0Or.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="3;0" fill="freeze"/>
|
|
39
|
+
<animate id="spinner_OLMs" begin="spinner_4v5M.end" attributeName="cx" dur="0.001s" values="20;4" fill="freeze"/>
|
|
40
|
+
<animate begin="spinner_OLMs.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="0;3" fill="freeze"/>
|
|
41
|
+
<animate begin="spinner_UHR2.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="4;12" fill="freeze"/>
|
|
42
|
+
<animate begin="spinner_Aguh.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="12;20" fill="freeze"/>
|
|
43
|
+
</circle>
|
|
44
|
+
</svg>
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
<div *ngIf="message" class="text-sm text-text-primary text-center">
|
|
48
|
+
{{ message }}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<div class="w-full rounded-lg overflow-hidden" [class]="class" role="radiogroup">
|
|
2
|
+
@if (label){
|
|
3
|
+
<label class="txt-field-label">
|
|
4
|
+
{{ label }}
|
|
5
|
+
@if(required){<span class="txt-required">*</span>} </label
|
|
6
|
+
>}
|
|
7
|
+
|
|
8
|
+
<button
|
|
9
|
+
*ngFor="let opt of options"
|
|
10
|
+
type="button"
|
|
11
|
+
role="radio"
|
|
12
|
+
[attr.aria-checked]="value === opt.value"
|
|
13
|
+
(click)="onSelectValue(opt.value)"
|
|
14
|
+
[disabled]="disabled"
|
|
15
|
+
[class.text-gray-900]="value !== opt.value"
|
|
16
|
+
class="flex-1 px-normal w-full flex items-center gap-normal h-10 rounded-md hover:bg-bg-hover transition-all duration-150 disabled:opacity-60 disabled:cursor-not-allowed"
|
|
17
|
+
>
|
|
18
|
+
<span
|
|
19
|
+
[ngClass]="{
|
|
20
|
+
'radio-checked': value === opt.value,
|
|
21
|
+
'radio-uncheck': value !== opt.value
|
|
22
|
+
}"
|
|
23
|
+
class="radio-container"
|
|
24
|
+
>
|
|
25
|
+
@if(value === opt.value) {<span class="radio-dot"></span>}
|
|
26
|
+
</span>
|
|
27
|
+
|
|
28
|
+
<span class="txt-default mb-0">{{ opt.label }}</span>
|
|
29
|
+
</button>
|
|
30
|
+
@if (invalid){
|
|
31
|
+
<div class="txt-invalid">
|
|
32
|
+
{{ getErrorMessage(label) }}
|
|
33
|
+
</div>
|
|
34
|
+
}
|
|
35
|
+
</div>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<div class="flex flex-col text-left mb-4 w-full" [class]="class">
|
|
2
|
+
@if(label){<label class="txt-field-label">
|
|
3
|
+
{{ label }}
|
|
4
|
+
@if(required) {<span class="txt-required">*</span>} </label
|
|
5
|
+
>}
|
|
6
|
+
|
|
7
|
+
<div class="inline-flex w-full rounded-lg overflow-hidden" role="radiogroup">
|
|
8
|
+
@for(opt of options; track opt){<button
|
|
9
|
+
type="button"
|
|
10
|
+
role="radio"
|
|
11
|
+
[attr.aria-checked]="value === opt.value"
|
|
12
|
+
(click)="onSelectValue(opt.value)"
|
|
13
|
+
[disabled]="disabled"
|
|
14
|
+
[class.text-gray-900]="value !== opt.value"
|
|
15
|
+
class="flex-1 bg-bg-primary flex items-center pl-normal gap-normal h-10 rounded-md hover:bg-bg-hover transition-all duration-150 disabled:opacity-60 disabled:cursor-not-allowed"
|
|
16
|
+
>
|
|
17
|
+
<span
|
|
18
|
+
[ngClass]="{
|
|
19
|
+
'radio-checked': value === opt.value,
|
|
20
|
+
'radio-uncheck': value !== opt.value
|
|
21
|
+
}"
|
|
22
|
+
class="radio-container"
|
|
23
|
+
>
|
|
24
|
+
@if(value === opt.value) {<span class="radio-dot"></span>}
|
|
25
|
+
</span>
|
|
26
|
+
|
|
27
|
+
<span class="txt-field-label mb-0">{{ opt.label }}</span></button
|
|
28
|
+
>}
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
@if(invalid){
|
|
32
|
+
<div class="txt-invalid">{{ getErrorMessage(label) }}</div>
|
|
33
|
+
}
|
|
34
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<div class="relative">
|
|
2
|
+
<fx-ui-hero-icon icon="magnifying-glass" [size]="18" class="absolute left-1 top-[3px] text-text-primary"></fx-ui-hero-icon>
|
|
3
|
+
<input
|
|
4
|
+
type="text"
|
|
5
|
+
class="input-default px-9"
|
|
6
|
+
[attr.placeholder]="placeholder"
|
|
7
|
+
[disabled]="disabled"
|
|
8
|
+
[value]="value"
|
|
9
|
+
(input)="onValueChange($any($event.target).value)"
|
|
10
|
+
(keydown.enter)="onEnterKey()"
|
|
11
|
+
/>
|
|
12
|
+
|
|
13
|
+
<button
|
|
14
|
+
*ngIf="value && !disabled"
|
|
15
|
+
type="button"
|
|
16
|
+
class="absolute inset-y-0 right-2 flex items-center text-text-primary hover:text-text-secondary"
|
|
17
|
+
(click)="clear()"
|
|
18
|
+
aria-label="Clear"
|
|
19
|
+
>
|
|
20
|
+
<i class="material-symbols-outlined text-lg select-none">close</i>
|
|
21
|
+
</button>
|
|
22
|
+
</div>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
::ng-deep .fx-select-field {
|
|
2
|
+
display: block !important;
|
|
3
|
+
width: 100% !important;
|
|
4
|
+
margin: 0 !important;
|
|
5
|
+
padding: 0 !important;
|
|
6
|
+
border-radius: 0.75rem;
|
|
7
|
+
box-shadow: 0 1px 1px rgb(var(--border-default));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
::ng-deep .fx-select-field .mat-mdc-form-field-wrapper,
|
|
11
|
+
::ng-deep .fx-select-field .mat-mdc-text-field-wrapper {
|
|
12
|
+
padding: 0 !important;
|
|
13
|
+
margin: 0 !important;
|
|
14
|
+
width: 100% !important;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
::ng-deep .fx-select-field .mdc-text-field {
|
|
18
|
+
width: 100% !important;
|
|
19
|
+
margin: 0 !important;
|
|
20
|
+
padding: 0 !important;
|
|
21
|
+
--mdc-shape-small: 0 !important;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
::ng-deep .fx-select-field .mat-mdc-form-field-flex {
|
|
25
|
+
width: 100% !important;
|
|
26
|
+
margin: 0 !important;
|
|
27
|
+
padding: 0 0.75rem !important;
|
|
28
|
+
border: 1px solid rgb(var(--border-default));
|
|
29
|
+
border-radius: 0.5rem;
|
|
30
|
+
height: 36px !important;
|
|
31
|
+
align-items: center;
|
|
32
|
+
background-color: rgb(var(--bg-primary));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
::ng-deep .fx-select-field .mdc-notched-outline,
|
|
36
|
+
::ng-deep .fx-select-field .mat-mdc-form-field-subscript-wrapper {
|
|
37
|
+
display: none !important;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
::ng-deep .fx-select-field.mat-focused .mat-mdc-form-field-flex {
|
|
41
|
+
border: 2px solid rgb(var(--border-interactive)) !important;
|
|
42
|
+
outline: none !important;
|
|
43
|
+
border-radius: 0.5rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
::ng-deep .fx-select-field.mat-form-field-invalid .mat-mdc-form-field-flex {
|
|
47
|
+
border-color: #ef4444 !important;
|
|
48
|
+
box-shadow: none !important;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
::ng-deep .fx-select-field .mat-mdc-select-trigger {
|
|
52
|
+
padding: 0 !important;
|
|
53
|
+
margin: 0 !important;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
::ng-deep .fx-select-field .mat-mdc-select-arrow-wrapper {
|
|
57
|
+
margin-right: 0 !important;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
::ng-deep .fx-select-field .mat-mdc-select-arrow-wrapper {
|
|
61
|
+
color: rgb(var(--text-primary));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
::ng-deep .mat-mdc-select-panel {
|
|
65
|
+
background-color: rgb(var(--bg-primary)) !important;
|
|
66
|
+
border: 1px solid rgb(var(--border-default)) !important;
|
|
67
|
+
border-radius: 0.5rem !important;
|
|
68
|
+
box-shadow: 0 2px 4px rgb(0 0 0 / 0.1) !important;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
::ng-deep .fx-select-field .mat-mdc-select-placeholder {
|
|
72
|
+
color: rgb(var(--text-placeholder)) !important;
|
|
73
|
+
font-size: 14px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
::ng-deep .fx-select-field .mat-mdc-select-value {
|
|
77
|
+
color: rgb(var(--text-primary)) !important;
|
|
78
|
+
font-size: 14px;
|
|
79
|
+
font-weight: 400;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.mat-select-panel .search-option-full-width {
|
|
83
|
+
/* Remove default padding to allow the input to stretch */
|
|
84
|
+
padding-left: 0 !important;
|
|
85
|
+
padding-right: 0 !important;
|
|
86
|
+
/* Ensure it is a block element to take up full width */
|
|
87
|
+
display: block;
|
|
88
|
+
/* Prevent the option from being highlighted on hover/focus */
|
|
89
|
+
pointer-events: none;
|
|
90
|
+
/* Optional: Adjust height if needed */
|
|
91
|
+
line-height: initial;
|
|
92
|
+
height: auto;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.mat-select-panel .search-option-full-width .search-bar {
|
|
96
|
+
width: 100%;
|
|
97
|
+
padding: 8px 16px; /* Add visual padding back to the input */
|
|
98
|
+
border: none;
|
|
99
|
+
/* Optional: Add a subtle border to separate it from the options */
|
|
100
|
+
border-bottom: 1px solid #ddd;
|
|
101
|
+
box-sizing: border-box; /* Include padding in the element's total width */
|
|
102
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<div class="mb-4 text-left w-full" [class]="class">
|
|
2
|
+
@if (label) {
|
|
3
|
+
<label class="block txt-field-label">
|
|
4
|
+
{{ label }}
|
|
5
|
+
@if(required) {<span class="txt-required">*</span>}
|
|
6
|
+
</label>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
<mat-form-field class="fx-select-field w-full shadow-sm" appearance="fill">
|
|
10
|
+
<mat-select
|
|
11
|
+
[placeholder]="placeholder"
|
|
12
|
+
[disabled]="disabled"
|
|
13
|
+
[multiple]="multiple"
|
|
14
|
+
[value]="value"
|
|
15
|
+
(selectionChange)="onSelectionChange($event.value)"
|
|
16
|
+
(openedChange)="onOpened($event)"
|
|
17
|
+
(blur)="onTouched()"
|
|
18
|
+
>
|
|
19
|
+
@if(enableSearch){
|
|
20
|
+
<div class="px-semi w-full">
|
|
21
|
+
<input
|
|
22
|
+
type="text"
|
|
23
|
+
[placeholder]="'Search'"
|
|
24
|
+
[(ngModel)]="searchTerm"
|
|
25
|
+
(ngModelChange)="onSearchChange($event)"
|
|
26
|
+
(click)="$event.stopPropagation()"
|
|
27
|
+
class="text-text-primary placeholder:text-text-placeholder w-full bg-bg-primary border-b px-semi py-normal border-border-default focus:outline-none focus:border-border-interactive text-sm text-text-primary tracking-normal ring-0 transition-colors duration-500 ease-in-out"
|
|
28
|
+
/>
|
|
29
|
+
</div>
|
|
30
|
+
}
|
|
31
|
+
<mat-option *ngFor="let option of filteredOptions" [value]="option.value">
|
|
32
|
+
<span class="txt-default">{{ option.label }}</span>
|
|
33
|
+
</mat-option>
|
|
34
|
+
</mat-select>
|
|
35
|
+
</mat-form-field>
|
|
36
|
+
|
|
37
|
+
@if(invalid) {
|
|
38
|
+
<div class="txt-invalid text-left">
|
|
39
|
+
{{ getErrorMessage(label) }}
|
|
40
|
+
</div>
|
|
41
|
+
}
|
|
42
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<div class="w-full animate-pulse space-y-normal">
|
|
2
|
+
<div
|
|
3
|
+
class="grid gap-small"
|
|
4
|
+
[ngStyle]="{ 'grid-template-columns': 'repeat(' + columns + ', minmax(0, 1fr))' }"
|
|
5
|
+
>
|
|
6
|
+
@for(col of [].constructor(columns); track col) {
|
|
7
|
+
<div class="h-6 bg-bg-hover rounded"></div>
|
|
8
|
+
}
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
@for(row of [].constructor(rows); track row) {
|
|
12
|
+
<div
|
|
13
|
+
class="grid gap-small"
|
|
14
|
+
[ngStyle]="{ 'grid-template-columns': 'repeat(' + columns + ', minmax(0, 1fr))' }"
|
|
15
|
+
>
|
|
16
|
+
@for(col of [].constructor(columns); track col) {
|
|
17
|
+
<div class="h-7 bg-bg-hover rounded"></div>
|
|
18
|
+
}
|
|
19
|
+
</div>
|
|
20
|
+
}
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<div
|
|
2
|
+
class="w-full select-none"
|
|
3
|
+
[class.cursor-not-allowed]="disabled"
|
|
4
|
+
[class.opacity-60]="disabled"
|
|
5
|
+
role="group"
|
|
6
|
+
>
|
|
7
|
+
<div
|
|
8
|
+
#track
|
|
9
|
+
class="relative touch-none py-4"
|
|
10
|
+
(click)="onTrackClick($event)"
|
|
11
|
+
[attr.aria-disabled]="disabled"
|
|
12
|
+
[attr.aria-orientation]="vertical ? 'vertical' : 'horizontal'"
|
|
13
|
+
>
|
|
14
|
+
<div
|
|
15
|
+
class="relative flex items-center"
|
|
16
|
+
[ngClass]="{ 'flex-col h-48': vertical }"
|
|
17
|
+
>
|
|
18
|
+
<div
|
|
19
|
+
class="relative flex-1 rounded-full bg-gray-600 h-2"
|
|
20
|
+
[ngClass]="{ 'w-1 rotate-0 h-full w-auto bg-border-gray-700': vertical }"
|
|
21
|
+
>
|
|
22
|
+
<div
|
|
23
|
+
class="absolute left-0 top-0 h-full rounded-full bg-primary"
|
|
24
|
+
*ngIf="!vertical"
|
|
25
|
+
[style.width.%]="percent"
|
|
26
|
+
></div>
|
|
27
|
+
|
|
28
|
+
<div
|
|
29
|
+
class="absolute bottom-0 left-0 w-full rounded-full bg-primary"
|
|
30
|
+
*ngIf="vertical"
|
|
31
|
+
[style.height.%]="percent"
|
|
32
|
+
style="transform-origin: bottom;"
|
|
33
|
+
></div>
|
|
34
|
+
|
|
35
|
+
<button
|
|
36
|
+
#thumb
|
|
37
|
+
type="button"
|
|
38
|
+
class="absolute -mt-1 -ml-1.5 w-4 h-4 rounded-full shadow focus:ring-primary bg-primary border-2 border-text-primary"
|
|
39
|
+
[ngStyle]="thumbStyle()"
|
|
40
|
+
role="slider"
|
|
41
|
+
[attr.aria-valuemin]="min"
|
|
42
|
+
[attr.aria-valuemax]="max"
|
|
43
|
+
[attr.aria-valuenow]="value"
|
|
44
|
+
[attr.aria-disabled]="disabled"
|
|
45
|
+
tabindex="0"
|
|
46
|
+
(pointerdown)="onPointerDown($event)"
|
|
47
|
+
(pointermove)="onPointerMove($event)"
|
|
48
|
+
(pointerup)="onPointerUp($event)"
|
|
49
|
+
[disabled]="disabled"
|
|
50
|
+
></button>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<div
|
|
2
|
+
class="relative flex items-center w-10 h-5 rounded-full transition-colors duration-300 cursor-pointer"
|
|
3
|
+
[ngClass]="{
|
|
4
|
+
'bg-success': value && !disabled,
|
|
5
|
+
'bg-button-default': !value && !disabled,
|
|
6
|
+
'bg-bg-hover': disabled
|
|
7
|
+
}"
|
|
8
|
+
(click)="toggle()"
|
|
9
|
+
>
|
|
10
|
+
@if(value) {
|
|
11
|
+
<i style="font-size: 20px;" class="material-symbols-outlined absolute left-0.5 top-0 text-text-inverse">check</i>
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
@if(!value) {
|
|
15
|
+
<i style="font-size: 20px;" class="material-symbols-outlined absolute right-0.5 top-0 text-text-inverse">close</i>
|
|
16
|
+
}
|
|
17
|
+
<div
|
|
18
|
+
class="absolute top-0.5 left-0.5 w-4 h-4 bg-text-inverse rounded-full shadow-md transform transition-transform duration-300"
|
|
19
|
+
[ngClass]="{ 'translate-x-5': value }"
|
|
20
|
+
></div>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<ng-template><ng-content></ng-content></ng-template>
|