@aiready/components 0.11.13 → 0.11.15
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/dist/components/button.d.ts +2 -2
- package/dist/components/button.js +9 -3
- package/dist/components/button.js.map +1 -1
- package/dist/components/card.d.ts +4 -1
- package/dist/components/card.js +27 -1
- package/dist/components/card.js.map +1 -1
- package/dist/index.d.ts +129 -8
- package/dist/index.js +1104 -97
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/src/code-block/CodeBlock.tsx +59 -64
- package/src/components/button.tsx +9 -1
- package/src/components/card.tsx +42 -0
- package/src/components/icons.tsx +409 -0
- package/src/components/modal.tsx +96 -0
- package/src/data-display/ScoreCircle.tsx +144 -0
- package/src/data-display/index.ts +2 -7
- package/src/feedback/FeedbackWidget.tsx +121 -0
- package/src/feedback/index.ts +3 -12
- package/src/index.ts +15 -0
- package/src/navigation/Breadcrumb.tsx +26 -52
- package/src/navigation/PlatformShell.tsx +408 -0
- package/src/navigation/index.ts +2 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/components",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.15",
|
|
4
4
|
"description": "Unified shared components library (UI, charts, hooks, utilities) for AIReady",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -62,8 +62,10 @@
|
|
|
62
62
|
"clsx": "^2.1.1",
|
|
63
63
|
"d3": "^7.9.0",
|
|
64
64
|
"d3-force": "^3.0.0",
|
|
65
|
+
"framer-motion": "^12.35.0",
|
|
66
|
+
"lucide-react": "^0.577.0",
|
|
65
67
|
"tailwind-merge": "^3.0.0",
|
|
66
|
-
"@aiready/core": "0.21.
|
|
68
|
+
"@aiready/core": "0.21.14"
|
|
67
69
|
},
|
|
68
70
|
"devDependencies": {
|
|
69
71
|
"@testing-library/jest-dom": "^6.6.5",
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React, { useState, useCallback, useMemo } from 'react';
|
|
4
|
+
import { motion, AnimatePresence } from 'framer-motion';
|
|
5
|
+
import { cn } from '../utils/cn';
|
|
4
6
|
|
|
5
7
|
export interface CodeBlockProps {
|
|
6
8
|
children: React.ReactNode;
|
|
@@ -8,17 +10,15 @@ export interface CodeBlockProps {
|
|
|
8
10
|
showCopy?: boolean;
|
|
9
11
|
showHeader?: boolean;
|
|
10
12
|
className?: string;
|
|
13
|
+
variant?: 'default' | 'glass';
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
// Dedent helper - removes common leading indentation
|
|
14
17
|
function dedentCode(code: string): string {
|
|
15
|
-
// Normalize tabs to two spaces
|
|
16
18
|
const normalized = code.replace(/\t/g, ' ').replace(/[ \t]+$/gm, '');
|
|
17
|
-
|
|
18
19
|
const lines = normalized.split('\n');
|
|
19
20
|
if (lines.length <= 1) return normalized.trim();
|
|
20
21
|
|
|
21
|
-
// Remove leading/trailing empty lines
|
|
22
22
|
let start = 0;
|
|
23
23
|
while (start < lines.length && lines[start].trim() === '') start++;
|
|
24
24
|
let end = lines.length - 1;
|
|
@@ -27,27 +27,21 @@ function dedentCode(code: string): string {
|
|
|
27
27
|
if (start > end) return '';
|
|
28
28
|
const relevantLines = lines.slice(start, end + 1);
|
|
29
29
|
|
|
30
|
-
// Find minimum indent across non-empty lines
|
|
31
30
|
const nonEmpty = relevantLines.filter((l) => l.trim() !== '');
|
|
32
31
|
const minIndent = nonEmpty.reduce((min, line) => {
|
|
33
32
|
const m = line.match(/^\s*/)?.[0].length ?? 0;
|
|
34
33
|
return Math.min(min, m);
|
|
35
34
|
}, Infinity);
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
)
|
|
45
|
-
.join('\n');
|
|
46
|
-
|
|
47
|
-
return dedented;
|
|
36
|
+
return minIndent === Infinity || minIndent === 0
|
|
37
|
+
? relevantLines.join('\n')
|
|
38
|
+
: relevantLines
|
|
39
|
+
.map((l) =>
|
|
40
|
+
l.startsWith(' '.repeat(minIndent)) ? l.slice(minIndent) : l
|
|
41
|
+
)
|
|
42
|
+
.join('\n');
|
|
48
43
|
}
|
|
49
44
|
|
|
50
|
-
// Simple Copy Button
|
|
51
45
|
function CopyButton({ code }: { code: string }) {
|
|
52
46
|
const [copied, setCopied] = useState(false);
|
|
53
47
|
|
|
@@ -57,7 +51,6 @@ function CopyButton({ code }: { code: string }) {
|
|
|
57
51
|
setCopied(true);
|
|
58
52
|
setTimeout(() => setCopied(false), 2000);
|
|
59
53
|
} catch {
|
|
60
|
-
// Fallback for older browsers
|
|
61
54
|
const textarea = document.createElement('textarea');
|
|
62
55
|
textarea.value = code;
|
|
63
56
|
textarea.style.position = 'fixed';
|
|
@@ -74,38 +67,30 @@ function CopyButton({ code }: { code: string }) {
|
|
|
74
67
|
return (
|
|
75
68
|
<button
|
|
76
69
|
onClick={handleCopy}
|
|
77
|
-
className="
|
|
78
|
-
title={copied ? 'Copied!' : 'Copy code'}
|
|
70
|
+
className="flex items-center gap-1.5 rounded-md px-2 py-1 text-[10px] font-bold uppercase tracking-wider text-slate-400 hover:bg-slate-700/50 hover:text-cyan-400 transition-all"
|
|
79
71
|
>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
<path
|
|
103
|
-
strokeLinecap="round"
|
|
104
|
-
strokeLinejoin="round"
|
|
105
|
-
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
|
|
106
|
-
/>
|
|
107
|
-
</svg>
|
|
108
|
-
)}
|
|
72
|
+
<AnimatePresence mode="wait">
|
|
73
|
+
{copied ? (
|
|
74
|
+
<motion.span
|
|
75
|
+
key="copied"
|
|
76
|
+
initial={{ opacity: 0, y: 5 }}
|
|
77
|
+
animate={{ opacity: 1, y: 0 }}
|
|
78
|
+
exit={{ opacity: 0, y: -5 }}
|
|
79
|
+
className="text-cyan-400"
|
|
80
|
+
>
|
|
81
|
+
Copied!
|
|
82
|
+
</motion.span>
|
|
83
|
+
) : (
|
|
84
|
+
<motion.span
|
|
85
|
+
key="copy"
|
|
86
|
+
initial={{ opacity: 0, y: 5 }}
|
|
87
|
+
animate={{ opacity: 1, y: 0 }}
|
|
88
|
+
exit={{ opacity: 0, y: -5 }}
|
|
89
|
+
>
|
|
90
|
+
Copy
|
|
91
|
+
</motion.span>
|
|
92
|
+
)}
|
|
93
|
+
</AnimatePresence>
|
|
109
94
|
</button>
|
|
110
95
|
);
|
|
111
96
|
}
|
|
@@ -116,13 +101,10 @@ export function CodeBlock({
|
|
|
116
101
|
showCopy = true,
|
|
117
102
|
showHeader = true,
|
|
118
103
|
className = '',
|
|
104
|
+
variant = 'glass',
|
|
119
105
|
}: CodeBlockProps) {
|
|
120
|
-
// Get code string from children
|
|
121
106
|
const codeString = useMemo(() => {
|
|
122
|
-
if (typeof children === 'string')
|
|
123
|
-
return dedentCode(children);
|
|
124
|
-
}
|
|
125
|
-
// Handle template literal children
|
|
107
|
+
if (typeof children === 'string') return dedentCode(children);
|
|
126
108
|
try {
|
|
127
109
|
const raw = React.Children.toArray(children)
|
|
128
110
|
.map((c) =>
|
|
@@ -137,18 +119,30 @@ export function CodeBlock({
|
|
|
137
119
|
|
|
138
120
|
return (
|
|
139
121
|
<div
|
|
140
|
-
className={
|
|
122
|
+
className={cn(
|
|
123
|
+
'group relative my-6 overflow-hidden rounded-2xl border transition-all',
|
|
124
|
+
variant === 'glass'
|
|
125
|
+
? 'border-indigo-500/20 bg-slate-950/40 backdrop-blur-md shadow-2xl'
|
|
126
|
+
: 'border-slate-700 bg-slate-900 shadow-lg',
|
|
127
|
+
className
|
|
128
|
+
)}
|
|
141
129
|
>
|
|
142
|
-
{/* Header bar */}
|
|
143
130
|
{showHeader && (
|
|
144
|
-
<div
|
|
131
|
+
<div
|
|
132
|
+
className={cn(
|
|
133
|
+
'flex items-center justify-between px-4 py-2 border-b',
|
|
134
|
+
variant === 'glass'
|
|
135
|
+
? 'border-indigo-500/10 bg-slate-900/20'
|
|
136
|
+
: 'border-slate-800 bg-slate-800/50'
|
|
137
|
+
)}
|
|
138
|
+
>
|
|
145
139
|
<div className="flex items-center gap-2">
|
|
146
140
|
<div className="flex gap-1.5">
|
|
147
|
-
<div className="h-
|
|
148
|
-
<div className="h-
|
|
149
|
-
<div className="h-
|
|
141
|
+
<div className="h-2.5 w-2.5 rounded-full bg-red-500/20 border border-red-500/40" />
|
|
142
|
+
<div className="h-2.5 w-2.5 rounded-full bg-amber-500/20 border border-amber-500/40" />
|
|
143
|
+
<div className="h-2.5 w-2.5 rounded-full bg-emerald-500/20 border border-emerald-500/40" />
|
|
150
144
|
</div>
|
|
151
|
-
<span className="ml-2 text-
|
|
145
|
+
<span className="ml-2 text-[10px] font-bold uppercase tracking-widest text-slate-500 font-mono">
|
|
152
146
|
{language}
|
|
153
147
|
</span>
|
|
154
148
|
</div>
|
|
@@ -156,8 +150,7 @@ export function CodeBlock({
|
|
|
156
150
|
</div>
|
|
157
151
|
)}
|
|
158
152
|
|
|
159
|
-
|
|
160
|
-
<pre className="overflow-x-auto p-4 text-sm leading-relaxed">
|
|
153
|
+
<pre className="overflow-x-auto p-4 text-sm leading-relaxed scrollbar-thin scrollbar-thumb-slate-700">
|
|
161
154
|
<code className="font-mono block whitespace-pre text-slate-300">
|
|
162
155
|
{codeString}
|
|
163
156
|
</code>
|
|
@@ -166,7 +159,6 @@ export function CodeBlock({
|
|
|
166
159
|
);
|
|
167
160
|
}
|
|
168
161
|
|
|
169
|
-
// Inline code component
|
|
170
162
|
export function InlineCode({
|
|
171
163
|
children,
|
|
172
164
|
className = '',
|
|
@@ -176,7 +168,10 @@ export function InlineCode({
|
|
|
176
168
|
}) {
|
|
177
169
|
return (
|
|
178
170
|
<code
|
|
179
|
-
className={
|
|
171
|
+
className={cn(
|
|
172
|
+
'rounded-md bg-slate-800/50 border border-slate-700/50 px-1.5 py-0.5 text-xs font-mono text-cyan-400',
|
|
173
|
+
className
|
|
174
|
+
)}
|
|
180
175
|
>
|
|
181
176
|
{children}
|
|
182
177
|
</code>
|
|
@@ -3,7 +3,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
|
|
|
3
3
|
import { cn } from '../utils/cn';
|
|
4
4
|
|
|
5
5
|
const buttonVariants = cva(
|
|
6
|
-
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-
|
|
6
|
+
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
|
|
7
7
|
{
|
|
8
8
|
variants: {
|
|
9
9
|
variant: {
|
|
@@ -16,12 +16,20 @@ const buttonVariants = cva(
|
|
|
16
16
|
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
17
17
|
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
18
18
|
link: 'text-primary underline-offset-4 hover:underline',
|
|
19
|
+
// Platform specific high-polish variants
|
|
20
|
+
glow: 'bg-gradient-to-r from-cyan-600 to-blue-600 text-white shadow-lg shadow-cyan-500/20 hover:shadow-cyan-500/40 hover:scale-[1.02] active:scale-[0.98]',
|
|
21
|
+
glass:
|
|
22
|
+
'bg-slate-800/50 backdrop-blur-sm border border-slate-700 text-slate-200 hover:bg-slate-700/50 hover:text-white',
|
|
23
|
+
accent:
|
|
24
|
+
'bg-cyan-500/10 text-cyan-400 border border-cyan-500/20 hover:bg-cyan-500/20',
|
|
19
25
|
},
|
|
20
26
|
size: {
|
|
21
27
|
default: 'h-10 px-4 py-2',
|
|
22
28
|
sm: 'h-9 rounded-md px-3',
|
|
23
29
|
lg: 'h-11 rounded-md px-8',
|
|
24
30
|
icon: 'h-10 w-10',
|
|
31
|
+
// Extra sizes for dashboard use
|
|
32
|
+
xs: 'h-7 rounded-md px-2 text-[10px] font-bold uppercase tracking-wider',
|
|
25
33
|
},
|
|
26
34
|
},
|
|
27
35
|
defaultVariants: {
|
package/src/components/card.tsx
CHANGED
|
@@ -75,6 +75,45 @@ const CardFooter = React.forwardRef<
|
|
|
75
75
|
));
|
|
76
76
|
CardFooter.displayName = 'CardFooter';
|
|
77
77
|
|
|
78
|
+
// GlassCard - Highly polished platform style
|
|
79
|
+
const GlassCard = React.forwardRef<
|
|
80
|
+
HTMLDivElement,
|
|
81
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
82
|
+
>(({ className, ...props }, ref) => (
|
|
83
|
+
<div
|
|
84
|
+
ref={ref}
|
|
85
|
+
className={cn(
|
|
86
|
+
'rounded-2xl border border-indigo-500/20 bg-slate-900/40 backdrop-blur-md shadow-xl transition-all hover:border-indigo-500/30',
|
|
87
|
+
className
|
|
88
|
+
)}
|
|
89
|
+
{...props}
|
|
90
|
+
/>
|
|
91
|
+
));
|
|
92
|
+
GlassCard.displayName = 'GlassCard';
|
|
93
|
+
|
|
94
|
+
const GlassCardHeader = React.forwardRef<
|
|
95
|
+
HTMLDivElement,
|
|
96
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
97
|
+
>(({ className, ...props }, ref) => (
|
|
98
|
+
<div
|
|
99
|
+
ref={ref}
|
|
100
|
+
className={cn(
|
|
101
|
+
'flex flex-col space-y-1.5 p-6 border-b border-indigo-500/10',
|
|
102
|
+
className
|
|
103
|
+
)}
|
|
104
|
+
{...props}
|
|
105
|
+
/>
|
|
106
|
+
));
|
|
107
|
+
GlassCardHeader.displayName = 'GlassCardHeader';
|
|
108
|
+
|
|
109
|
+
const GlassCardContent = React.forwardRef<
|
|
110
|
+
HTMLDivElement,
|
|
111
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
112
|
+
>(({ className, ...props }, ref) => (
|
|
113
|
+
<div ref={ref} className={cn('p-6', className)} {...props} />
|
|
114
|
+
));
|
|
115
|
+
GlassCardContent.displayName = 'GlassCardContent';
|
|
116
|
+
|
|
78
117
|
export {
|
|
79
118
|
Card,
|
|
80
119
|
CardHeader,
|
|
@@ -82,4 +121,7 @@ export {
|
|
|
82
121
|
CardTitle,
|
|
83
122
|
CardDescription,
|
|
84
123
|
CardContent,
|
|
124
|
+
GlassCard,
|
|
125
|
+
GlassCardHeader,
|
|
126
|
+
GlassCardContent,
|
|
85
127
|
};
|