virtual-ui-lib 1.0.72 → 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 +220 -2
- package/dist/index.mjs +218 -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
|
@@ -45,7 +45,8 @@ __export(index_exports, {
|
|
|
45
45
|
PageLoader: () => PageLoader,
|
|
46
46
|
PricingCard: () => PricingCard,
|
|
47
47
|
RatingStars: () => RatingStars,
|
|
48
|
-
Sidebar: () => Sidebar
|
|
48
|
+
Sidebar: () => Sidebar,
|
|
49
|
+
StatCard: () => StatCard
|
|
49
50
|
});
|
|
50
51
|
module.exports = __toCommonJS(index_exports);
|
|
51
52
|
|
|
@@ -3110,6 +3111,222 @@ var RatingStars = ({
|
|
|
3110
3111
|
));
|
|
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"));
|
|
3112
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
|
+
};
|
|
3113
3330
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3114
3331
|
0 && (module.exports = {
|
|
3115
3332
|
AvatarCard,
|
|
@@ -3128,5 +3345,6 @@ var RatingStars = ({
|
|
|
3128
3345
|
PageLoader,
|
|
3129
3346
|
PricingCard,
|
|
3130
3347
|
RatingStars,
|
|
3131
|
-
Sidebar
|
|
3348
|
+
Sidebar,
|
|
3349
|
+
StatCard
|
|
3132
3350
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -3059,6 +3059,222 @@ var RatingStars = ({
|
|
|
3059
3059
|
));
|
|
3060
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
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
|
+
};
|
|
3062
3278
|
export {
|
|
3063
3279
|
AvatarCard,
|
|
3064
3280
|
BackgoundImageSlider,
|
|
@@ -3076,5 +3292,6 @@ export {
|
|
|
3076
3292
|
PageLoader,
|
|
3077
3293
|
PricingCard,
|
|
3078
3294
|
RatingStars,
|
|
3079
|
-
Sidebar
|
|
3295
|
+
Sidebar,
|
|
3296
|
+
StatCard
|
|
3080
3297
|
};
|