@libs-ui/components-process-bar-circle 0.2.356-37 → 0.2.357-22
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/README.md
CHANGED
|
@@ -1,41 +1,38 @@
|
|
|
1
1
|
# @libs-ui/components-process-bar-circle
|
|
2
2
|
|
|
3
|
-
> Component hiển thị tiến trình dạng vòng tròn (Circular Progress Bar)
|
|
3
|
+
> Component hiển thị tiến trình dạng vòng tròn (Circular Progress Bar) SVG-based, hỗ trợ tùy biến linh hoạt về kích thước, màu sắc và nhãn hiển thị.
|
|
4
4
|
|
|
5
5
|
## Giới thiệu
|
|
6
6
|
|
|
7
|
-
`LibsUiComponentsProcessBarCircleComponent` là
|
|
7
|
+
`LibsUiComponentsProcessBarCircleComponent` là component vẽ vòng tròn tiến trình sử dụng SVG thuần, đảm bảo độ sắc nét cao trên mọi độ phân giải màn hình. Component nhận toàn bộ cấu hình qua một input duy nhất `[config]` kiểu `IProcessBarCircleInterface`, hỗ trợ tùy chỉnh kích thước, màu nền, màu tiến trình, độ dày nét vẽ và hiển thị nhãn phần trăm ở giữa. Mọi thuộc tính SVG được tính toán tự động từ `size` và `strokeWidth`, đảm bảo vòng tròn luôn căn giữa và không bị méo.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Tính năng
|
|
10
10
|
|
|
11
|
-
- ✅ **SVG-based**:
|
|
12
|
-
- ✅ **Cấu hình linh hoạt**:
|
|
13
|
-
- ✅ **Smooth
|
|
14
|
-
- ✅ **Label
|
|
15
|
-
- ✅ **OnPush
|
|
16
|
-
- ✅ **
|
|
11
|
+
- ✅ **SVG-based**: Vẽ bằng SVG, sắc nét trên mọi độ phân giải và màn hình Retina.
|
|
12
|
+
- ✅ **Cấu hình linh hoạt**: Tùy chỉnh `size`, `strokeWidth`, `color`, `backgroundColor`, `showLabel`, `labelClass`, `classInclude` qua một object duy nhất.
|
|
13
|
+
- ✅ **Smooth Animation**: CSS transition trên `stroke-dashoffset` giúp vòng tròn chuyển đổi mượt mà khi phần trăm thay đổi.
|
|
14
|
+
- ✅ **Label tùy chỉnh**: Hiển thị nhãn phần trăm ở giữa, có thể ẩn hoặc ghi đè class CSS.
|
|
15
|
+
- ✅ **OnPush + Signals**: Sử dụng `ChangeDetectionStrategy.OnPush` và Angular Signals, tối ưu hóa hiệu năng render.
|
|
16
|
+
- ✅ **Percent Clamping**: Tự động giới hạn giá trị percent trong khoảng [0, 100], không bị lỗi SVG khi nhận giá trị ngoài phạm vi.
|
|
17
17
|
|
|
18
18
|
## Khi nào sử dụng
|
|
19
19
|
|
|
20
|
-
- Hiển thị phần trăm hoàn thành của một tác vụ
|
|
21
|
-
- Biểu diễn số liệu thống kê
|
|
22
|
-
- Làm
|
|
23
|
-
-
|
|
20
|
+
- Hiển thị phần trăm hoàn thành của một tác vụ (upload, xử lý, tải dữ liệu).
|
|
21
|
+
- Biểu diễn số liệu thống kê dạng vòng tròn trên dashboard (dung lượng đĩa, tiến độ dự án, điểm số).
|
|
22
|
+
- Làm chỉ báo tiến trình (progress indicator) có trạng thái rõ ràng thay cho spinner đơn giản.
|
|
23
|
+
- Nhúng vào card, bảng dữ liệu hoặc widget nhỏ gọn để trực quan hóa KPI.
|
|
24
24
|
|
|
25
25
|
## Cài đặt
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
# npm
|
|
29
28
|
npm install @libs-ui/components-process-bar-circle
|
|
30
|
-
|
|
31
|
-
# yarn
|
|
32
|
-
yarn add @libs-ui/components-process-bar-circle
|
|
33
29
|
```
|
|
34
30
|
|
|
35
31
|
## Import
|
|
36
32
|
|
|
37
33
|
```typescript
|
|
38
34
|
import { LibsUiComponentsProcessBarCircleComponent } from '@libs-ui/components-process-bar-circle';
|
|
35
|
+
import { IProcessBarCircleInterface } from '@libs-ui/components-process-bar-circle';
|
|
39
36
|
|
|
40
37
|
@Component({
|
|
41
38
|
standalone: true,
|
|
@@ -45,80 +42,176 @@ import { LibsUiComponentsProcessBarCircleComponent } from '@libs-ui/components-p
|
|
|
45
42
|
export class YourComponent {}
|
|
46
43
|
```
|
|
47
44
|
|
|
48
|
-
## Ví dụ
|
|
45
|
+
## Ví dụ sử dụng
|
|
46
|
+
|
|
47
|
+
### 1. Sử dụng cơ bản
|
|
49
48
|
|
|
50
|
-
|
|
49
|
+
Hiển thị vòng tiến trình với các thiết lập mặc định.
|
|
51
50
|
|
|
52
51
|
```html
|
|
53
|
-
<libs_ui-components-process_bar-circle
|
|
52
|
+
<libs_ui-components-process_bar-circle
|
|
53
|
+
[config]="{ percent: 75 }" />
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// Không yêu cầu logic TS
|
|
54
58
|
```
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### 2. Các biến thể
|
|
63
|
+
|
|
64
|
+
Tùy chỉnh kích thước, độ dày và màu sắc khác nhau.
|
|
57
65
|
|
|
58
66
|
```html
|
|
67
|
+
<!-- Kích thước lớn, màu xanh lá -->
|
|
59
68
|
<libs_ui-components-process_bar-circle
|
|
60
69
|
[config]="{
|
|
61
|
-
percent:
|
|
70
|
+
percent: 100,
|
|
62
71
|
size: 150,
|
|
63
|
-
strokeWidth:
|
|
72
|
+
strokeWidth: 15,
|
|
64
73
|
color: '#10b981',
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
labelClass: 'text-2xl font-bold text-emerald-600'
|
|
75
|
+
}" />
|
|
76
|
+
|
|
77
|
+
<!-- Kích thước nhỏ, màu cam, ẩn label -->
|
|
78
|
+
<libs_ui-components-process_bar-circle
|
|
79
|
+
[config]="{
|
|
80
|
+
percent: 30,
|
|
81
|
+
size: 60,
|
|
82
|
+
strokeWidth: 6,
|
|
83
|
+
color: '#f59e0b',
|
|
84
|
+
showLabel: false
|
|
67
85
|
}" />
|
|
68
86
|
```
|
|
69
87
|
|
|
70
|
-
|
|
88
|
+
```typescript
|
|
89
|
+
// Cấu hình các style khác nhau qua thuộc tính config
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### 3. Demo tương tác
|
|
71
95
|
|
|
72
|
-
|
|
96
|
+
Thay đổi các giá trị trực tiếp để thấy sự phản hồi của component.
|
|
73
97
|
|
|
74
|
-
|
|
98
|
+
```html
|
|
99
|
+
<div class="flex flex-col items-center gap-6">
|
|
100
|
+
<libs_ui-components-process_bar-circle
|
|
101
|
+
[config]="{
|
|
102
|
+
percent: interactivePercent(),
|
|
103
|
+
size: interactiveSize(),
|
|
104
|
+
strokeWidth: interactiveStrokeWidth()
|
|
105
|
+
}" />
|
|
106
|
+
|
|
107
|
+
<div class="w-full max-w-xs space-y-4">
|
|
108
|
+
<div>
|
|
109
|
+
<label for="percent-range" class="block text-xs text-gray-400 mb-1">Percent: {{ interactivePercent() }}%</label>
|
|
110
|
+
<input id="percent-range" type="range" min="0" max="100" [value]="interactivePercent()" (input)="updatePercent($event)" class="w-full">
|
|
111
|
+
</div>
|
|
112
|
+
<div>
|
|
113
|
+
<label for="size-range" class="block text-xs text-gray-400 mb-1">Size: {{ interactiveSize() }}px</label>
|
|
114
|
+
<input id="size-range" type="range" min="50" max="250" [value]="interactiveSize()" (input)="updateSize($event)" class="w-full">
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
```
|
|
75
119
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
120
|
+
```typescript
|
|
121
|
+
import { signal } from '@angular/core';
|
|
122
|
+
|
|
123
|
+
// [config]="{ percent: interactivePercent(), size: interactiveSize(), strokeWidth: interactiveStrokeWidth() }"
|
|
124
|
+
readonly interactivePercent = signal(65);
|
|
125
|
+
readonly interactiveSize = signal(120);
|
|
126
|
+
readonly interactiveStrokeWidth = signal(10);
|
|
127
|
+
|
|
128
|
+
// Handler đổi percent — dùng cho (input)="updatePercent($event)"
|
|
129
|
+
updatePercent(e: Event): void {
|
|
130
|
+
this.interactivePercent.set(+(e.target as HTMLInputElement).value);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Handler đổi size — dùng cho (input)="updateSize($event)"
|
|
134
|
+
updateSize(e: Event): void {
|
|
135
|
+
this.interactiveSize.set(+(e.target as HTMLInputElement).value);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## @Input()
|
|
140
|
+
|
|
141
|
+
Component nhận một input duy nhất là `[config]` kiểu `IProcessBarCircleInterface` (bắt buộc).
|
|
142
|
+
|
|
143
|
+
| Input | Type | Default | Mô tả | Ví dụ |
|
|
144
|
+
|---|---|---|---|---|
|
|
145
|
+
| `[config]` | `IProcessBarCircleInterface` | **Bắt buộc** | Object chứa toàn bộ cấu hình hiển thị của vòng tròn tiến trình. | `[config]="{ percent: 75 }"` |
|
|
146
|
+
|
|
147
|
+
### Các thuộc tính của `IProcessBarCircleInterface`
|
|
148
|
+
|
|
149
|
+
| Thuộc tính | Type | Default | Bắt buộc | Mô tả | Ví dụ |
|
|
150
|
+
|---|---|---|---|---|---|
|
|
151
|
+
| `percent` | `number` | — | ✅ Có | Phần trăm hoàn thành. Tự động bị giới hạn trong khoảng [0, 100]. | `percent: 75` |
|
|
152
|
+
| `size` | `number` | `100` | Không | Kích thước cạnh của vùng chứa SVG (px). Áp dụng cho cả width lẫn height. | `size: 150` |
|
|
153
|
+
| `strokeWidth` | `number` | `8` | Không | Độ dày của nét vẽ vòng tròn (px). Ảnh hưởng đến bán kính thực của đường kẻ. | `strokeWidth: 12` |
|
|
154
|
+
| `color` | `string` | `'#3b82f6'` | Không | Màu của đường tiến trình (HEX, RGB, CSS color). | `color: '#10b981'` |
|
|
155
|
+
| `backgroundColor` | `string` | `'#f1f5f9'` | Không | Màu nền của vòng tròn phía sau (phần chưa hoàn thành). | `backgroundColor: '#e0f2fe'` |
|
|
156
|
+
| `showLabel` | `boolean` | `true` | Không | Có hiển thị nhãn phần trăm ở giữa vòng tròn hay không. | `showLabel: false` |
|
|
157
|
+
| `labelClass` | `string` | `''` | Không | Class CSS tùy chỉnh cho thẻ `<span>` chứa nhãn phần trăm. Ghi đè style mặc định `text-sm font-semibold text-gray-700`. | `labelClass: 'text-xl font-bold text-blue-600'` |
|
|
158
|
+
| `classInclude` | `string` | `''` | Không | Class CSS tùy chỉnh thêm vào thẻ `<div>` bọc ngoài cùng của component. | `classInclude: 'mx-auto'` |
|
|
159
|
+
|
|
160
|
+
## @Output()
|
|
161
|
+
|
|
162
|
+
Component này không phát ra Output event.
|
|
79
163
|
|
|
80
164
|
## Types & Interfaces
|
|
81
165
|
|
|
82
166
|
```typescript
|
|
167
|
+
import { IProcessBarCircleInterface } from '@libs-ui/components-process-bar-circle';
|
|
168
|
+
|
|
83
169
|
export interface IProcessBarCircleInterface {
|
|
84
|
-
/** Phần trăm hoàn thành (0-100) */
|
|
170
|
+
/** Phần trăm hoàn thành (0-100) — bắt buộc */
|
|
85
171
|
percent: number;
|
|
86
|
-
/** Kích thước
|
|
172
|
+
/** Kích thước vùng SVG (px), mặc định 100 */
|
|
87
173
|
size?: number;
|
|
88
|
-
/** Độ dày
|
|
174
|
+
/** Độ dày nét vẽ (px), mặc định 8 */
|
|
89
175
|
strokeWidth?: number;
|
|
90
|
-
/** Màu
|
|
176
|
+
/** Màu đường tiến trình, mặc định '#3b82f6' */
|
|
91
177
|
color?: string;
|
|
92
|
-
/** Màu nền
|
|
178
|
+
/** Màu nền vòng tròn, mặc định '#f1f5f9' */
|
|
93
179
|
backgroundColor?: string;
|
|
94
|
-
/**
|
|
180
|
+
/** Hiển thị nhãn phần trăm ở giữa, mặc định true */
|
|
95
181
|
showLabel?: boolean;
|
|
96
|
-
/** Class CSS
|
|
182
|
+
/** Class CSS bổ sung cho thẻ <span> nhãn phần trăm */
|
|
97
183
|
labelClass?: string;
|
|
98
|
-
/** Class CSS
|
|
184
|
+
/** Class CSS bổ sung cho thẻ <div> bọc ngoài cùng */
|
|
99
185
|
classInclude?: string;
|
|
100
186
|
}
|
|
101
187
|
```
|
|
102
188
|
|
|
103
|
-
##
|
|
189
|
+
## Lưu ý quan trọng
|
|
104
190
|
|
|
105
|
-
|
|
191
|
+
⚠️ **Tính toán SVG tự động**: Component tự tính `radius = (size - strokeWidth) / 2` và `center = size / 2`. Nếu `strokeWidth` quá lớn so với `size`, vòng tròn có thể bị tràn ra ngoài — hãy đảm bảo `strokeWidth < size / 2`.
|
|
106
192
|
|
|
107
|
-
|
|
193
|
+
⚠️ **Percent ngoài phạm vi**: Giá trị `percent` được tự động kẹp vào [0, 100] qua `Math.max(0, Math.min(100, percent))`. Không cần validate thủ công trước khi truyền vào.
|
|
108
194
|
|
|
109
|
-
|
|
195
|
+
⚠️ **labelClass ghi đè hoàn toàn**: Khi truyền `labelClass`, các class mặc định `text-sm font-semibold text-gray-700` vẫn còn nhưng `labelClass` được bind thêm qua `[class]`. Để thay thế hoàn toàn style chữ, hãy dùng `!important` hoặc class có specificity cao hơn.
|
|
110
196
|
|
|
111
|
-
|
|
197
|
+
⚠️ **SVG rotate**: Component áp dụng `class="transform -rotate-90"` lên thẻ `<svg>` để vòng tròn bắt đầu từ đỉnh (12 giờ) thay vì từ bên phải (3 giờ). Đây là hành vi mặc định, không thể tắt qua config.
|
|
112
198
|
|
|
113
|
-
##
|
|
199
|
+
## Hidden Logic
|
|
114
200
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
201
|
+
### 1. SVG Dash Array Calculation
|
|
202
|
+
|
|
203
|
+
Component tính `circumference = 2 * Math.PI * radius` để xác định chu vi đường tròn, sau đó đặt `stroke-dasharray = circumference` và điều chỉnh `stroke-dashoffset = circumference - (percent / 100) * circumference`. Khi `percent = 0`, `dashoffset = circumference` (ẩn toàn bộ nét vẽ). Khi `percent = 100`, `dashoffset = 0` (hiện toàn bộ vòng tròn).
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
circumference = 2 * Math.PI * ((size - strokeWidth) / 2)
|
|
207
|
+
offset = circumference - (percent / 100) * circumference
|
|
118
208
|
```
|
|
119
209
|
|
|
120
|
-
|
|
210
|
+
### 2. Dynamic Coordinate Handling
|
|
121
211
|
|
|
122
|
-
|
|
212
|
+
Tất cả thuộc tính SVG (`cx`, `cy`, `r`) được tính toán động bằng computed signals, đảm bảo vòng tròn luôn căn giữa chính xác dù `size` hay `strokeWidth` thay đổi runtime.
|
|
123
213
|
|
|
124
|
-
|
|
214
|
+
```
|
|
215
|
+
radius = (size - strokeWidth) / 2
|
|
216
|
+
center = size / 2
|
|
217
|
+
```
|
|
@@ -18,10 +18,10 @@ export class LibsUiComponentsProcessBarCircleComponent {
|
|
|
18
18
|
backgroundColor = computed(() => this.config().backgroundColor ?? '#f1f5f9');
|
|
19
19
|
showLabel = computed(() => this.config().showLabel ?? true);
|
|
20
20
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsProcessBarCircleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
21
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiComponentsProcessBarCircleComponent, isStandalone: true, selector: "libs_ui-components-process_bar-circle", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div\n [class]=\"config().classInclude\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n class=\"relative flex items-center justify-center\">\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n class=\"transform -rotate-90\">\n <!-- Background Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"backgroundColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\" />\n <!-- Progress Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"color()\"\n [attr.stroke-width]=\"strokeWidth()\"\n [attr.stroke-dasharray]=\"circumference()\"\n [attr.stroke-dashoffset]=\"offset()\"\n stroke-linecap=\"round\"\n fill=\"transparent\"\n class=\"transition-all duration-300 ease-in-out\" />\n </svg>\n\n <!-- Label -->\n @if (showLabel()) {\n <div class=\"absolute inset-0 flex items-center justify-center\">\n <span\n [class]=\"config().labelClass\"\n class=\"text-sm font-semibold text-gray-700\">\n {{ config().percent }}%\n </span>\n </div>\n }\n</div>\n",
|
|
21
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiComponentsProcessBarCircleComponent, isStandalone: true, selector: "libs_ui-components-process_bar-circle", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div\n [class]=\"config().classInclude\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n class=\"relative flex items-center justify-center\">\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n class=\"transform -rotate-90\">\n <!-- Background Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"backgroundColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\" />\n <!-- Progress Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"color()\"\n [attr.stroke-width]=\"strokeWidth()\"\n [attr.stroke-dasharray]=\"circumference()\"\n [attr.stroke-dashoffset]=\"offset()\"\n stroke-linecap=\"round\"\n fill=\"transparent\"\n class=\"transition-all duration-300 ease-in-out\" />\n </svg>\n\n <!-- Label -->\n @if (showLabel()) {\n <div class=\"absolute inset-0 flex items-center justify-center\">\n <span\n [class]=\"config().labelClass\"\n class=\"text-sm font-semibold text-gray-700\">\n {{ config().percent }}%\n </span>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
22
22
|
}
|
|
23
23
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsProcessBarCircleComponent, decorators: [{
|
|
24
24
|
type: Component,
|
|
25
25
|
args: [{ selector: 'libs_ui-components-process_bar-circle', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n [class]=\"config().classInclude\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n class=\"relative flex items-center justify-center\">\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n class=\"transform -rotate-90\">\n <!-- Background Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"backgroundColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\" />\n <!-- Progress Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"color()\"\n [attr.stroke-width]=\"strokeWidth()\"\n [attr.stroke-dasharray]=\"circumference()\"\n [attr.stroke-dashoffset]=\"offset()\"\n stroke-linecap=\"round\"\n fill=\"transparent\"\n class=\"transition-all duration-300 ease-in-out\" />\n </svg>\n\n <!-- Label -->\n @if (showLabel()) {\n <div class=\"absolute inset-0 flex items-center justify-center\">\n <span\n [class]=\"config().labelClass\"\n class=\"text-sm font-semibold text-gray-700\">\n {{ config().percent }}%\n </span>\n </div>\n }\n</div>\n" }]
|
|
26
26
|
}] });
|
|
27
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
27
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvY2Vzcy1iYXItY2lyY2xlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMtdWkvY29tcG9uZW50cy9wcm9jZXNzLWJhci9jaXJjbGUvc3JjL3Byb2Nlc3MtYmFyLWNpcmNsZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9saWJzLXVpL2NvbXBvbmVudHMvcHJvY2Vzcy1iYXIvY2lyY2xlL3NyYy9wcm9jZXNzLWJhci1jaXJjbGUuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxNQUFNLGVBQWUsQ0FBQzs7QUFXcEYsTUFBTSxPQUFPLHlDQUF5QztJQUNwRCxtQ0FBbUM7SUFDMUIsTUFBTSxHQUFHLEtBQUssQ0FBQyxRQUFRLEVBQThCLENBQUM7SUFFL0QsdUNBQXVDO0lBQzdCLElBQUksR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksSUFBSSxHQUFHLENBQUMsQ0FBQztJQUNqRCxXQUFXLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxXQUFXLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDN0QsTUFBTSxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNoRSxNQUFNLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN6QyxhQUFhLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQzVELE1BQU0sR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQy9CLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQzVELE9BQU8sSUFBSSxDQUFDLGFBQWEsRUFBRSxHQUFHLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUNqRSxDQUFDLENBQUMsQ0FBQztJQUVPLEtBQUssR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssSUFBSSxTQUFTLENBQUMsQ0FBQztJQUN6RCxlQUFlLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxlQUFlLElBQUksU0FBUyxDQUFDLENBQUM7SUFDN0UsU0FBUyxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQyxDQUFDO3dHQWpCM0QseUNBQXlDOzRGQUF6Qyx5Q0FBeUMsdU9DWnRELHN1Q0EwQ0EsMkNEbENZLFlBQVk7OzRGQUlYLHlDQUF5QztrQkFSckQsU0FBUzsrQkFFRSx1Q0FBdUMsY0FDckMsSUFBSSxXQUNQLENBQUMsWUFBWSxDQUFDLG1CQUVOLHVCQUF1QixDQUFDLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgY29tcHV0ZWQsIGlucHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBJUHJvY2Vzc0JhckNpcmNsZUludGVyZmFjZSB9IGZyb20gJy4vcHJvY2Vzcy1iYXItY2lyY2xlLmludGVyZmFjZSc7XG5cbkBDb21wb25lbnQoe1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQGFuZ3VsYXItZXNsaW50L2NvbXBvbmVudC1zZWxlY3RvclxuICBzZWxlY3RvcjogJ2xpYnNfdWktY29tcG9uZW50cy1wcm9jZXNzX2Jhci1jaXJjbGUnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXSxcbiAgdGVtcGxhdGVVcmw6ICcuL3Byb2Nlc3MtYmFyLWNpcmNsZS5jb21wb25lbnQuaHRtbCcsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBMaWJzVWlDb21wb25lbnRzUHJvY2Vzc0JhckNpcmNsZUNvbXBvbmVudCB7XG4gIC8qKiBD4bqldSBow6xuaCBjaG8gdsOybmcgdGnhur9uIHRyw6xuaCAqL1xuICByZWFkb25seSBjb25maWcgPSBpbnB1dC5yZXF1aXJlZDxJUHJvY2Vzc0JhckNpcmNsZUludGVyZmFjZT4oKTtcblxuICAvLyBDb21wdXRlZCB2YWx1ZXMgZm9yIFNWRyBjYWxjdWxhdGlvbnNcbiAgcHJvdGVjdGVkIHNpemUgPSBjb21wdXRlZCgoKSA9PiB0aGlzLmNvbmZpZygpLnNpemUgPz8gMTAwKTtcbiAgcHJvdGVjdGVkIHN0cm9rZVdpZHRoID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5jb25maWcoKS5zdHJva2VXaWR0aCA/PyA4KTtcbiAgcHJvdGVjdGVkIHJhZGl1cyA9IGNvbXB1dGVkKCgpID0+ICh0aGlzLnNpemUoKSAtIHRoaXMuc3Ryb2tlV2lkdGgoKSkgLyAyKTtcbiAgcHJvdGVjdGVkIGNlbnRlciA9IGNvbXB1dGVkKCgpID0+IHRoaXMuc2l6ZSgpIC8gMik7XG4gIHByb3RlY3RlZCBjaXJjdW1mZXJlbmNlID0gY29tcHV0ZWQoKCkgPT4gMiAqIE1hdGguUEkgKiB0aGlzLnJhZGl1cygpKTtcbiAgcHJvdGVjdGVkIG9mZnNldCA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBjb25zdCBwID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oMTAwLCB0aGlzLmNvbmZpZygpLnBlcmNlbnQpKTtcbiAgICByZXR1cm4gdGhpcy5jaXJjdW1mZXJlbmNlKCkgLSAocCAvIDEwMCkgKiB0aGlzLmNpcmN1bWZlcmVuY2UoKTtcbiAgfSk7XG5cbiAgcHJvdGVjdGVkIGNvbG9yID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5jb25maWcoKS5jb2xvciA/PyAnIzNiODJmNicpO1xuICBwcm90ZWN0ZWQgYmFja2dyb3VuZENvbG9yID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5jb25maWcoKS5iYWNrZ3JvdW5kQ29sb3IgPz8gJyNmMWY1ZjknKTtcbiAgcHJvdGVjdGVkIHNob3dMYWJlbCA9IGNvbXB1dGVkKCgpID0+IHRoaXMuY29uZmlnKCkuc2hvd0xhYmVsID8/IHRydWUpO1xufVxuIiwiPGRpdlxuICBbY2xhc3NdPVwiY29uZmlnKCkuY2xhc3NJbmNsdWRlXCJcbiAgW3N0eWxlLndpZHRoLnB4XT1cInNpemUoKVwiXG4gIFtzdHlsZS5oZWlnaHQucHhdPVwic2l6ZSgpXCJcbiAgY2xhc3M9XCJyZWxhdGl2ZSBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlclwiPlxuICA8c3ZnXG4gICAgW2F0dHIud2lkdGhdPVwic2l6ZSgpXCJcbiAgICBbYXR0ci5oZWlnaHRdPVwic2l6ZSgpXCJcbiAgICBjbGFzcz1cInRyYW5zZm9ybSAtcm90YXRlLTkwXCI+XG4gICAgPCEtLSBCYWNrZ3JvdW5kIENpcmNsZSAtLT5cbiAgICA8Y2lyY2xlXG4gICAgICBbYXR0ci5jeF09XCJjZW50ZXIoKVwiXG4gICAgICBbYXR0ci5jeV09XCJjZW50ZXIoKVwiXG4gICAgICBbYXR0ci5yXT1cInJhZGl1cygpXCJcbiAgICAgIFthdHRyLnN0cm9rZV09XCJiYWNrZ3JvdW5kQ29sb3IoKVwiXG4gICAgICBbYXR0ci5zdHJva2Utd2lkdGhdPVwic3Ryb2tlV2lkdGgoKVwiXG4gICAgICBmaWxsPVwidHJhbnNwYXJlbnRcIiAvPlxuICAgIDwhLS0gUHJvZ3Jlc3MgQ2lyY2xlIC0tPlxuICAgIDxjaXJjbGVcbiAgICAgIFthdHRyLmN4XT1cImNlbnRlcigpXCJcbiAgICAgIFthdHRyLmN5XT1cImNlbnRlcigpXCJcbiAgICAgIFthdHRyLnJdPVwicmFkaXVzKClcIlxuICAgICAgW2F0dHIuc3Ryb2tlXT1cImNvbG9yKClcIlxuICAgICAgW2F0dHIuc3Ryb2tlLXdpZHRoXT1cInN0cm9rZVdpZHRoKClcIlxuICAgICAgW2F0dHIuc3Ryb2tlLWRhc2hhcnJheV09XCJjaXJjdW1mZXJlbmNlKClcIlxuICAgICAgW2F0dHIuc3Ryb2tlLWRhc2hvZmZzZXRdPVwib2Zmc2V0KClcIlxuICAgICAgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiXG4gICAgICBmaWxsPVwidHJhbnNwYXJlbnRcIlxuICAgICAgY2xhc3M9XCJ0cmFuc2l0aW9uLWFsbCBkdXJhdGlvbi0zMDAgZWFzZS1pbi1vdXRcIiAvPlxuICA8L3N2Zz5cblxuICA8IS0tIExhYmVsIC0tPlxuICBAaWYgKHNob3dMYWJlbCgpKSB7XG4gICAgPGRpdiBjbGFzcz1cImFic29sdXRlIGluc2V0LTAgZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXJcIj5cbiAgICAgIDxzcGFuXG4gICAgICAgIFtjbGFzc109XCJjb25maWcoKS5sYWJlbENsYXNzXCJcbiAgICAgICAgY2xhc3M9XCJ0ZXh0LXNtIGZvbnQtc2VtaWJvbGQgdGV4dC1ncmF5LTcwMFwiPlxuICAgICAgICB7eyBjb25maWcoKS5wZXJjZW50IH19JVxuICAgICAgPC9zcGFuPlxuICAgIDwvZGl2PlxuICB9XG48L2Rpdj5cbiJdfQ==
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CommonModule } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { input, computed,
|
|
3
|
+
import { input, computed, Component, ChangeDetectionStrategy } from '@angular/core';
|
|
4
4
|
|
|
5
5
|
class LibsUiComponentsProcessBarCircleComponent {
|
|
6
6
|
/** Cấu hình cho vòng tiến trình */
|
|
@@ -19,7 +19,7 @@ class LibsUiComponentsProcessBarCircleComponent {
|
|
|
19
19
|
backgroundColor = computed(() => this.config().backgroundColor ?? '#f1f5f9');
|
|
20
20
|
showLabel = computed(() => this.config().showLabel ?? true);
|
|
21
21
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsProcessBarCircleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
22
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiComponentsProcessBarCircleComponent, isStandalone: true, selector: "libs_ui-components-process_bar-circle", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div\n [class]=\"config().classInclude\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n class=\"relative flex items-center justify-center\">\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n class=\"transform -rotate-90\">\n <!-- Background Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"backgroundColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\" />\n <!-- Progress Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"color()\"\n [attr.stroke-width]=\"strokeWidth()\"\n [attr.stroke-dasharray]=\"circumference()\"\n [attr.stroke-dashoffset]=\"offset()\"\n stroke-linecap=\"round\"\n fill=\"transparent\"\n class=\"transition-all duration-300 ease-in-out\" />\n </svg>\n\n <!-- Label -->\n @if (showLabel()) {\n <div class=\"absolute inset-0 flex items-center justify-center\">\n <span\n [class]=\"config().labelClass\"\n class=\"text-sm font-semibold text-gray-700\">\n {{ config().percent }}%\n </span>\n </div>\n }\n</div>\n",
|
|
22
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiComponentsProcessBarCircleComponent, isStandalone: true, selector: "libs_ui-components-process_bar-circle", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div\n [class]=\"config().classInclude\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n class=\"relative flex items-center justify-center\">\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n class=\"transform -rotate-90\">\n <!-- Background Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"backgroundColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\" />\n <!-- Progress Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"color()\"\n [attr.stroke-width]=\"strokeWidth()\"\n [attr.stroke-dasharray]=\"circumference()\"\n [attr.stroke-dashoffset]=\"offset()\"\n stroke-linecap=\"round\"\n fill=\"transparent\"\n class=\"transition-all duration-300 ease-in-out\" />\n </svg>\n\n <!-- Label -->\n @if (showLabel()) {\n <div class=\"absolute inset-0 flex items-center justify-center\">\n <span\n [class]=\"config().labelClass\"\n class=\"text-sm font-semibold text-gray-700\">\n {{ config().percent }}%\n </span>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
23
23
|
}
|
|
24
24
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsProcessBarCircleComponent, decorators: [{
|
|
25
25
|
type: Component,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"libs-ui-components-process-bar-circle.mjs","sources":["../../../../../../libs-ui/components/process-bar/circle/src/process-bar-circle.component.ts","../../../../../../libs-ui/components/process-bar/circle/src/process-bar-circle.component.html","../../../../../../libs-ui/components/process-bar/circle/src/libs-ui-components-process-bar-circle.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { IProcessBarCircleInterface } from './process-bar-circle.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-process_bar-circle',\n standalone: true,\n imports: [CommonModule],\n templateUrl: './process-bar-circle.component.html',\n
|
|
1
|
+
{"version":3,"file":"libs-ui-components-process-bar-circle.mjs","sources":["../../../../../../libs-ui/components/process-bar/circle/src/process-bar-circle.component.ts","../../../../../../libs-ui/components/process-bar/circle/src/process-bar-circle.component.html","../../../../../../libs-ui/components/process-bar/circle/src/libs-ui-components-process-bar-circle.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { IProcessBarCircleInterface } from './process-bar-circle.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-process_bar-circle',\n standalone: true,\n imports: [CommonModule],\n templateUrl: './process-bar-circle.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LibsUiComponentsProcessBarCircleComponent {\n /** Cấu hình cho vòng tiến trình */\n readonly config = input.required<IProcessBarCircleInterface>();\n\n // Computed values for SVG calculations\n protected size = computed(() => this.config().size ?? 100);\n protected strokeWidth = computed(() => this.config().strokeWidth ?? 8);\n protected radius = computed(() => (this.size() - this.strokeWidth()) / 2);\n protected center = computed(() => this.size() / 2);\n protected circumference = computed(() => 2 * Math.PI * this.radius());\n protected offset = computed(() => {\n const p = Math.max(0, Math.min(100, this.config().percent));\n return this.circumference() - (p / 100) * this.circumference();\n });\n\n protected color = computed(() => this.config().color ?? '#3b82f6');\n protected backgroundColor = computed(() => this.config().backgroundColor ?? '#f1f5f9');\n protected showLabel = computed(() => this.config().showLabel ?? true);\n}\n","<div\n [class]=\"config().classInclude\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n class=\"relative flex items-center justify-center\">\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n class=\"transform -rotate-90\">\n <!-- Background Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"backgroundColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\" />\n <!-- Progress Circle -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"radius()\"\n [attr.stroke]=\"color()\"\n [attr.stroke-width]=\"strokeWidth()\"\n [attr.stroke-dasharray]=\"circumference()\"\n [attr.stroke-dashoffset]=\"offset()\"\n stroke-linecap=\"round\"\n fill=\"transparent\"\n class=\"transition-all duration-300 ease-in-out\" />\n </svg>\n\n <!-- Label -->\n @if (showLabel()) {\n <div class=\"absolute inset-0 flex items-center justify-center\">\n <span\n [class]=\"config().labelClass\"\n class=\"text-sm font-semibold text-gray-700\">\n {{ config().percent }}%\n </span>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;MAYa,yCAAyC,CAAA;;AAE3C,IAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,EAA8B,CAAC;;AAGrD,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;AACjD,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAC7D,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;AAChE,IAAA,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;AACzC,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC5D,IAAA,MAAM,GAAG,QAAQ,CAAC,MAAK;QAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5D,QAAA,OAAO,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;AACjE,KAAC,CAAC,CAAC;AAEO,IAAA,KAAK,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC;AACzD,IAAA,eAAe,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,eAAe,IAAI,SAAS,CAAC,CAAC;AAC7E,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;wGAjB3D,yCAAyC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;4FAAzC,yCAAyC,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uCAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECZtD,suCA0CA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDlCY,YAAY,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAIX,yCAAyC,EAAA,UAAA,EAAA,CAAA;kBARrD,SAAS;+BAEE,uCAAuC,EAAA,UAAA,EACrC,IAAI,EACP,OAAA,EAAA,CAAC,YAAY,CAAC,EAAA,eAAA,EAEN,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,suCAAA,EAAA,CAAA;;;AEVjD;;AAEG;;;;"}
|