@aiready/components 0.11.18 → 0.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/components",
3
- "version": "0.11.18",
3
+ "version": "0.11.22",
4
4
  "description": "Unified shared components library (UI, charts, hooks, utilities) for AIReady",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -65,7 +65,7 @@
65
65
  "framer-motion": "^12.35.0",
66
66
  "lucide-react": "^0.577.0",
67
67
  "tailwind-merge": "^3.0.0",
68
- "@aiready/core": "0.21.17"
68
+ "@aiready/core": "0.21.21"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@testing-library/jest-dom": "^6.6.5",
@@ -390,6 +390,154 @@ export function RefreshCwIcon({
390
390
  );
391
391
  }
392
392
 
393
+ export function WalletIcon({
394
+ className = 'w-6 h-6',
395
+ ...props
396
+ }: { className?: string } & React.SVGProps<SVGSVGElement>) {
397
+ return (
398
+ <svg
399
+ viewBox="0 0 24 24"
400
+ fill="none"
401
+ stroke="currentColor"
402
+ strokeWidth="2"
403
+ strokeLinecap="round"
404
+ strokeLinejoin="round"
405
+ className={className}
406
+ {...props}
407
+ >
408
+ <path d="M21 12V7a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-1" />
409
+ <path d="M16 12h5" />
410
+ <circle cx="16" cy="12" r="1" />
411
+ </svg>
412
+ );
413
+ }
414
+
415
+ export function ClockIcon({
416
+ className = 'w-6 h-6',
417
+ ...props
418
+ }: { className?: string } & React.SVGProps<SVGSVGElement>) {
419
+ return (
420
+ <svg
421
+ viewBox="0 0 24 24"
422
+ fill="none"
423
+ stroke="currentColor"
424
+ strokeWidth="2"
425
+ strokeLinecap="round"
426
+ strokeLinejoin="round"
427
+ className={className}
428
+ {...props}
429
+ >
430
+ <circle cx="12" cy="12" r="10" />
431
+ <polyline points="12 6 12 12 16 14" />
432
+ </svg>
433
+ );
434
+ }
435
+
436
+ export function ZapIcon({
437
+ className = 'w-6 h-6',
438
+ ...props
439
+ }: { className?: string } & React.SVGProps<SVGSVGElement>) {
440
+ return (
441
+ <svg
442
+ viewBox="0 0 24 24"
443
+ fill="none"
444
+ stroke="currentColor"
445
+ strokeWidth="2"
446
+ strokeLinecap="round"
447
+ strokeLinejoin="round"
448
+ className={className}
449
+ {...props}
450
+ >
451
+ <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
452
+ </svg>
453
+ );
454
+ }
455
+
456
+ export function HammerIcon({
457
+ className = 'w-6 h-6',
458
+ ...props
459
+ }: { className?: string } & React.SVGProps<SVGSVGElement>) {
460
+ return (
461
+ <svg
462
+ viewBox="0 0 24 24"
463
+ fill="none"
464
+ stroke="currentColor"
465
+ strokeWidth="2"
466
+ strokeLinecap="round"
467
+ strokeLinejoin="round"
468
+ className={className}
469
+ {...props}
470
+ >
471
+ <path d="M18.42 13.59L7.46 2.63a1 1 0 0 0-1.42 0l-4.7 4.7a1 1 0 0 0 0 1.42L11 18.23l1.07-1.07-1.41-1.41 1.42-1.42 1.41 1.41 1.41-1.41-1.41-1.41 1.42-1.42 1.41 1.41 2-2z" />
472
+ <path d="M13 18l6 6" />
473
+ </svg>
474
+ );
475
+ }
476
+
477
+ export function ArrowRightIcon({
478
+ className = 'w-6 h-6',
479
+ ...props
480
+ }: { className?: string } & React.SVGProps<SVGSVGElement>) {
481
+ return (
482
+ <svg
483
+ viewBox="0 0 24 24"
484
+ fill="none"
485
+ stroke="currentColor"
486
+ strokeWidth="2"
487
+ strokeLinecap="round"
488
+ strokeLinejoin="round"
489
+ className={className}
490
+ {...props}
491
+ >
492
+ <line x1="5" y1="12" x2="19" y2="12" />
493
+ <polyline points="12 5 19 12 12 19" />
494
+ </svg>
495
+ );
496
+ }
497
+
498
+ export function ShieldCheckIcon({
499
+ className = 'w-6 h-6',
500
+ ...props
501
+ }: { className?: string } & React.SVGProps<SVGSVGElement>) {
502
+ return (
503
+ <svg
504
+ viewBox="0 0 24 24"
505
+ fill="none"
506
+ stroke="currentColor"
507
+ strokeWidth="2"
508
+ strokeLinecap="round"
509
+ strokeLinejoin="round"
510
+ className={className}
511
+ {...props}
512
+ >
513
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
514
+ <path d="M9 12l2 2 4-4" />
515
+ </svg>
516
+ );
517
+ }
518
+
519
+ export function AlertTriangleIcon({
520
+ className = 'w-6 h-6',
521
+ ...props
522
+ }: { className?: string } & React.SVGProps<SVGSVGElement>) {
523
+ return (
524
+ <svg
525
+ viewBox="0 0 24 24"
526
+ fill="none"
527
+ stroke="currentColor"
528
+ strokeWidth="2"
529
+ strokeLinecap="round"
530
+ strokeLinejoin="round"
531
+ className={className}
532
+ {...props}
533
+ >
534
+ <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
535
+ <line x1="12" y1="9" x2="12" y2="13" />
536
+ <line x1="12" y1="17" x2="12.01" y2="17" />
537
+ </svg>
538
+ );
539
+ }
540
+
393
541
  export default {
394
542
  RocketIcon,
395
543
  ChartIcon,
@@ -406,4 +554,11 @@ export default {
406
554
  BrainIcon,
407
555
  TerminalIcon,
408
556
  CommandLineIcon,
557
+ WalletIcon,
558
+ ClockIcon,
559
+ ZapIcon,
560
+ HammerIcon,
561
+ ArrowRightIcon,
562
+ ShieldCheckIcon,
563
+ AlertTriangleIcon,
409
564
  };
@@ -58,7 +58,7 @@ export function FeedbackWidget({
58
58
  initial={{ opacity: 0, scale: 0.9, y: 20 }}
59
59
  animate={{ opacity: 1, scale: 1, y: 0 }}
60
60
  exit={{ opacity: 0, scale: 0.9, y: 20 }}
61
- className="absolute bottom-16 right-0 w-80 rounded-2xl p-4 bg-slate-900 border border-cyan-500/30 shadow-2xl backdrop-blur-xl"
61
+ className="absolute bottom-full mb-4 right-0 w-80 rounded-2xl p-4 bg-slate-900 border border-cyan-500/30 shadow-2xl backdrop-blur-xl top-auto"
62
62
  >
63
63
  <div className="flex items-center justify-between mb-4">
64
64
  <h4 className="font-bold text-white flex items-center gap-2 text-sm">
@@ -0,0 +1,51 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ formatNumber,
4
+ formatCompactNumber,
5
+ formatPercentage,
6
+ formatFileSize,
7
+ formatRelativeTime,
8
+ formatDuration,
9
+ formatMetric,
10
+ } from '../formatters';
11
+
12
+ describe('Formatters', () => {
13
+ it('should format numbers with commas', () => {
14
+ expect(formatNumber(1234567)).toBe('1,234,567');
15
+ });
16
+
17
+ it('should format compact numbers', () => {
18
+ expect(formatCompactNumber(1234)).toBe('1.2K');
19
+ expect(formatCompactNumber(1234567)).toBe('1.2M');
20
+ });
21
+
22
+ it('should format percentages', () => {
23
+ expect(formatPercentage(0.1234)).toBe('12.3%');
24
+ expect(formatPercentage(0.1234, 0)).toBe('12%');
25
+ });
26
+
27
+ it('should format file sizes', () => {
28
+ expect(formatFileSize(1024)).toBe('1.0 KB');
29
+ expect(formatFileSize(1048576)).toBe('1.0 MB');
30
+ });
31
+
32
+ it('should format relative time', () => {
33
+ const now = new Date();
34
+ const oneHourAgo = new Date(now.getTime() - 3600000);
35
+ expect(formatRelativeTime(oneHourAgo)).toBe('1 hour ago');
36
+ expect(formatRelativeTime(now)).toBe('just now');
37
+ });
38
+
39
+ it('should format duration', () => {
40
+ expect(formatDuration(3661000)).toBe('1h 1m 1s');
41
+ expect(formatDuration(61000)).toBe('1m 1s');
42
+ expect(formatDuration(1000)).toBe('1s');
43
+ });
44
+
45
+ it('should format metrics based on unit', () => {
46
+ expect(formatMetric(1024, 'bytes')).toBe('1.0 KB');
47
+ expect(formatMetric(0.5, 'percentage')).toBe('50.0%');
48
+ expect(formatMetric(3600000, 'duration')).toBe('1h 0m 0s');
49
+ expect(formatMetric(1200, 'number')).toBe('1.2K');
50
+ });
51
+ });
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ scoreColor,
4
+ scoreBg,
5
+ scoreLabel,
6
+ scoreGlow,
7
+ getScoreRating,
8
+ } from '../score';
9
+
10
+ describe('Score Utilities', () => {
11
+ it('should return correct color for scores', () => {
12
+ expect(scoreColor(80)).toBe('text-emerald-400');
13
+ expect(scoreColor(60)).toBe('text-amber-400');
14
+ expect(scoreColor(30)).toBe('text-red-400');
15
+ expect(scoreColor(null)).toBe('text-slate-400');
16
+ });
17
+
18
+ it('should return correct background for scores', () => {
19
+ expect(scoreBg(80)).toContain('emerald');
20
+ expect(scoreBg(60)).toContain('amber');
21
+ expect(scoreBg(30)).toContain('red');
22
+ expect(scoreBg(null)).toContain('slate');
23
+ });
24
+
25
+ it('should return correct labels', () => {
26
+ expect(scoreLabel(80)).toBe('AI-Ready');
27
+ expect(scoreLabel(60)).toBe('Needs Improvement');
28
+ expect(scoreLabel(30)).toBe('Critical Issues');
29
+ expect(scoreLabel(null)).toBe('Not analyzed');
30
+ });
31
+
32
+ it('should return correct rating strings', () => {
33
+ expect(getScoreRating(95)).toBe('excellent');
34
+ expect(getScoreRating(80)).toBe('good');
35
+ expect(getScoreRating(65)).toBe('fair');
36
+ expect(getScoreRating(45)).toBe('needs-work');
37
+ expect(getScoreRating(20)).toBe('critical');
38
+ expect(getScoreRating(null)).toBe('critical');
39
+ });
40
+ });