virtual-ui-lib 1.0.71 → 1.0.73
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 +247 -108
- package/dist/index.js +338 -2
- package/dist/index.mjs +335 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Virtual UI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A modern and customizable **React UI Component Library** designed for fast development and clean design systems.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## Install
|
|
7
|
+
## 📦 Install
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npm install virtual-ui-lib
|
|
@@ -12,209 +12,348 @@ npm install virtual-ui-lib
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
## Usage
|
|
15
|
+
## 🚀 Usage
|
|
16
16
|
|
|
17
17
|
```jsx
|
|
18
18
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Spinner,
|
|
26
|
-
Modal
|
|
19
|
+
Navbar,
|
|
20
|
+
Sidebar,
|
|
21
|
+
AvatarCard,
|
|
22
|
+
PricingCard,
|
|
23
|
+
Loader,
|
|
24
|
+
OTPInput
|
|
27
25
|
} from "virtual-ui-lib"
|
|
28
26
|
|
|
29
27
|
function App() {
|
|
30
28
|
return (
|
|
31
29
|
<>
|
|
32
|
-
<
|
|
30
|
+
<Navbar />
|
|
31
|
+
<Sidebar />
|
|
32
|
+
|
|
33
|
+
<div style={{ padding: "20px" }}>
|
|
34
|
+
<AvatarCard />
|
|
35
|
+
<PricingCard />
|
|
36
|
+
<OTPInput />
|
|
37
|
+
<Loader />
|
|
38
|
+
</div>
|
|
39
|
+
</>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
# 🧩 Components
|
|
47
|
+
|
|
48
|
+
Virtual UI includes the following components:
|
|
49
|
+
|
|
50
|
+
* AvatarCard
|
|
51
|
+
* BackgroundImageSlider
|
|
52
|
+
* Charts
|
|
53
|
+
* ColorPicker
|
|
54
|
+
* FileUpload
|
|
55
|
+
* Footer
|
|
56
|
+
* ImageCard
|
|
57
|
+
* ImageSlider
|
|
58
|
+
* InvoiceCard
|
|
59
|
+
* Loader
|
|
60
|
+
* Navbar
|
|
61
|
+
* NotificationToast
|
|
62
|
+
* OTPInput
|
|
63
|
+
* PageLoader
|
|
64
|
+
* PricingCard
|
|
65
|
+
* RatingStars
|
|
66
|
+
* Sidebar
|
|
37
67
|
|
|
38
|
-
|
|
68
|
+
---
|
|
39
69
|
|
|
40
|
-
|
|
70
|
+
# 📘 Component Details
|
|
41
71
|
|
|
42
|
-
|
|
72
|
+
---
|
|
43
73
|
|
|
44
|
-
|
|
74
|
+
## AvatarCard
|
|
45
75
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
)
|
|
49
|
-
}
|
|
76
|
+
```jsx
|
|
77
|
+
<AvatarCard />
|
|
50
78
|
```
|
|
51
79
|
|
|
80
|
+
### Props
|
|
81
|
+
|
|
82
|
+
| Prop | Description |
|
|
83
|
+
| ----- | ------------ |
|
|
84
|
+
| name | User name |
|
|
85
|
+
| image | Avatar image |
|
|
86
|
+
| role | User role |
|
|
87
|
+
| size | Card size |
|
|
88
|
+
|
|
52
89
|
---
|
|
53
90
|
|
|
54
|
-
|
|
91
|
+
## Navbar
|
|
92
|
+
|
|
93
|
+
```jsx
|
|
94
|
+
<Navbar />
|
|
95
|
+
```
|
|
55
96
|
|
|
56
|
-
|
|
97
|
+
### Props
|
|
57
98
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
* Avatar
|
|
64
|
-
* Spinner
|
|
65
|
-
* Modal
|
|
99
|
+
| Prop | Description |
|
|
100
|
+
| ----- | ---------------- |
|
|
101
|
+
| logo | Logo text/image |
|
|
102
|
+
| links | Navigation links |
|
|
103
|
+
| fixed | Sticky navbar |
|
|
66
104
|
|
|
67
105
|
---
|
|
68
106
|
|
|
69
|
-
|
|
107
|
+
## Sidebar
|
|
70
108
|
|
|
71
109
|
```jsx
|
|
72
|
-
<
|
|
110
|
+
<Sidebar />
|
|
73
111
|
```
|
|
74
112
|
|
|
75
113
|
### Props
|
|
76
114
|
|
|
77
|
-
| Prop
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
| color | Text color |
|
|
82
|
-
| size | sm / md / lg |
|
|
83
|
-
| width | Button width |
|
|
84
|
-
| radius | Border radius |
|
|
85
|
-
| shadow | Box shadow |
|
|
86
|
-
| disabled | Disable button |
|
|
87
|
-
| icon | Add icon |
|
|
115
|
+
| Prop | Description |
|
|
116
|
+
| --------- | -------------- |
|
|
117
|
+
| items | Sidebar items |
|
|
118
|
+
| collapsed | Collapse state |
|
|
88
119
|
|
|
89
120
|
---
|
|
90
121
|
|
|
91
|
-
|
|
122
|
+
## PricingCard
|
|
92
123
|
|
|
93
124
|
```jsx
|
|
94
|
-
<
|
|
125
|
+
<PricingCard />
|
|
95
126
|
```
|
|
96
127
|
|
|
97
128
|
### Props
|
|
98
129
|
|
|
99
|
-
| Prop
|
|
100
|
-
|
|
|
101
|
-
| title
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
| shadow | Box shadow |
|
|
106
|
-
| children | Extra content inside card |
|
|
130
|
+
| Prop | Description |
|
|
131
|
+
| ----------- | ---------------- |
|
|
132
|
+
| title | Plan name |
|
|
133
|
+
| price | Plan price |
|
|
134
|
+
| features | List of features |
|
|
135
|
+
| highlighted | Highlight plan |
|
|
107
136
|
|
|
108
137
|
---
|
|
109
138
|
|
|
110
|
-
|
|
139
|
+
## OTPInput
|
|
111
140
|
|
|
112
141
|
```jsx
|
|
113
|
-
<
|
|
142
|
+
<OTPInput length={6} />
|
|
114
143
|
```
|
|
115
144
|
|
|
116
145
|
### Props
|
|
117
146
|
|
|
118
|
-
| Prop
|
|
119
|
-
|
|
|
120
|
-
|
|
|
121
|
-
|
|
|
122
|
-
| radius | Border radius |
|
|
123
|
-
| shadow | Box shadow |
|
|
124
|
-
| value | Input value |
|
|
125
|
-
| onChange | Input change handler |
|
|
147
|
+
| Prop | Description |
|
|
148
|
+
| -------- | ------------------ |
|
|
149
|
+
| length | Number of digits |
|
|
150
|
+
| onChange | OTP change handler |
|
|
126
151
|
|
|
127
152
|
---
|
|
128
153
|
|
|
129
|
-
|
|
154
|
+
## Loader
|
|
130
155
|
|
|
131
156
|
```jsx
|
|
132
|
-
<
|
|
157
|
+
<Loader />
|
|
133
158
|
```
|
|
134
159
|
|
|
135
160
|
### Props
|
|
136
161
|
|
|
137
|
-
| Prop | Description
|
|
138
|
-
| ----- |
|
|
139
|
-
|
|
|
140
|
-
|
|
|
141
|
-
| color | Text color |
|
|
162
|
+
| Prop | Description |
|
|
163
|
+
| ----- | ------------ |
|
|
164
|
+
| size | Loader size |
|
|
165
|
+
| color | Loader color |
|
|
142
166
|
|
|
143
167
|
---
|
|
144
168
|
|
|
145
|
-
|
|
169
|
+
## NotificationToast
|
|
146
170
|
|
|
147
171
|
```jsx
|
|
148
|
-
<
|
|
172
|
+
<NotificationToast message="Saved!" />
|
|
149
173
|
```
|
|
150
174
|
|
|
151
175
|
### Props
|
|
152
176
|
|
|
153
|
-
| Prop
|
|
154
|
-
|
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
|
|
177
|
+
| Prop | Description |
|
|
178
|
+
| ------- | ---------------------- |
|
|
179
|
+
| message | Toast text |
|
|
180
|
+
| type | success / error / info |
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Charts
|
|
185
|
+
|
|
186
|
+
```jsx
|
|
187
|
+
<Charts />
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Props
|
|
191
|
+
|
|
192
|
+
| Prop | Description |
|
|
193
|
+
| ---- | ---------------- |
|
|
194
|
+
| type | bar / line / pie |
|
|
195
|
+
| data | Chart data |
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## ColorPicker
|
|
200
|
+
|
|
201
|
+
```jsx
|
|
202
|
+
<ColorPicker />
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Props
|
|
206
|
+
|
|
207
|
+
| Prop | Description |
|
|
208
|
+
| -------- | -------------- |
|
|
209
|
+
| value | Selected color |
|
|
210
|
+
| onChange | Change handler |
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## FileUpload
|
|
215
|
+
|
|
216
|
+
```jsx
|
|
217
|
+
<FileUpload />
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Props
|
|
221
|
+
|
|
222
|
+
| Prop | Description |
|
|
223
|
+
| -------- | -------------------- |
|
|
224
|
+
| onUpload | Upload handler |
|
|
225
|
+
| multiple | Allow multiple files |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## ImageCard
|
|
230
|
+
|
|
231
|
+
```jsx
|
|
232
|
+
<ImageCard />
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Props
|
|
236
|
+
|
|
237
|
+
| Prop | Description |
|
|
238
|
+
| ----- | ------------ |
|
|
239
|
+
| src | Image source |
|
|
240
|
+
| title | Image title |
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## ImageSlider
|
|
245
|
+
|
|
246
|
+
```jsx
|
|
247
|
+
<ImageSlider />
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Props
|
|
251
|
+
|
|
252
|
+
| Prop | Description |
|
|
253
|
+
| -------- | ----------- |
|
|
254
|
+
| images | Image array |
|
|
255
|
+
| autoPlay | Auto slide |
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## BackgroundImageSlider
|
|
260
|
+
|
|
261
|
+
```jsx
|
|
262
|
+
<BackgroundImageSlider />
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Props
|
|
266
|
+
|
|
267
|
+
| Prop | Description |
|
|
268
|
+
| ------- | ----------------- |
|
|
269
|
+
| images | Background images |
|
|
270
|
+
| overlay | Overlay color |
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## InvoiceCard
|
|
275
|
+
|
|
276
|
+
```jsx
|
|
277
|
+
<InvoiceCard />
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Props
|
|
281
|
+
|
|
282
|
+
| Prop | Description |
|
|
283
|
+
| --------- | -------------- |
|
|
284
|
+
| invoiceId | Invoice ID |
|
|
285
|
+
| amount | Amount |
|
|
286
|
+
| status | Paid / Pending |
|
|
158
287
|
|
|
159
288
|
---
|
|
160
289
|
|
|
161
|
-
|
|
290
|
+
## RatingStars
|
|
162
291
|
|
|
163
292
|
```jsx
|
|
164
|
-
<
|
|
293
|
+
<RatingStars rating={4} />
|
|
165
294
|
```
|
|
166
295
|
|
|
167
296
|
### Props
|
|
168
297
|
|
|
169
|
-
| Prop
|
|
170
|
-
|
|
|
171
|
-
|
|
|
172
|
-
|
|
|
173
|
-
| radius | Border radius |
|
|
298
|
+
| Prop | Description |
|
|
299
|
+
| -------- | --------------- |
|
|
300
|
+
| rating | Number of stars |
|
|
301
|
+
| onChange | Change handler |
|
|
174
302
|
|
|
175
303
|
---
|
|
176
304
|
|
|
177
|
-
|
|
305
|
+
## PageLoader
|
|
178
306
|
|
|
179
307
|
```jsx
|
|
180
|
-
<
|
|
308
|
+
<PageLoader />
|
|
181
309
|
```
|
|
182
310
|
|
|
183
311
|
### Props
|
|
184
312
|
|
|
185
|
-
| Prop
|
|
186
|
-
|
|
|
187
|
-
|
|
|
188
|
-
| color | Spinner color |
|
|
189
|
-
| border | Border width |
|
|
313
|
+
| Prop | Description |
|
|
314
|
+
| ---------- | ---------------- |
|
|
315
|
+
| fullScreen | Full page loader |
|
|
190
316
|
|
|
191
317
|
---
|
|
192
318
|
|
|
193
|
-
|
|
319
|
+
## Footer
|
|
194
320
|
|
|
195
321
|
```jsx
|
|
196
|
-
<
|
|
197
|
-
Hello Modal
|
|
198
|
-
</Modal>
|
|
322
|
+
<Footer />
|
|
199
323
|
```
|
|
200
324
|
|
|
201
325
|
### Props
|
|
202
326
|
|
|
203
|
-
| Prop
|
|
204
|
-
|
|
|
205
|
-
|
|
|
206
|
-
|
|
|
207
|
-
|
|
208
|
-
|
|
327
|
+
| Prop | Description |
|
|
328
|
+
| ----- | ------------ |
|
|
329
|
+
| text | Footer text |
|
|
330
|
+
| links | Footer links |
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
# 🤝 Contributing
|
|
335
|
+
|
|
336
|
+
Contributions are welcome!
|
|
337
|
+
|
|
338
|
+
* Fork the repo
|
|
339
|
+
* Create a new branch
|
|
340
|
+
* Submit a pull request
|
|
209
341
|
|
|
210
342
|
---
|
|
211
343
|
|
|
212
|
-
#
|
|
344
|
+
# 📄 License
|
|
213
345
|
|
|
214
|
-
|
|
346
|
+
MIT License
|
|
215
347
|
|
|
216
348
|
---
|
|
217
349
|
|
|
218
|
-
#
|
|
350
|
+
# 💡 Future Improvements
|
|
351
|
+
|
|
352
|
+
* Theme system (dark/light mode)
|
|
353
|
+
* Animation presets
|
|
354
|
+
* Accessibility improvements
|
|
355
|
+
* More enterprise components
|
|
356
|
+
|
|
357
|
+
---
|
|
219
358
|
|
|
220
|
-
|
|
359
|
+
Made with ❤️ for developers
|
package/dist/index.js
CHANGED
|
@@ -44,7 +44,9 @@ __export(index_exports, {
|
|
|
44
44
|
OTPInput: () => OTPInput,
|
|
45
45
|
PageLoader: () => PageLoader,
|
|
46
46
|
PricingCard: () => PricingCard,
|
|
47
|
-
|
|
47
|
+
RatingStars: () => RatingStars,
|
|
48
|
+
Sidebar: () => Sidebar,
|
|
49
|
+
StatCard: () => StatCard
|
|
48
50
|
});
|
|
49
51
|
module.exports = __toCommonJS(index_exports);
|
|
50
52
|
|
|
@@ -2993,6 +2995,338 @@ var ColorPicker = ({
|
|
|
2993
2995
|
alignItems: "center"
|
|
2994
2996
|
} }, /* @__PURE__ */ import_react16.default.createElement("span", { style: { fontSize: "10px", color: "rgba(255,255,255,0.25)", fontWeight: "600", textTransform: "uppercase", letterSpacing: "0.5px" } }, "RGBA"), /* @__PURE__ */ import_react16.default.createElement("span", { style: { fontSize: "10px", fontFamily: "monospace", color: "rgba(255,255,255,0.5)" } }, alpha(color, opacity / 100))));
|
|
2995
2997
|
};
|
|
2998
|
+
|
|
2999
|
+
// src/components/RatingStars/RatingStars.jsx
|
|
3000
|
+
var import_react17 = __toESM(require("react"));
|
|
3001
|
+
var RatingStars = ({
|
|
3002
|
+
defaultRating = 0,
|
|
3003
|
+
total = 5,
|
|
3004
|
+
size = 32,
|
|
3005
|
+
allowHalf = true,
|
|
3006
|
+
showLabel = true,
|
|
3007
|
+
showCount = true,
|
|
3008
|
+
reviewCount = 0,
|
|
3009
|
+
readOnly = false,
|
|
3010
|
+
accent = "#f59e0b",
|
|
3011
|
+
bg = "#0f172a",
|
|
3012
|
+
radius = "14px",
|
|
3013
|
+
onChange = () => {
|
|
3014
|
+
}
|
|
3015
|
+
}) => {
|
|
3016
|
+
const [rating, setRating] = (0, import_react17.useState)(defaultRating);
|
|
3017
|
+
const [hovered, setHovered] = (0, import_react17.useState)(0);
|
|
3018
|
+
const labels = ["", "Terrible", "Bad", "Okay", "Good", "Excellent"];
|
|
3019
|
+
const halfLabels = { 0.5: "Awful", 1: "Terrible", 1.5: "Very Bad", 2: "Bad", 2.5: "Below Average", 3: "Okay", 3.5: "Above Average", 4: "Good", 4.5: "Great", 5: "Excellent" };
|
|
3020
|
+
const alpha = (hex, op) => {
|
|
3021
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
3022
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
3023
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
3024
|
+
return `rgba(${r},${g},${b},${op})`;
|
|
3025
|
+
};
|
|
3026
|
+
const active = hovered || rating;
|
|
3027
|
+
const handleMouseMove = (e, i) => {
|
|
3028
|
+
if (readOnly) return;
|
|
3029
|
+
if (allowHalf) {
|
|
3030
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
3031
|
+
const half = e.clientX - rect.left < rect.width / 2;
|
|
3032
|
+
setHovered(half ? i - 0.5 : i);
|
|
3033
|
+
} else {
|
|
3034
|
+
setHovered(i);
|
|
3035
|
+
}
|
|
3036
|
+
};
|
|
3037
|
+
const handleClick = (e, i) => {
|
|
3038
|
+
if (readOnly) return;
|
|
3039
|
+
let val;
|
|
3040
|
+
if (allowHalf) {
|
|
3041
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
3042
|
+
val = e.clientX - rect.left < rect.width / 2 ? i - 0.5 : i;
|
|
3043
|
+
} else {
|
|
3044
|
+
val = i;
|
|
3045
|
+
}
|
|
3046
|
+
setRating(val);
|
|
3047
|
+
onChange(val);
|
|
3048
|
+
};
|
|
3049
|
+
const StarIcon = ({ index }) => {
|
|
3050
|
+
const fill = active >= index ? "full" : active >= index - 0.5 ? "half" : "empty";
|
|
3051
|
+
const id = `half-${index}`;
|
|
3052
|
+
return /* @__PURE__ */ import_react17.default.createElement(
|
|
3053
|
+
"svg",
|
|
3054
|
+
{
|
|
3055
|
+
width: size,
|
|
3056
|
+
height: size,
|
|
3057
|
+
viewBox: "0 0 24 24",
|
|
3058
|
+
style: { cursor: readOnly ? "default" : "pointer", transition: "transform 0.1s", flexShrink: 0 },
|
|
3059
|
+
onMouseMove: (e) => handleMouseMove(e, index),
|
|
3060
|
+
onMouseLeave: () => !readOnly && setHovered(0),
|
|
3061
|
+
onClick: (e) => handleClick(e, index),
|
|
3062
|
+
onMouseEnter: (e) => {
|
|
3063
|
+
if (!readOnly) e.currentTarget.style.transform = "scale(1.15)";
|
|
3064
|
+
}
|
|
3065
|
+
},
|
|
3066
|
+
/* @__PURE__ */ import_react17.default.createElement("defs", null, /* @__PURE__ */ import_react17.default.createElement("linearGradient", { id }, /* @__PURE__ */ import_react17.default.createElement("stop", { offset: "50%", stopColor: accent }), /* @__PURE__ */ import_react17.default.createElement("stop", { offset: "50%", stopColor: "transparent" }))),
|
|
3067
|
+
/* @__PURE__ */ import_react17.default.createElement(
|
|
3068
|
+
"polygon",
|
|
3069
|
+
{
|
|
3070
|
+
points: "12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26",
|
|
3071
|
+
fill: fill === "full" ? accent : fill === "half" ? `url(#${id})` : "transparent",
|
|
3072
|
+
stroke: fill === "empty" ? "rgba(255,255,255,0.15)" : accent,
|
|
3073
|
+
strokeWidth: "1.5"
|
|
3074
|
+
}
|
|
3075
|
+
)
|
|
3076
|
+
);
|
|
3077
|
+
};
|
|
3078
|
+
return /* @__PURE__ */ import_react17.default.createElement("div", { style: {
|
|
3079
|
+
background: bg,
|
|
3080
|
+
borderRadius: radius,
|
|
3081
|
+
padding: "20px 22px",
|
|
3082
|
+
display: "inline-flex",
|
|
3083
|
+
flexDirection: "column",
|
|
3084
|
+
alignItems: "center",
|
|
3085
|
+
gap: "12px",
|
|
3086
|
+
fontFamily: "system-ui, sans-serif",
|
|
3087
|
+
border: "1px solid rgba(255,255,255,0.07)",
|
|
3088
|
+
boxShadow: "0 10px 40px rgba(0,0,0,0.4)"
|
|
3089
|
+
} }, /* @__PURE__ */ import_react17.default.createElement("div", { style: { display: "flex", gap: "4px", alignItems: "center" } }, Array.from({ length: total }, (_, i) => /* @__PURE__ */ import_react17.default.createElement(StarIcon, { key: i + 1, index: i + 1 }))), showLabel && /* @__PURE__ */ import_react17.default.createElement("div", { style: {
|
|
3090
|
+
fontSize: "14px",
|
|
3091
|
+
fontWeight: "700",
|
|
3092
|
+
minHeight: "20px",
|
|
3093
|
+
color: active > 0 ? accent : "rgba(255,255,255,0.2)",
|
|
3094
|
+
transition: "color 0.2s"
|
|
3095
|
+
} }, active > 0 ? allowHalf ? halfLabels[active] : labels[Math.round(active)] : readOnly ? "Not rated" : "Rate this"), (rating > 0 || readOnly) && showCount && /* @__PURE__ */ import_react17.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ import_react17.default.createElement("span", { style: {
|
|
3096
|
+
fontSize: "28px",
|
|
3097
|
+
fontWeight: "800",
|
|
3098
|
+
color: "#fff",
|
|
3099
|
+
lineHeight: 1
|
|
3100
|
+
} }, rating.toFixed(1)), /* @__PURE__ */ import_react17.default.createElement("div", null, /* @__PURE__ */ import_react17.default.createElement("div", { style: { display: "flex", gap: "1px", marginBottom: "3px" } }, Array.from({ length: total }, (_, i) => {
|
|
3101
|
+
const fill = rating >= i + 1 ? "full" : rating >= i + 0.5 ? "half" : "empty";
|
|
3102
|
+
const gid = `sm-${i}`;
|
|
3103
|
+
return /* @__PURE__ */ import_react17.default.createElement("svg", { key: i, width: "12", height: "12", viewBox: "0 0 24 24" }, /* @__PURE__ */ import_react17.default.createElement("defs", null, /* @__PURE__ */ import_react17.default.createElement("linearGradient", { id: gid }, /* @__PURE__ */ import_react17.default.createElement("stop", { offset: "50%", stopColor: accent }), /* @__PURE__ */ import_react17.default.createElement("stop", { offset: "50%", stopColor: "transparent" }))), /* @__PURE__ */ import_react17.default.createElement(
|
|
3104
|
+
"polygon",
|
|
3105
|
+
{
|
|
3106
|
+
points: "12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26",
|
|
3107
|
+
fill: fill === "full" ? accent : fill === "half" ? `url(#${gid})` : "transparent",
|
|
3108
|
+
stroke: fill === "empty" ? "rgba(255,255,255,0.15)" : accent,
|
|
3109
|
+
strokeWidth: "1.5"
|
|
3110
|
+
}
|
|
3111
|
+
));
|
|
3112
|
+
})), reviewCount > 0 && /* @__PURE__ */ import_react17.default.createElement("span", { style: { fontSize: "11px", color: "rgba(255,255,255,0.3)" } }, reviewCount.toLocaleString(), " reviews"))), !readOnly && rating === 0 && /* @__PURE__ */ import_react17.default.createElement("p", { style: { fontSize: "11px", color: "rgba(255,255,255,0.2)", margin: 0 } }, allowHalf ? "Hover to rate \u2022 Half stars supported" : "Click to rate"));
|
|
3113
|
+
};
|
|
3114
|
+
|
|
3115
|
+
// src/components/StatCard/StatCard.jsx
|
|
3116
|
+
var import_react18 = __toESM(require("react"));
|
|
3117
|
+
var StatCard = ({
|
|
3118
|
+
title = "Active Users",
|
|
3119
|
+
value = "128K",
|
|
3120
|
+
numericValue = 128e3,
|
|
3121
|
+
change = "+12.4%",
|
|
3122
|
+
isPositive = true,
|
|
3123
|
+
icon = "\u{1F465}",
|
|
3124
|
+
bg = "#ffffff",
|
|
3125
|
+
accent = "#3b82f6",
|
|
3126
|
+
radius = "16px",
|
|
3127
|
+
showBadge = true,
|
|
3128
|
+
showIcon = true,
|
|
3129
|
+
barPercent = 68
|
|
3130
|
+
}) => {
|
|
3131
|
+
const [count, setCount] = (0, import_react18.useState)(0);
|
|
3132
|
+
const [barWidth, setBarWidth] = (0, import_react18.useState)(0);
|
|
3133
|
+
const [visible, setVisible] = (0, import_react18.useState)(false);
|
|
3134
|
+
const [entered, setEntered] = (0, import_react18.useState)(false);
|
|
3135
|
+
const ref = (0, import_react18.useRef)(null);
|
|
3136
|
+
(0, import_react18.useEffect)(() => {
|
|
3137
|
+
const observer = new IntersectionObserver(
|
|
3138
|
+
([entry]) => {
|
|
3139
|
+
if (entry.isIntersecting) {
|
|
3140
|
+
setVisible(true);
|
|
3141
|
+
observer.disconnect();
|
|
3142
|
+
}
|
|
3143
|
+
},
|
|
3144
|
+
{ threshold: 0.3 }
|
|
3145
|
+
);
|
|
3146
|
+
if (ref.current) observer.observe(ref.current);
|
|
3147
|
+
return () => observer.disconnect();
|
|
3148
|
+
}, []);
|
|
3149
|
+
(0, import_react18.useEffect)(() => {
|
|
3150
|
+
if (!visible) return;
|
|
3151
|
+
setEntered(true);
|
|
3152
|
+
const duration = 1400;
|
|
3153
|
+
const start = performance.now();
|
|
3154
|
+
const step = (now) => {
|
|
3155
|
+
const p = Math.min((now - start) / duration, 1);
|
|
3156
|
+
const eased = 1 - Math.pow(1 - p, 3);
|
|
3157
|
+
setCount(Math.floor(eased * numericValue));
|
|
3158
|
+
if (p < 1) requestAnimationFrame(step);
|
|
3159
|
+
};
|
|
3160
|
+
requestAnimationFrame(step);
|
|
3161
|
+
}, [visible, numericValue]);
|
|
3162
|
+
(0, import_react18.useEffect)(() => {
|
|
3163
|
+
if (!visible) return;
|
|
3164
|
+
const t = setTimeout(() => setBarWidth(barPercent), 200);
|
|
3165
|
+
return () => clearTimeout(t);
|
|
3166
|
+
}, [visible, barPercent]);
|
|
3167
|
+
const formatCount = (n) => {
|
|
3168
|
+
if (numericValue >= 1e6) return (n / 1e6).toFixed(1) + "M";
|
|
3169
|
+
if (numericValue >= 1e3) return (n / 1e3).toFixed(1) + "K";
|
|
3170
|
+
return n.toLocaleString();
|
|
3171
|
+
};
|
|
3172
|
+
const alpha = (hex, op) => {
|
|
3173
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
3174
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
3175
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
3176
|
+
return `rgba(${r},${g},${b},${op})`;
|
|
3177
|
+
};
|
|
3178
|
+
const uid = accent.replace("#", "sc");
|
|
3179
|
+
return /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("style", null, `
|
|
3180
|
+
@import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700;800&display=swap');
|
|
3181
|
+
|
|
3182
|
+
.sc-${uid} {
|
|
3183
|
+
font-family: 'Sora', sans-serif;
|
|
3184
|
+
background: ${bg};
|
|
3185
|
+
border-radius: ${radius};
|
|
3186
|
+
padding: 24px;
|
|
3187
|
+
display: inline-flex;
|
|
3188
|
+
flex-direction: column;
|
|
3189
|
+
gap: 14px;
|
|
3190
|
+
border: 1px solid rgba(0,0,0,0.07);
|
|
3191
|
+
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
|
|
3192
|
+
min-width: 200px;
|
|
3193
|
+
position: relative;
|
|
3194
|
+
overflow: hidden;
|
|
3195
|
+
opacity: 0;
|
|
3196
|
+
transform: translateY(24px);
|
|
3197
|
+
transition: opacity 0.5s ease, transform 0.5s ease, box-shadow 0.25s ease;
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3200
|
+
.sc-${uid}.entered {
|
|
3201
|
+
opacity: 1;
|
|
3202
|
+
transform: translateY(0);
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
.sc-${uid}:hover {
|
|
3206
|
+
transform: translateY(-5px) !important;
|
|
3207
|
+
box-shadow: 0 16px 40px ${alpha(accent, 0.18)};
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
/* Shimmer sweep on mount */
|
|
3211
|
+
.sc-${uid}::before {
|
|
3212
|
+
content: '';
|
|
3213
|
+
position: absolute;
|
|
3214
|
+
inset: 0;
|
|
3215
|
+
background: linear-gradient(105deg, transparent 40%, ${alpha(accent, 0.08)} 50%, transparent 60%);
|
|
3216
|
+
transform: translateX(-100%);
|
|
3217
|
+
transition: transform 0s;
|
|
3218
|
+
}
|
|
3219
|
+
.sc-${uid}.entered::before {
|
|
3220
|
+
animation: sc-shimmer-${uid} 0.9s ease 0.3s forwards;
|
|
3221
|
+
}
|
|
3222
|
+
@keyframes sc-shimmer-${uid} {
|
|
3223
|
+
to { transform: translateX(200%); }
|
|
3224
|
+
}
|
|
3225
|
+
|
|
3226
|
+
/* Pulse ring on icon */
|
|
3227
|
+
.sc-icon-${uid} {
|
|
3228
|
+
font-size: 1.3rem;
|
|
3229
|
+
background: ${alpha(accent, 0.1)};
|
|
3230
|
+
width: 42px;
|
|
3231
|
+
height: 42px;
|
|
3232
|
+
border-radius: 10px;
|
|
3233
|
+
display: flex;
|
|
3234
|
+
align-items: center;
|
|
3235
|
+
justify-content: center;
|
|
3236
|
+
position: relative;
|
|
3237
|
+
}
|
|
3238
|
+
.sc-icon-${uid}::after {
|
|
3239
|
+
content: '';
|
|
3240
|
+
position: absolute;
|
|
3241
|
+
inset: -4px;
|
|
3242
|
+
border-radius: 14px;
|
|
3243
|
+
border: 2px solid ${alpha(accent, 0.25)};
|
|
3244
|
+
animation: sc-pulse-${uid} 2s ease-in-out infinite;
|
|
3245
|
+
}
|
|
3246
|
+
@keyframes sc-pulse-${uid} {
|
|
3247
|
+
0%, 100% { transform: scale(1); opacity: 0.6; }
|
|
3248
|
+
50% { transform: scale(1.12); opacity: 0; }
|
|
3249
|
+
}
|
|
3250
|
+
|
|
3251
|
+
.sc-top-${uid} {
|
|
3252
|
+
display: flex;
|
|
3253
|
+
justify-content: space-between;
|
|
3254
|
+
align-items: center;
|
|
3255
|
+
}
|
|
3256
|
+
|
|
3257
|
+
.sc-badge-up-${uid} {
|
|
3258
|
+
font-size: 0.72rem;
|
|
3259
|
+
font-weight: 700;
|
|
3260
|
+
color: #16a34a;
|
|
3261
|
+
background: #dcfce7;
|
|
3262
|
+
padding: 3px 10px;
|
|
3263
|
+
border-radius: 999px;
|
|
3264
|
+
letter-spacing: 0.02em;
|
|
3265
|
+
animation: sc-badgepop-${uid} 0.4s cubic-bezier(.34,1.56,.64,1) 0.6s both;
|
|
3266
|
+
}
|
|
3267
|
+
.sc-badge-down-${uid} {
|
|
3268
|
+
font-size: 0.72rem;
|
|
3269
|
+
font-weight: 700;
|
|
3270
|
+
color: #dc2626;
|
|
3271
|
+
background: #fee2e2;
|
|
3272
|
+
padding: 3px 10px;
|
|
3273
|
+
border-radius: 999px;
|
|
3274
|
+
letter-spacing: 0.02em;
|
|
3275
|
+
animation: sc-badgepop-${uid} 0.4s cubic-bezier(.34,1.56,.64,1) 0.6s both;
|
|
3276
|
+
}
|
|
3277
|
+
@keyframes sc-badgepop-${uid} {
|
|
3278
|
+
from { transform: scale(0.5); opacity: 0; }
|
|
3279
|
+
to { transform: scale(1); opacity: 1; }
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
.sc-value-${uid} {
|
|
3283
|
+
font-size: 2rem;
|
|
3284
|
+
font-weight: 800;
|
|
3285
|
+
color: #0f172a;
|
|
3286
|
+
line-height: 1;
|
|
3287
|
+
font-variant-numeric: tabular-nums;
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
.sc-label-${uid} {
|
|
3291
|
+
font-size: 0.78rem;
|
|
3292
|
+
font-weight: 600;
|
|
3293
|
+
color: #94a3b8;
|
|
3294
|
+
text-transform: uppercase;
|
|
3295
|
+
letter-spacing: 0.07em;
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
.sc-track-${uid} {
|
|
3299
|
+
height: 5px;
|
|
3300
|
+
border-radius: 999px;
|
|
3301
|
+
background: rgba(0,0,0,0.06);
|
|
3302
|
+
overflow: hidden;
|
|
3303
|
+
}
|
|
3304
|
+
.sc-fill-${uid} {
|
|
3305
|
+
height: 100%;
|
|
3306
|
+
border-radius: 999px;
|
|
3307
|
+
background: linear-gradient(90deg, ${alpha(accent, 0.5)}, ${accent});
|
|
3308
|
+
width: 0%;
|
|
3309
|
+
transition: width 1.2s cubic-bezier(0.22, 1, 0.36, 1) 0.4s;
|
|
3310
|
+
box-shadow: 0 0 8px ${alpha(accent, 0.5)};
|
|
3311
|
+
}
|
|
3312
|
+
`), /* @__PURE__ */ import_react18.default.createElement(
|
|
3313
|
+
"div",
|
|
3314
|
+
{
|
|
3315
|
+
ref,
|
|
3316
|
+
className: `sc-${uid}${entered ? " entered" : ""}`
|
|
3317
|
+
},
|
|
3318
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { className: `sc-top-${uid}` }, showIcon && /* @__PURE__ */ import_react18.default.createElement("div", { className: `sc-icon-${uid}` }, icon), showBadge && /* @__PURE__ */ import_react18.default.createElement("span", { className: isPositive ? `sc-badge-up-${uid}` : `sc-badge-down-${uid}` }, isPositive ? "\u25B2" : "\u25BC", " ", change)),
|
|
3319
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { className: `sc-value-${uid}` }, visible ? formatCount(count) : "0"),
|
|
3320
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { className: `sc-label-${uid}` }, title),
|
|
3321
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { className: `sc-track-${uid}` }, /* @__PURE__ */ import_react18.default.createElement(
|
|
3322
|
+
"div",
|
|
3323
|
+
{
|
|
3324
|
+
className: `sc-fill-${uid}`,
|
|
3325
|
+
style: { width: `${barWidth}%` }
|
|
3326
|
+
}
|
|
3327
|
+
))
|
|
3328
|
+
));
|
|
3329
|
+
};
|
|
2996
3330
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2997
3331
|
0 && (module.exports = {
|
|
2998
3332
|
AvatarCard,
|
|
@@ -3010,5 +3344,7 @@ var ColorPicker = ({
|
|
|
3010
3344
|
OTPInput,
|
|
3011
3345
|
PageLoader,
|
|
3012
3346
|
PricingCard,
|
|
3013
|
-
|
|
3347
|
+
RatingStars,
|
|
3348
|
+
Sidebar,
|
|
3349
|
+
StatCard
|
|
3014
3350
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -2943,6 +2943,338 @@ var ColorPicker = ({
|
|
|
2943
2943
|
alignItems: "center"
|
|
2944
2944
|
} }, /* @__PURE__ */ React16.createElement("span", { style: { fontSize: "10px", color: "rgba(255,255,255,0.25)", fontWeight: "600", textTransform: "uppercase", letterSpacing: "0.5px" } }, "RGBA"), /* @__PURE__ */ React16.createElement("span", { style: { fontSize: "10px", fontFamily: "monospace", color: "rgba(255,255,255,0.5)" } }, alpha(color, opacity / 100))));
|
|
2945
2945
|
};
|
|
2946
|
+
|
|
2947
|
+
// src/components/RatingStars/RatingStars.jsx
|
|
2948
|
+
import React17, { useState as useState15 } from "react";
|
|
2949
|
+
var RatingStars = ({
|
|
2950
|
+
defaultRating = 0,
|
|
2951
|
+
total = 5,
|
|
2952
|
+
size = 32,
|
|
2953
|
+
allowHalf = true,
|
|
2954
|
+
showLabel = true,
|
|
2955
|
+
showCount = true,
|
|
2956
|
+
reviewCount = 0,
|
|
2957
|
+
readOnly = false,
|
|
2958
|
+
accent = "#f59e0b",
|
|
2959
|
+
bg = "#0f172a",
|
|
2960
|
+
radius = "14px",
|
|
2961
|
+
onChange = () => {
|
|
2962
|
+
}
|
|
2963
|
+
}) => {
|
|
2964
|
+
const [rating, setRating] = useState15(defaultRating);
|
|
2965
|
+
const [hovered, setHovered] = useState15(0);
|
|
2966
|
+
const labels = ["", "Terrible", "Bad", "Okay", "Good", "Excellent"];
|
|
2967
|
+
const halfLabels = { 0.5: "Awful", 1: "Terrible", 1.5: "Very Bad", 2: "Bad", 2.5: "Below Average", 3: "Okay", 3.5: "Above Average", 4: "Good", 4.5: "Great", 5: "Excellent" };
|
|
2968
|
+
const alpha = (hex, op) => {
|
|
2969
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
2970
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
2971
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
2972
|
+
return `rgba(${r},${g},${b},${op})`;
|
|
2973
|
+
};
|
|
2974
|
+
const active = hovered || rating;
|
|
2975
|
+
const handleMouseMove = (e, i) => {
|
|
2976
|
+
if (readOnly) return;
|
|
2977
|
+
if (allowHalf) {
|
|
2978
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
2979
|
+
const half = e.clientX - rect.left < rect.width / 2;
|
|
2980
|
+
setHovered(half ? i - 0.5 : i);
|
|
2981
|
+
} else {
|
|
2982
|
+
setHovered(i);
|
|
2983
|
+
}
|
|
2984
|
+
};
|
|
2985
|
+
const handleClick = (e, i) => {
|
|
2986
|
+
if (readOnly) return;
|
|
2987
|
+
let val;
|
|
2988
|
+
if (allowHalf) {
|
|
2989
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
2990
|
+
val = e.clientX - rect.left < rect.width / 2 ? i - 0.5 : i;
|
|
2991
|
+
} else {
|
|
2992
|
+
val = i;
|
|
2993
|
+
}
|
|
2994
|
+
setRating(val);
|
|
2995
|
+
onChange(val);
|
|
2996
|
+
};
|
|
2997
|
+
const StarIcon = ({ index }) => {
|
|
2998
|
+
const fill = active >= index ? "full" : active >= index - 0.5 ? "half" : "empty";
|
|
2999
|
+
const id = `half-${index}`;
|
|
3000
|
+
return /* @__PURE__ */ React17.createElement(
|
|
3001
|
+
"svg",
|
|
3002
|
+
{
|
|
3003
|
+
width: size,
|
|
3004
|
+
height: size,
|
|
3005
|
+
viewBox: "0 0 24 24",
|
|
3006
|
+
style: { cursor: readOnly ? "default" : "pointer", transition: "transform 0.1s", flexShrink: 0 },
|
|
3007
|
+
onMouseMove: (e) => handleMouseMove(e, index),
|
|
3008
|
+
onMouseLeave: () => !readOnly && setHovered(0),
|
|
3009
|
+
onClick: (e) => handleClick(e, index),
|
|
3010
|
+
onMouseEnter: (e) => {
|
|
3011
|
+
if (!readOnly) e.currentTarget.style.transform = "scale(1.15)";
|
|
3012
|
+
}
|
|
3013
|
+
},
|
|
3014
|
+
/* @__PURE__ */ React17.createElement("defs", null, /* @__PURE__ */ React17.createElement("linearGradient", { id }, /* @__PURE__ */ React17.createElement("stop", { offset: "50%", stopColor: accent }), /* @__PURE__ */ React17.createElement("stop", { offset: "50%", stopColor: "transparent" }))),
|
|
3015
|
+
/* @__PURE__ */ React17.createElement(
|
|
3016
|
+
"polygon",
|
|
3017
|
+
{
|
|
3018
|
+
points: "12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26",
|
|
3019
|
+
fill: fill === "full" ? accent : fill === "half" ? `url(#${id})` : "transparent",
|
|
3020
|
+
stroke: fill === "empty" ? "rgba(255,255,255,0.15)" : accent,
|
|
3021
|
+
strokeWidth: "1.5"
|
|
3022
|
+
}
|
|
3023
|
+
)
|
|
3024
|
+
);
|
|
3025
|
+
};
|
|
3026
|
+
return /* @__PURE__ */ React17.createElement("div", { style: {
|
|
3027
|
+
background: bg,
|
|
3028
|
+
borderRadius: radius,
|
|
3029
|
+
padding: "20px 22px",
|
|
3030
|
+
display: "inline-flex",
|
|
3031
|
+
flexDirection: "column",
|
|
3032
|
+
alignItems: "center",
|
|
3033
|
+
gap: "12px",
|
|
3034
|
+
fontFamily: "system-ui, sans-serif",
|
|
3035
|
+
border: "1px solid rgba(255,255,255,0.07)",
|
|
3036
|
+
boxShadow: "0 10px 40px rgba(0,0,0,0.4)"
|
|
3037
|
+
} }, /* @__PURE__ */ React17.createElement("div", { style: { display: "flex", gap: "4px", alignItems: "center" } }, Array.from({ length: total }, (_, i) => /* @__PURE__ */ React17.createElement(StarIcon, { key: i + 1, index: i + 1 }))), showLabel && /* @__PURE__ */ React17.createElement("div", { style: {
|
|
3038
|
+
fontSize: "14px",
|
|
3039
|
+
fontWeight: "700",
|
|
3040
|
+
minHeight: "20px",
|
|
3041
|
+
color: active > 0 ? accent : "rgba(255,255,255,0.2)",
|
|
3042
|
+
transition: "color 0.2s"
|
|
3043
|
+
} }, active > 0 ? allowHalf ? halfLabels[active] : labels[Math.round(active)] : readOnly ? "Not rated" : "Rate this"), (rating > 0 || readOnly) && showCount && /* @__PURE__ */ React17.createElement("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ React17.createElement("span", { style: {
|
|
3044
|
+
fontSize: "28px",
|
|
3045
|
+
fontWeight: "800",
|
|
3046
|
+
color: "#fff",
|
|
3047
|
+
lineHeight: 1
|
|
3048
|
+
} }, rating.toFixed(1)), /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("div", { style: { display: "flex", gap: "1px", marginBottom: "3px" } }, Array.from({ length: total }, (_, i) => {
|
|
3049
|
+
const fill = rating >= i + 1 ? "full" : rating >= i + 0.5 ? "half" : "empty";
|
|
3050
|
+
const gid = `sm-${i}`;
|
|
3051
|
+
return /* @__PURE__ */ React17.createElement("svg", { key: i, width: "12", height: "12", viewBox: "0 0 24 24" }, /* @__PURE__ */ React17.createElement("defs", null, /* @__PURE__ */ React17.createElement("linearGradient", { id: gid }, /* @__PURE__ */ React17.createElement("stop", { offset: "50%", stopColor: accent }), /* @__PURE__ */ React17.createElement("stop", { offset: "50%", stopColor: "transparent" }))), /* @__PURE__ */ React17.createElement(
|
|
3052
|
+
"polygon",
|
|
3053
|
+
{
|
|
3054
|
+
points: "12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26",
|
|
3055
|
+
fill: fill === "full" ? accent : fill === "half" ? `url(#${gid})` : "transparent",
|
|
3056
|
+
stroke: fill === "empty" ? "rgba(255,255,255,0.15)" : accent,
|
|
3057
|
+
strokeWidth: "1.5"
|
|
3058
|
+
}
|
|
3059
|
+
));
|
|
3060
|
+
})), reviewCount > 0 && /* @__PURE__ */ React17.createElement("span", { style: { fontSize: "11px", color: "rgba(255,255,255,0.3)" } }, reviewCount.toLocaleString(), " reviews"))), !readOnly && rating === 0 && /* @__PURE__ */ React17.createElement("p", { style: { fontSize: "11px", color: "rgba(255,255,255,0.2)", margin: 0 } }, allowHalf ? "Hover to rate \u2022 Half stars supported" : "Click to rate"));
|
|
3061
|
+
};
|
|
3062
|
+
|
|
3063
|
+
// src/components/StatCard/StatCard.jsx
|
|
3064
|
+
import React18, { useEffect as useEffect7, useRef as useRef3, useState as useState16 } from "react";
|
|
3065
|
+
var StatCard = ({
|
|
3066
|
+
title = "Active Users",
|
|
3067
|
+
value = "128K",
|
|
3068
|
+
numericValue = 128e3,
|
|
3069
|
+
change = "+12.4%",
|
|
3070
|
+
isPositive = true,
|
|
3071
|
+
icon = "\u{1F465}",
|
|
3072
|
+
bg = "#ffffff",
|
|
3073
|
+
accent = "#3b82f6",
|
|
3074
|
+
radius = "16px",
|
|
3075
|
+
showBadge = true,
|
|
3076
|
+
showIcon = true,
|
|
3077
|
+
barPercent = 68
|
|
3078
|
+
}) => {
|
|
3079
|
+
const [count, setCount] = useState16(0);
|
|
3080
|
+
const [barWidth, setBarWidth] = useState16(0);
|
|
3081
|
+
const [visible, setVisible] = useState16(false);
|
|
3082
|
+
const [entered, setEntered] = useState16(false);
|
|
3083
|
+
const ref = useRef3(null);
|
|
3084
|
+
useEffect7(() => {
|
|
3085
|
+
const observer = new IntersectionObserver(
|
|
3086
|
+
([entry]) => {
|
|
3087
|
+
if (entry.isIntersecting) {
|
|
3088
|
+
setVisible(true);
|
|
3089
|
+
observer.disconnect();
|
|
3090
|
+
}
|
|
3091
|
+
},
|
|
3092
|
+
{ threshold: 0.3 }
|
|
3093
|
+
);
|
|
3094
|
+
if (ref.current) observer.observe(ref.current);
|
|
3095
|
+
return () => observer.disconnect();
|
|
3096
|
+
}, []);
|
|
3097
|
+
useEffect7(() => {
|
|
3098
|
+
if (!visible) return;
|
|
3099
|
+
setEntered(true);
|
|
3100
|
+
const duration = 1400;
|
|
3101
|
+
const start = performance.now();
|
|
3102
|
+
const step = (now) => {
|
|
3103
|
+
const p = Math.min((now - start) / duration, 1);
|
|
3104
|
+
const eased = 1 - Math.pow(1 - p, 3);
|
|
3105
|
+
setCount(Math.floor(eased * numericValue));
|
|
3106
|
+
if (p < 1) requestAnimationFrame(step);
|
|
3107
|
+
};
|
|
3108
|
+
requestAnimationFrame(step);
|
|
3109
|
+
}, [visible, numericValue]);
|
|
3110
|
+
useEffect7(() => {
|
|
3111
|
+
if (!visible) return;
|
|
3112
|
+
const t = setTimeout(() => setBarWidth(barPercent), 200);
|
|
3113
|
+
return () => clearTimeout(t);
|
|
3114
|
+
}, [visible, barPercent]);
|
|
3115
|
+
const formatCount = (n) => {
|
|
3116
|
+
if (numericValue >= 1e6) return (n / 1e6).toFixed(1) + "M";
|
|
3117
|
+
if (numericValue >= 1e3) return (n / 1e3).toFixed(1) + "K";
|
|
3118
|
+
return n.toLocaleString();
|
|
3119
|
+
};
|
|
3120
|
+
const alpha = (hex, op) => {
|
|
3121
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
3122
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
3123
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
3124
|
+
return `rgba(${r},${g},${b},${op})`;
|
|
3125
|
+
};
|
|
3126
|
+
const uid = accent.replace("#", "sc");
|
|
3127
|
+
return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("style", null, `
|
|
3128
|
+
@import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700;800&display=swap');
|
|
3129
|
+
|
|
3130
|
+
.sc-${uid} {
|
|
3131
|
+
font-family: 'Sora', sans-serif;
|
|
3132
|
+
background: ${bg};
|
|
3133
|
+
border-radius: ${radius};
|
|
3134
|
+
padding: 24px;
|
|
3135
|
+
display: inline-flex;
|
|
3136
|
+
flex-direction: column;
|
|
3137
|
+
gap: 14px;
|
|
3138
|
+
border: 1px solid rgba(0,0,0,0.07);
|
|
3139
|
+
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
|
|
3140
|
+
min-width: 200px;
|
|
3141
|
+
position: relative;
|
|
3142
|
+
overflow: hidden;
|
|
3143
|
+
opacity: 0;
|
|
3144
|
+
transform: translateY(24px);
|
|
3145
|
+
transition: opacity 0.5s ease, transform 0.5s ease, box-shadow 0.25s ease;
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
.sc-${uid}.entered {
|
|
3149
|
+
opacity: 1;
|
|
3150
|
+
transform: translateY(0);
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3153
|
+
.sc-${uid}:hover {
|
|
3154
|
+
transform: translateY(-5px) !important;
|
|
3155
|
+
box-shadow: 0 16px 40px ${alpha(accent, 0.18)};
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
/* Shimmer sweep on mount */
|
|
3159
|
+
.sc-${uid}::before {
|
|
3160
|
+
content: '';
|
|
3161
|
+
position: absolute;
|
|
3162
|
+
inset: 0;
|
|
3163
|
+
background: linear-gradient(105deg, transparent 40%, ${alpha(accent, 0.08)} 50%, transparent 60%);
|
|
3164
|
+
transform: translateX(-100%);
|
|
3165
|
+
transition: transform 0s;
|
|
3166
|
+
}
|
|
3167
|
+
.sc-${uid}.entered::before {
|
|
3168
|
+
animation: sc-shimmer-${uid} 0.9s ease 0.3s forwards;
|
|
3169
|
+
}
|
|
3170
|
+
@keyframes sc-shimmer-${uid} {
|
|
3171
|
+
to { transform: translateX(200%); }
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
/* Pulse ring on icon */
|
|
3175
|
+
.sc-icon-${uid} {
|
|
3176
|
+
font-size: 1.3rem;
|
|
3177
|
+
background: ${alpha(accent, 0.1)};
|
|
3178
|
+
width: 42px;
|
|
3179
|
+
height: 42px;
|
|
3180
|
+
border-radius: 10px;
|
|
3181
|
+
display: flex;
|
|
3182
|
+
align-items: center;
|
|
3183
|
+
justify-content: center;
|
|
3184
|
+
position: relative;
|
|
3185
|
+
}
|
|
3186
|
+
.sc-icon-${uid}::after {
|
|
3187
|
+
content: '';
|
|
3188
|
+
position: absolute;
|
|
3189
|
+
inset: -4px;
|
|
3190
|
+
border-radius: 14px;
|
|
3191
|
+
border: 2px solid ${alpha(accent, 0.25)};
|
|
3192
|
+
animation: sc-pulse-${uid} 2s ease-in-out infinite;
|
|
3193
|
+
}
|
|
3194
|
+
@keyframes sc-pulse-${uid} {
|
|
3195
|
+
0%, 100% { transform: scale(1); opacity: 0.6; }
|
|
3196
|
+
50% { transform: scale(1.12); opacity: 0; }
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
.sc-top-${uid} {
|
|
3200
|
+
display: flex;
|
|
3201
|
+
justify-content: space-between;
|
|
3202
|
+
align-items: center;
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
.sc-badge-up-${uid} {
|
|
3206
|
+
font-size: 0.72rem;
|
|
3207
|
+
font-weight: 700;
|
|
3208
|
+
color: #16a34a;
|
|
3209
|
+
background: #dcfce7;
|
|
3210
|
+
padding: 3px 10px;
|
|
3211
|
+
border-radius: 999px;
|
|
3212
|
+
letter-spacing: 0.02em;
|
|
3213
|
+
animation: sc-badgepop-${uid} 0.4s cubic-bezier(.34,1.56,.64,1) 0.6s both;
|
|
3214
|
+
}
|
|
3215
|
+
.sc-badge-down-${uid} {
|
|
3216
|
+
font-size: 0.72rem;
|
|
3217
|
+
font-weight: 700;
|
|
3218
|
+
color: #dc2626;
|
|
3219
|
+
background: #fee2e2;
|
|
3220
|
+
padding: 3px 10px;
|
|
3221
|
+
border-radius: 999px;
|
|
3222
|
+
letter-spacing: 0.02em;
|
|
3223
|
+
animation: sc-badgepop-${uid} 0.4s cubic-bezier(.34,1.56,.64,1) 0.6s both;
|
|
3224
|
+
}
|
|
3225
|
+
@keyframes sc-badgepop-${uid} {
|
|
3226
|
+
from { transform: scale(0.5); opacity: 0; }
|
|
3227
|
+
to { transform: scale(1); opacity: 1; }
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
.sc-value-${uid} {
|
|
3231
|
+
font-size: 2rem;
|
|
3232
|
+
font-weight: 800;
|
|
3233
|
+
color: #0f172a;
|
|
3234
|
+
line-height: 1;
|
|
3235
|
+
font-variant-numeric: tabular-nums;
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
.sc-label-${uid} {
|
|
3239
|
+
font-size: 0.78rem;
|
|
3240
|
+
font-weight: 600;
|
|
3241
|
+
color: #94a3b8;
|
|
3242
|
+
text-transform: uppercase;
|
|
3243
|
+
letter-spacing: 0.07em;
|
|
3244
|
+
}
|
|
3245
|
+
|
|
3246
|
+
.sc-track-${uid} {
|
|
3247
|
+
height: 5px;
|
|
3248
|
+
border-radius: 999px;
|
|
3249
|
+
background: rgba(0,0,0,0.06);
|
|
3250
|
+
overflow: hidden;
|
|
3251
|
+
}
|
|
3252
|
+
.sc-fill-${uid} {
|
|
3253
|
+
height: 100%;
|
|
3254
|
+
border-radius: 999px;
|
|
3255
|
+
background: linear-gradient(90deg, ${alpha(accent, 0.5)}, ${accent});
|
|
3256
|
+
width: 0%;
|
|
3257
|
+
transition: width 1.2s cubic-bezier(0.22, 1, 0.36, 1) 0.4s;
|
|
3258
|
+
box-shadow: 0 0 8px ${alpha(accent, 0.5)};
|
|
3259
|
+
}
|
|
3260
|
+
`), /* @__PURE__ */ React18.createElement(
|
|
3261
|
+
"div",
|
|
3262
|
+
{
|
|
3263
|
+
ref,
|
|
3264
|
+
className: `sc-${uid}${entered ? " entered" : ""}`
|
|
3265
|
+
},
|
|
3266
|
+
/* @__PURE__ */ React18.createElement("div", { className: `sc-top-${uid}` }, showIcon && /* @__PURE__ */ React18.createElement("div", { className: `sc-icon-${uid}` }, icon), showBadge && /* @__PURE__ */ React18.createElement("span", { className: isPositive ? `sc-badge-up-${uid}` : `sc-badge-down-${uid}` }, isPositive ? "\u25B2" : "\u25BC", " ", change)),
|
|
3267
|
+
/* @__PURE__ */ React18.createElement("div", { className: `sc-value-${uid}` }, visible ? formatCount(count) : "0"),
|
|
3268
|
+
/* @__PURE__ */ React18.createElement("div", { className: `sc-label-${uid}` }, title),
|
|
3269
|
+
/* @__PURE__ */ React18.createElement("div", { className: `sc-track-${uid}` }, /* @__PURE__ */ React18.createElement(
|
|
3270
|
+
"div",
|
|
3271
|
+
{
|
|
3272
|
+
className: `sc-fill-${uid}`,
|
|
3273
|
+
style: { width: `${barWidth}%` }
|
|
3274
|
+
}
|
|
3275
|
+
))
|
|
3276
|
+
));
|
|
3277
|
+
};
|
|
2946
3278
|
export {
|
|
2947
3279
|
AvatarCard,
|
|
2948
3280
|
BackgoundImageSlider,
|
|
@@ -2959,5 +3291,7 @@ export {
|
|
|
2959
3291
|
OTPInput,
|
|
2960
3292
|
PageLoader,
|
|
2961
3293
|
PricingCard,
|
|
2962
|
-
|
|
3294
|
+
RatingStars,
|
|
3295
|
+
Sidebar,
|
|
3296
|
+
StatCard
|
|
2963
3297
|
};
|