@lastbrain/ai-ui-react 1.0.7 → 1.0.8
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/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +65 -3
- package/dist/styles/inline.d.ts +125 -0
- package/dist/styles/inline.d.ts.map +1 -0
- package/dist/styles/inline.js +135 -0
- package/package.json +1 -1
- package/src/components/AiStatusButton.tsx +151 -70
- package/src/styles/inline.ts +155 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAItD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,GACf,EAAE,mBAAmB,2CAsQrB"}
|
|
@@ -1,13 +1,75 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from "react";
|
|
4
|
+
import { aiStyles } from "../styles/inline";
|
|
4
5
|
export function AiStatusButton({ status, loading = false, className = "", }) {
|
|
5
6
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
7
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
6
8
|
if (loading) {
|
|
7
|
-
return (_jsx("button", {
|
|
9
|
+
return (_jsx("button", { style: {
|
|
10
|
+
...aiStyles.statusButton,
|
|
11
|
+
...aiStyles.statusButtonDisabled,
|
|
12
|
+
}, className: className, disabled: true, children: _jsx("svg", { style: {
|
|
13
|
+
animation: "ai-spin 1s linear infinite",
|
|
14
|
+
}, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83" }) }) }));
|
|
8
15
|
}
|
|
9
16
|
if (!status) {
|
|
10
|
-
return (_jsxs("
|
|
17
|
+
return (_jsxs("div", { style: { position: "relative", display: "inline-block" }, children: [_jsx("button", { style: {
|
|
18
|
+
...aiStyles.statusButton,
|
|
19
|
+
color: "#ef4444",
|
|
20
|
+
...(isHovered && aiStyles.statusButtonHover),
|
|
21
|
+
}, className: className, onMouseEnter: () => {
|
|
22
|
+
setShowTooltip(true);
|
|
23
|
+
setIsHovered(true);
|
|
24
|
+
}, onMouseLeave: () => {
|
|
25
|
+
setShowTooltip(false);
|
|
26
|
+
setIsHovered(false);
|
|
27
|
+
}, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" }) }) }), showTooltip && _jsx("div", { style: aiStyles.tooltip, children: "No status available" })] }));
|
|
11
28
|
}
|
|
12
|
-
return (_jsxs("div", {
|
|
29
|
+
return (_jsxs("div", { style: { position: "relative", display: "inline-block" }, children: [_jsx("button", { style: {
|
|
30
|
+
...aiStyles.statusButton,
|
|
31
|
+
color: "#10b981",
|
|
32
|
+
...(isHovered && aiStyles.statusButtonHover),
|
|
33
|
+
}, className: className, onMouseEnter: () => {
|
|
34
|
+
setShowTooltip(true);
|
|
35
|
+
setIsHovered(true);
|
|
36
|
+
}, onMouseLeave: () => {
|
|
37
|
+
setShowTooltip(false);
|
|
38
|
+
setIsHovered(false);
|
|
39
|
+
}, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" }) }) }), showTooltip && (_jsxs("div", { style: aiStyles.tooltip, children: [_jsx("div", { style: aiStyles.tooltipHeader, children: "API Status" }), _jsxs("div", { style: {
|
|
40
|
+
...aiStyles.tooltipSection,
|
|
41
|
+
...aiStyles.tooltipSectionFirst,
|
|
42
|
+
}, children: [_jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "API Key:" }), _jsx("span", { style: aiStyles.tooltipValue, children: status.api_key.name })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Env:" }), _jsx("span", { style: aiStyles.tooltipValue, children: status.api_key.env })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Rate Limit:" }), _jsxs("span", { style: aiStyles.tooltipValue, children: [status.api_key.rate_limit_rpm, " req/min"] })] })] }), _jsxs("div", { style: aiStyles.tooltipSection, children: [_jsx("div", { style: aiStyles.tooltipSubtitle, children: "Balance" }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Total:" }), _jsx("span", { style: {
|
|
43
|
+
...aiStyles.tooltipValue,
|
|
44
|
+
...aiStyles.tooltipValueBold,
|
|
45
|
+
}, children: status.balance.total.toLocaleString() })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Purchased:" }), _jsx("span", { style: aiStyles.tooltipValue, children: status.balance.purchased.toLocaleString() })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Quota:" }), _jsx("span", { style: aiStyles.tooltipValue, children: status.balance.quota.toLocaleString() })] })] }), _jsxs("div", { style: aiStyles.tooltipSection, children: [_jsx("div", { style: aiStyles.tooltipSubtitle, children: "Plan" }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Type:" }), _jsx("span", { style: {
|
|
46
|
+
...aiStyles.tooltipValue,
|
|
47
|
+
textTransform: "capitalize",
|
|
48
|
+
}, children: status.quota.plan })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Remaining:" }), _jsxs("span", { style: aiStyles.tooltipValue, children: [status.quota.remaining_quota.toLocaleString(), " /", " ", status.quota.effective_quota.toLocaleString()] })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Status:" }), _jsx("span", { style: {
|
|
49
|
+
...aiStyles.tooltipValue,
|
|
50
|
+
...(status.quota.is_active
|
|
51
|
+
? aiStyles.tooltipValueSuccess
|
|
52
|
+
: aiStyles.tooltipValueWarning),
|
|
53
|
+
}, children: status.quota.is_active ? "Active" : "Inactive" })] })] }), _jsxs("div", { style: aiStyles.tooltipSection, children: [_jsx("div", { style: aiStyles.tooltipSubtitle, children: "Storage" }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Database:" }), _jsxs("span", { style: aiStyles.tooltipValue, children: [status.storage.db_mb.toFixed(2), " MB"] })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Files:" }), _jsxs("span", { style: aiStyles.tooltipValue, children: [status.storage.files_mb.toFixed(2), " MB"] })] }), _jsxs("div", { style: aiStyles.tooltipRow, children: [_jsx("span", { style: aiStyles.tooltipLabel, children: "Total:" }), _jsxs("span", { style: {
|
|
54
|
+
...aiStyles.tooltipValue,
|
|
55
|
+
...aiStyles.tooltipValueBold,
|
|
56
|
+
}, children: [(status.storage.db_mb + status.storage.files_mb).toFixed(2), " MB"] })] })] }), _jsxs("div", { style: aiStyles.tooltipActions, children: [_jsx("a", { href: "https://ai.lastbrain.io/fr/auth/dashboard", target: "_blank", rel: "noopener noreferrer", style: aiStyles.tooltipLink, onMouseEnter: (e) => {
|
|
57
|
+
e.currentTarget.style.background = "#dbeafe";
|
|
58
|
+
e.currentTarget.style.borderColor = "#3b82f6";
|
|
59
|
+
}, onMouseLeave: (e) => {
|
|
60
|
+
e.currentTarget.style.background = "#eff6ff";
|
|
61
|
+
e.currentTarget.style.borderColor = "#dbeafe";
|
|
62
|
+
}, children: "Dashboard" }), _jsx("a", { href: "https://ai.lastbrain.io/fr/auth/billing", target: "_blank", rel: "noopener noreferrer", style: aiStyles.tooltipLink, onMouseEnter: (e) => {
|
|
63
|
+
e.currentTarget.style.background = "#dbeafe";
|
|
64
|
+
e.currentTarget.style.borderColor = "#3b82f6";
|
|
65
|
+
}, onMouseLeave: (e) => {
|
|
66
|
+
e.currentTarget.style.background = "#eff6ff";
|
|
67
|
+
e.currentTarget.style.borderColor = "#dbeafe";
|
|
68
|
+
}, children: "History" }), _jsx("a", { href: "https://ai.lastbrain.io/fr/auth/billing", target: "_blank", rel: "noopener noreferrer", style: aiStyles.tooltipLink, onMouseEnter: (e) => {
|
|
69
|
+
e.currentTarget.style.background = "#dbeafe";
|
|
70
|
+
e.currentTarget.style.borderColor = "#3b82f6";
|
|
71
|
+
}, onMouseLeave: (e) => {
|
|
72
|
+
e.currentTarget.style.background = "#eff6ff";
|
|
73
|
+
e.currentTarget.style.borderColor = "#dbeafe";
|
|
74
|
+
}, children: "Settings" })] })] }))] }));
|
|
13
75
|
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline styles for AI UI components
|
|
3
|
+
* These styles are injected directly to avoid CSS import requirements
|
|
4
|
+
*/
|
|
5
|
+
export declare const aiStyles: {
|
|
6
|
+
statusButton: {
|
|
7
|
+
display: "inline-flex";
|
|
8
|
+
alignItems: "center";
|
|
9
|
+
justifyContent: "center";
|
|
10
|
+
width: string;
|
|
11
|
+
height: string;
|
|
12
|
+
border: string;
|
|
13
|
+
borderRadius: string;
|
|
14
|
+
background: string;
|
|
15
|
+
color: string;
|
|
16
|
+
cursor: "pointer";
|
|
17
|
+
transition: string;
|
|
18
|
+
};
|
|
19
|
+
statusButtonHover: {
|
|
20
|
+
background: string;
|
|
21
|
+
boxShadow: string;
|
|
22
|
+
};
|
|
23
|
+
statusButtonDisabled: {
|
|
24
|
+
opacity: number;
|
|
25
|
+
cursor: "not-allowed";
|
|
26
|
+
};
|
|
27
|
+
tooltip: {
|
|
28
|
+
position: "absolute";
|
|
29
|
+
top: string;
|
|
30
|
+
right: number;
|
|
31
|
+
zIndex: number;
|
|
32
|
+
minWidth: string;
|
|
33
|
+
maxWidth: string;
|
|
34
|
+
padding: string;
|
|
35
|
+
background: string;
|
|
36
|
+
border: string;
|
|
37
|
+
borderRadius: string;
|
|
38
|
+
boxShadow: string;
|
|
39
|
+
fontSize: string;
|
|
40
|
+
color: string;
|
|
41
|
+
};
|
|
42
|
+
tooltipHeader: {
|
|
43
|
+
fontWeight: number;
|
|
44
|
+
fontSize: string;
|
|
45
|
+
paddingBottom: string;
|
|
46
|
+
marginBottom: string;
|
|
47
|
+
borderBottom: string;
|
|
48
|
+
color: string;
|
|
49
|
+
};
|
|
50
|
+
tooltipSection: {
|
|
51
|
+
padding: string;
|
|
52
|
+
borderTop: string;
|
|
53
|
+
};
|
|
54
|
+
tooltipSectionFirst: {
|
|
55
|
+
borderTop: string;
|
|
56
|
+
paddingTop: number;
|
|
57
|
+
};
|
|
58
|
+
tooltipSubtitle: {
|
|
59
|
+
fontWeight: number;
|
|
60
|
+
marginBottom: string;
|
|
61
|
+
fontSize: string;
|
|
62
|
+
color: string;
|
|
63
|
+
textTransform: "uppercase";
|
|
64
|
+
letterSpacing: string;
|
|
65
|
+
};
|
|
66
|
+
tooltipRow: {
|
|
67
|
+
display: "flex";
|
|
68
|
+
justifyContent: "space-between";
|
|
69
|
+
gap: string;
|
|
70
|
+
marginBottom: string;
|
|
71
|
+
alignItems: "center";
|
|
72
|
+
};
|
|
73
|
+
tooltipLabel: {
|
|
74
|
+
color: string;
|
|
75
|
+
fontSize: string;
|
|
76
|
+
};
|
|
77
|
+
tooltipValue: {
|
|
78
|
+
fontFamily: string;
|
|
79
|
+
fontSize: string;
|
|
80
|
+
color: string;
|
|
81
|
+
fontWeight: number;
|
|
82
|
+
};
|
|
83
|
+
tooltipValueBold: {
|
|
84
|
+
fontWeight: number;
|
|
85
|
+
color: string;
|
|
86
|
+
};
|
|
87
|
+
tooltipValueSuccess: {
|
|
88
|
+
color: string;
|
|
89
|
+
fontWeight: number;
|
|
90
|
+
};
|
|
91
|
+
tooltipValueWarning: {
|
|
92
|
+
color: string;
|
|
93
|
+
fontWeight: number;
|
|
94
|
+
};
|
|
95
|
+
tooltipActions: {
|
|
96
|
+
display: "flex";
|
|
97
|
+
gap: string;
|
|
98
|
+
justifyContent: "space-between";
|
|
99
|
+
paddingTop: string;
|
|
100
|
+
marginTop: string;
|
|
101
|
+
borderTop: string;
|
|
102
|
+
};
|
|
103
|
+
tooltipLink: {
|
|
104
|
+
flex: number;
|
|
105
|
+
textAlign: "center";
|
|
106
|
+
padding: string;
|
|
107
|
+
color: string;
|
|
108
|
+
textDecoration: string;
|
|
109
|
+
borderRadius: string;
|
|
110
|
+
transition: string;
|
|
111
|
+
fontSize: string;
|
|
112
|
+
fontWeight: number;
|
|
113
|
+
background: string;
|
|
114
|
+
border: string;
|
|
115
|
+
};
|
|
116
|
+
spinner: {
|
|
117
|
+
width: string;
|
|
118
|
+
height: string;
|
|
119
|
+
border: string;
|
|
120
|
+
borderTopColor: string;
|
|
121
|
+
borderRadius: string;
|
|
122
|
+
animation: string;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=inline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../../src/styles/inline.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyIpB,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline styles for AI UI components
|
|
3
|
+
* These styles are injected directly to avoid CSS import requirements
|
|
4
|
+
*/
|
|
5
|
+
export const aiStyles = {
|
|
6
|
+
statusButton: {
|
|
7
|
+
display: "inline-flex",
|
|
8
|
+
alignItems: "center",
|
|
9
|
+
justifyContent: "center",
|
|
10
|
+
width: "40px",
|
|
11
|
+
height: "40px",
|
|
12
|
+
border: "1px solid #e5e7eb",
|
|
13
|
+
borderRadius: "8px",
|
|
14
|
+
background: "#ffffff",
|
|
15
|
+
color: "#1f2937",
|
|
16
|
+
cursor: "pointer",
|
|
17
|
+
transition: "all 0.2s",
|
|
18
|
+
},
|
|
19
|
+
statusButtonHover: {
|
|
20
|
+
background: "#f9fafb",
|
|
21
|
+
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
|
22
|
+
},
|
|
23
|
+
statusButtonDisabled: {
|
|
24
|
+
opacity: 0.5,
|
|
25
|
+
cursor: "not-allowed",
|
|
26
|
+
},
|
|
27
|
+
tooltip: {
|
|
28
|
+
position: "absolute",
|
|
29
|
+
top: "calc(100% + 8px)",
|
|
30
|
+
right: 0,
|
|
31
|
+
zIndex: 1000,
|
|
32
|
+
minWidth: "320px",
|
|
33
|
+
maxWidth: "400px",
|
|
34
|
+
padding: "16px",
|
|
35
|
+
background: "#ffffff",
|
|
36
|
+
border: "1px solid #e5e7eb",
|
|
37
|
+
borderRadius: "8px",
|
|
38
|
+
boxShadow: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)",
|
|
39
|
+
fontSize: "12px",
|
|
40
|
+
color: "#1f2937",
|
|
41
|
+
},
|
|
42
|
+
tooltipHeader: {
|
|
43
|
+
fontWeight: 600,
|
|
44
|
+
fontSize: "16px",
|
|
45
|
+
paddingBottom: "12px",
|
|
46
|
+
marginBottom: "12px",
|
|
47
|
+
borderBottom: "1px solid #e5e7eb",
|
|
48
|
+
color: "#111827",
|
|
49
|
+
},
|
|
50
|
+
tooltipSection: {
|
|
51
|
+
padding: "12px 0",
|
|
52
|
+
borderTop: "1px solid #f3f4f6",
|
|
53
|
+
},
|
|
54
|
+
tooltipSectionFirst: {
|
|
55
|
+
borderTop: "none",
|
|
56
|
+
paddingTop: 0,
|
|
57
|
+
},
|
|
58
|
+
tooltipSubtitle: {
|
|
59
|
+
fontWeight: 600,
|
|
60
|
+
marginBottom: "8px",
|
|
61
|
+
fontSize: "12px",
|
|
62
|
+
color: "#111827",
|
|
63
|
+
textTransform: "uppercase",
|
|
64
|
+
letterSpacing: "0.05em",
|
|
65
|
+
},
|
|
66
|
+
tooltipRow: {
|
|
67
|
+
display: "flex",
|
|
68
|
+
justifyContent: "space-between",
|
|
69
|
+
gap: "16px",
|
|
70
|
+
marginBottom: "6px",
|
|
71
|
+
alignItems: "center",
|
|
72
|
+
},
|
|
73
|
+
tooltipLabel: {
|
|
74
|
+
color: "#6b7280",
|
|
75
|
+
fontSize: "12px",
|
|
76
|
+
},
|
|
77
|
+
tooltipValue: {
|
|
78
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
|
79
|
+
fontSize: "12px",
|
|
80
|
+
color: "#111827",
|
|
81
|
+
fontWeight: 500,
|
|
82
|
+
},
|
|
83
|
+
tooltipValueBold: {
|
|
84
|
+
fontWeight: 700,
|
|
85
|
+
color: "#111827",
|
|
86
|
+
},
|
|
87
|
+
tooltipValueSuccess: {
|
|
88
|
+
color: "#10b981",
|
|
89
|
+
fontWeight: 600,
|
|
90
|
+
},
|
|
91
|
+
tooltipValueWarning: {
|
|
92
|
+
color: "#f59e0b",
|
|
93
|
+
fontWeight: 600,
|
|
94
|
+
},
|
|
95
|
+
tooltipActions: {
|
|
96
|
+
display: "flex",
|
|
97
|
+
gap: "8px",
|
|
98
|
+
justifyContent: "space-between",
|
|
99
|
+
paddingTop: "12px",
|
|
100
|
+
marginTop: "8px",
|
|
101
|
+
borderTop: "1px solid #f3f4f6",
|
|
102
|
+
},
|
|
103
|
+
tooltipLink: {
|
|
104
|
+
flex: 1,
|
|
105
|
+
textAlign: "center",
|
|
106
|
+
padding: "6px 12px",
|
|
107
|
+
color: "#3b82f6",
|
|
108
|
+
textDecoration: "none",
|
|
109
|
+
borderRadius: "6px",
|
|
110
|
+
transition: "all 0.2s",
|
|
111
|
+
fontSize: "11px",
|
|
112
|
+
fontWeight: 500,
|
|
113
|
+
background: "#eff6ff",
|
|
114
|
+
border: "1px solid #dbeafe",
|
|
115
|
+
},
|
|
116
|
+
spinner: {
|
|
117
|
+
width: "16px",
|
|
118
|
+
height: "16px",
|
|
119
|
+
border: "2px solid #e5e7eb",
|
|
120
|
+
borderTopColor: "#3b82f6",
|
|
121
|
+
borderRadius: "50%",
|
|
122
|
+
animation: "spin 1s linear infinite",
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
// Inject keyframes animation for spinner
|
|
126
|
+
if (typeof document !== "undefined") {
|
|
127
|
+
const styleSheet = document.createElement("style");
|
|
128
|
+
styleSheet.textContent = `
|
|
129
|
+
@keyframes ai-spin {
|
|
130
|
+
from { transform: rotate(0deg); }
|
|
131
|
+
to { transform: rotate(360deg); }
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
document.head.appendChild(styleSheet);
|
|
135
|
+
}
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type { AiStatus } from "@lastbrain/ai-ui-core";
|
|
4
4
|
import { useState } from "react";
|
|
5
|
+
import { aiStyles } from "../styles/inline";
|
|
5
6
|
|
|
6
7
|
export interface AiStatusButtonProps {
|
|
7
8
|
status: AiStatus | null;
|
|
@@ -15,15 +16,22 @@ export function AiStatusButton({
|
|
|
15
16
|
className = "",
|
|
16
17
|
}: AiStatusButtonProps) {
|
|
17
18
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
19
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
18
20
|
|
|
19
21
|
if (loading) {
|
|
20
22
|
return (
|
|
21
23
|
<button
|
|
22
|
-
|
|
24
|
+
style={{
|
|
25
|
+
...aiStyles.statusButton,
|
|
26
|
+
...aiStyles.statusButtonDisabled,
|
|
27
|
+
}}
|
|
28
|
+
className={className}
|
|
23
29
|
disabled
|
|
24
30
|
>
|
|
25
31
|
<svg
|
|
26
|
-
|
|
32
|
+
style={{
|
|
33
|
+
animation: "ai-spin 1s linear infinite",
|
|
34
|
+
}}
|
|
27
35
|
width="16"
|
|
28
36
|
height="16"
|
|
29
37
|
viewBox="0 0 24 24"
|
|
@@ -38,31 +46,55 @@ export function AiStatusButton({
|
|
|
38
46
|
|
|
39
47
|
if (!status) {
|
|
40
48
|
return (
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
<div style={{ position: "relative", display: "inline-block" }}>
|
|
50
|
+
<button
|
|
51
|
+
style={{
|
|
52
|
+
...aiStyles.statusButton,
|
|
53
|
+
color: "#ef4444",
|
|
54
|
+
...(isHovered && aiStyles.statusButtonHover),
|
|
55
|
+
}}
|
|
56
|
+
className={className}
|
|
57
|
+
onMouseEnter={() => {
|
|
58
|
+
setShowTooltip(true);
|
|
59
|
+
setIsHovered(true);
|
|
60
|
+
}}
|
|
61
|
+
onMouseLeave={() => {
|
|
62
|
+
setShowTooltip(false);
|
|
63
|
+
setIsHovered(false);
|
|
64
|
+
}}
|
|
52
65
|
>
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
<svg
|
|
67
|
+
width="16"
|
|
68
|
+
height="16"
|
|
69
|
+
viewBox="0 0 24 24"
|
|
70
|
+
fill="none"
|
|
71
|
+
stroke="currentColor"
|
|
72
|
+
>
|
|
73
|
+
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12" />
|
|
74
|
+
</svg>
|
|
75
|
+
</button>
|
|
76
|
+
{showTooltip && <div style={aiStyles.tooltip}>No status available</div>}
|
|
77
|
+
</div>
|
|
57
78
|
);
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
return (
|
|
61
|
-
<div
|
|
82
|
+
<div style={{ position: "relative", display: "inline-block" }}>
|
|
62
83
|
<button
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
84
|
+
style={{
|
|
85
|
+
...aiStyles.statusButton,
|
|
86
|
+
color: "#10b981",
|
|
87
|
+
...(isHovered && aiStyles.statusButtonHover),
|
|
88
|
+
}}
|
|
89
|
+
className={className}
|
|
90
|
+
onMouseEnter={() => {
|
|
91
|
+
setShowTooltip(true);
|
|
92
|
+
setIsHovered(true);
|
|
93
|
+
}}
|
|
94
|
+
onMouseLeave={() => {
|
|
95
|
+
setShowTooltip(false);
|
|
96
|
+
setIsHovered(false);
|
|
97
|
+
}}
|
|
66
98
|
>
|
|
67
99
|
<svg
|
|
68
100
|
width="16"
|
|
@@ -76,101 +108,134 @@ export function AiStatusButton({
|
|
|
76
108
|
</button>
|
|
77
109
|
|
|
78
110
|
{showTooltip && (
|
|
79
|
-
<div
|
|
80
|
-
<div
|
|
111
|
+
<div style={aiStyles.tooltip}>
|
|
112
|
+
<div style={aiStyles.tooltipHeader}>API Status</div>
|
|
81
113
|
|
|
82
|
-
<div
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
114
|
+
<div
|
|
115
|
+
style={{
|
|
116
|
+
...aiStyles.tooltipSection,
|
|
117
|
+
...aiStyles.tooltipSectionFirst,
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
<div style={aiStyles.tooltipRow}>
|
|
121
|
+
<span style={aiStyles.tooltipLabel}>API Key:</span>
|
|
122
|
+
<span style={aiStyles.tooltipValue}>{status.api_key.name}</span>
|
|
86
123
|
</div>
|
|
87
|
-
<div
|
|
88
|
-
<span
|
|
89
|
-
<span
|
|
124
|
+
<div style={aiStyles.tooltipRow}>
|
|
125
|
+
<span style={aiStyles.tooltipLabel}>Env:</span>
|
|
126
|
+
<span style={aiStyles.tooltipValue}>{status.api_key.env}</span>
|
|
90
127
|
</div>
|
|
91
|
-
<div
|
|
92
|
-
<span
|
|
93
|
-
<span
|
|
128
|
+
<div style={aiStyles.tooltipRow}>
|
|
129
|
+
<span style={aiStyles.tooltipLabel}>Rate Limit:</span>
|
|
130
|
+
<span style={aiStyles.tooltipValue}>
|
|
94
131
|
{status.api_key.rate_limit_rpm} req/min
|
|
95
132
|
</span>
|
|
96
133
|
</div>
|
|
97
134
|
</div>
|
|
98
135
|
|
|
99
|
-
<div
|
|
100
|
-
<div
|
|
101
|
-
<div
|
|
102
|
-
<span
|
|
103
|
-
<span
|
|
136
|
+
<div style={aiStyles.tooltipSection}>
|
|
137
|
+
<div style={aiStyles.tooltipSubtitle}>Balance</div>
|
|
138
|
+
<div style={aiStyles.tooltipRow}>
|
|
139
|
+
<span style={aiStyles.tooltipLabel}>Total:</span>
|
|
140
|
+
<span
|
|
141
|
+
style={{
|
|
142
|
+
...aiStyles.tooltipValue,
|
|
143
|
+
...aiStyles.tooltipValueBold,
|
|
144
|
+
}}
|
|
145
|
+
>
|
|
104
146
|
{status.balance.total.toLocaleString()}
|
|
105
147
|
</span>
|
|
106
148
|
</div>
|
|
107
|
-
<div
|
|
108
|
-
<span
|
|
109
|
-
<span
|
|
149
|
+
<div style={aiStyles.tooltipRow}>
|
|
150
|
+
<span style={aiStyles.tooltipLabel}>Purchased:</span>
|
|
151
|
+
<span style={aiStyles.tooltipValue}>
|
|
110
152
|
{status.balance.purchased.toLocaleString()}
|
|
111
153
|
</span>
|
|
112
154
|
</div>
|
|
113
|
-
<div
|
|
114
|
-
<span
|
|
115
|
-
<span
|
|
155
|
+
<div style={aiStyles.tooltipRow}>
|
|
156
|
+
<span style={aiStyles.tooltipLabel}>Quota:</span>
|
|
157
|
+
<span style={aiStyles.tooltipValue}>
|
|
116
158
|
{status.balance.quota.toLocaleString()}
|
|
117
159
|
</span>
|
|
118
160
|
</div>
|
|
119
161
|
</div>
|
|
120
162
|
|
|
121
|
-
<div
|
|
122
|
-
<div
|
|
123
|
-
<div
|
|
124
|
-
<span
|
|
125
|
-
<span
|
|
163
|
+
<div style={aiStyles.tooltipSection}>
|
|
164
|
+
<div style={aiStyles.tooltipSubtitle}>Plan</div>
|
|
165
|
+
<div style={aiStyles.tooltipRow}>
|
|
166
|
+
<span style={aiStyles.tooltipLabel}>Type:</span>
|
|
167
|
+
<span
|
|
168
|
+
style={{
|
|
169
|
+
...aiStyles.tooltipValue,
|
|
170
|
+
textTransform: "capitalize",
|
|
171
|
+
}}
|
|
172
|
+
>
|
|
126
173
|
{status.quota.plan}
|
|
127
174
|
</span>
|
|
128
175
|
</div>
|
|
129
|
-
<div
|
|
130
|
-
<span
|
|
131
|
-
<span
|
|
176
|
+
<div style={aiStyles.tooltipRow}>
|
|
177
|
+
<span style={aiStyles.tooltipLabel}>Remaining:</span>
|
|
178
|
+
<span style={aiStyles.tooltipValue}>
|
|
132
179
|
{status.quota.remaining_quota.toLocaleString()} /{" "}
|
|
133
180
|
{status.quota.effective_quota.toLocaleString()}
|
|
134
181
|
</span>
|
|
135
182
|
</div>
|
|
136
|
-
<div
|
|
137
|
-
<span
|
|
183
|
+
<div style={aiStyles.tooltipRow}>
|
|
184
|
+
<span style={aiStyles.tooltipLabel}>Status:</span>
|
|
138
185
|
<span
|
|
139
|
-
|
|
186
|
+
style={{
|
|
187
|
+
...aiStyles.tooltipValue,
|
|
188
|
+
...(status.quota.is_active
|
|
189
|
+
? aiStyles.tooltipValueSuccess
|
|
190
|
+
: aiStyles.tooltipValueWarning),
|
|
191
|
+
}}
|
|
140
192
|
>
|
|
141
193
|
{status.quota.is_active ? "Active" : "Inactive"}
|
|
142
194
|
</span>
|
|
143
195
|
</div>
|
|
144
196
|
</div>
|
|
145
197
|
|
|
146
|
-
<div
|
|
147
|
-
<div
|
|
148
|
-
<div
|
|
149
|
-
<span
|
|
150
|
-
<span
|
|
198
|
+
<div style={aiStyles.tooltipSection}>
|
|
199
|
+
<div style={aiStyles.tooltipSubtitle}>Storage</div>
|
|
200
|
+
<div style={aiStyles.tooltipRow}>
|
|
201
|
+
<span style={aiStyles.tooltipLabel}>Database:</span>
|
|
202
|
+
<span style={aiStyles.tooltipValue}>
|
|
151
203
|
{status.storage.db_mb.toFixed(2)} MB
|
|
152
204
|
</span>
|
|
153
205
|
</div>
|
|
154
|
-
<div
|
|
155
|
-
<span
|
|
156
|
-
<span
|
|
206
|
+
<div style={aiStyles.tooltipRow}>
|
|
207
|
+
<span style={aiStyles.tooltipLabel}>Files:</span>
|
|
208
|
+
<span style={aiStyles.tooltipValue}>
|
|
157
209
|
{status.storage.files_mb.toFixed(2)} MB
|
|
158
210
|
</span>
|
|
159
211
|
</div>
|
|
160
|
-
<div
|
|
161
|
-
<span
|
|
162
|
-
<span
|
|
212
|
+
<div style={aiStyles.tooltipRow}>
|
|
213
|
+
<span style={aiStyles.tooltipLabel}>Total:</span>
|
|
214
|
+
<span
|
|
215
|
+
style={{
|
|
216
|
+
...aiStyles.tooltipValue,
|
|
217
|
+
...aiStyles.tooltipValueBold,
|
|
218
|
+
}}
|
|
219
|
+
>
|
|
163
220
|
{(status.storage.db_mb + status.storage.files_mb).toFixed(2)} MB
|
|
164
221
|
</span>
|
|
165
222
|
</div>
|
|
166
223
|
</div>
|
|
167
224
|
|
|
168
|
-
<div
|
|
225
|
+
<div style={aiStyles.tooltipActions}>
|
|
169
226
|
<a
|
|
170
227
|
href="https://ai.lastbrain.io/fr/auth/dashboard"
|
|
171
228
|
target="_blank"
|
|
172
229
|
rel="noopener noreferrer"
|
|
173
|
-
|
|
230
|
+
style={aiStyles.tooltipLink}
|
|
231
|
+
onMouseEnter={(e) => {
|
|
232
|
+
e.currentTarget.style.background = "#dbeafe";
|
|
233
|
+
e.currentTarget.style.borderColor = "#3b82f6";
|
|
234
|
+
}}
|
|
235
|
+
onMouseLeave={(e) => {
|
|
236
|
+
e.currentTarget.style.background = "#eff6ff";
|
|
237
|
+
e.currentTarget.style.borderColor = "#dbeafe";
|
|
238
|
+
}}
|
|
174
239
|
>
|
|
175
240
|
Dashboard
|
|
176
241
|
</a>
|
|
@@ -178,7 +243,15 @@ export function AiStatusButton({
|
|
|
178
243
|
href="https://ai.lastbrain.io/fr/auth/billing"
|
|
179
244
|
target="_blank"
|
|
180
245
|
rel="noopener noreferrer"
|
|
181
|
-
|
|
246
|
+
style={aiStyles.tooltipLink}
|
|
247
|
+
onMouseEnter={(e) => {
|
|
248
|
+
e.currentTarget.style.background = "#dbeafe";
|
|
249
|
+
e.currentTarget.style.borderColor = "#3b82f6";
|
|
250
|
+
}}
|
|
251
|
+
onMouseLeave={(e) => {
|
|
252
|
+
e.currentTarget.style.background = "#eff6ff";
|
|
253
|
+
e.currentTarget.style.borderColor = "#dbeafe";
|
|
254
|
+
}}
|
|
182
255
|
>
|
|
183
256
|
History
|
|
184
257
|
</a>
|
|
@@ -186,7 +259,15 @@ export function AiStatusButton({
|
|
|
186
259
|
href="https://ai.lastbrain.io/fr/auth/billing"
|
|
187
260
|
target="_blank"
|
|
188
261
|
rel="noopener noreferrer"
|
|
189
|
-
|
|
262
|
+
style={aiStyles.tooltipLink}
|
|
263
|
+
onMouseEnter={(e) => {
|
|
264
|
+
e.currentTarget.style.background = "#dbeafe";
|
|
265
|
+
e.currentTarget.style.borderColor = "#3b82f6";
|
|
266
|
+
}}
|
|
267
|
+
onMouseLeave={(e) => {
|
|
268
|
+
e.currentTarget.style.background = "#eff6ff";
|
|
269
|
+
e.currentTarget.style.borderColor = "#dbeafe";
|
|
270
|
+
}}
|
|
190
271
|
>
|
|
191
272
|
Settings
|
|
192
273
|
</a>
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline styles for AI UI components
|
|
3
|
+
* These styles are injected directly to avoid CSS import requirements
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const aiStyles = {
|
|
7
|
+
statusButton: {
|
|
8
|
+
display: "inline-flex" as const,
|
|
9
|
+
alignItems: "center" as const,
|
|
10
|
+
justifyContent: "center" as const,
|
|
11
|
+
width: "40px",
|
|
12
|
+
height: "40px",
|
|
13
|
+
border: "1px solid #e5e7eb",
|
|
14
|
+
borderRadius: "8px",
|
|
15
|
+
background: "#ffffff",
|
|
16
|
+
color: "#1f2937",
|
|
17
|
+
cursor: "pointer" as const,
|
|
18
|
+
transition: "all 0.2s",
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
statusButtonHover: {
|
|
22
|
+
background: "#f9fafb",
|
|
23
|
+
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
statusButtonDisabled: {
|
|
27
|
+
opacity: 0.5,
|
|
28
|
+
cursor: "not-allowed" as const,
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
tooltip: {
|
|
32
|
+
position: "absolute" as const,
|
|
33
|
+
top: "calc(100% + 8px)",
|
|
34
|
+
right: 0,
|
|
35
|
+
zIndex: 1000,
|
|
36
|
+
minWidth: "320px",
|
|
37
|
+
maxWidth: "400px",
|
|
38
|
+
padding: "16px",
|
|
39
|
+
background: "#ffffff",
|
|
40
|
+
border: "1px solid #e5e7eb",
|
|
41
|
+
borderRadius: "8px",
|
|
42
|
+
boxShadow:
|
|
43
|
+
"0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)",
|
|
44
|
+
fontSize: "12px",
|
|
45
|
+
color: "#1f2937",
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
tooltipHeader: {
|
|
49
|
+
fontWeight: 600,
|
|
50
|
+
fontSize: "16px",
|
|
51
|
+
paddingBottom: "12px",
|
|
52
|
+
marginBottom: "12px",
|
|
53
|
+
borderBottom: "1px solid #e5e7eb",
|
|
54
|
+
color: "#111827",
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
tooltipSection: {
|
|
58
|
+
padding: "12px 0",
|
|
59
|
+
borderTop: "1px solid #f3f4f6",
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
tooltipSectionFirst: {
|
|
63
|
+
borderTop: "none",
|
|
64
|
+
paddingTop: 0,
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
tooltipSubtitle: {
|
|
68
|
+
fontWeight: 600,
|
|
69
|
+
marginBottom: "8px",
|
|
70
|
+
fontSize: "12px",
|
|
71
|
+
color: "#111827",
|
|
72
|
+
textTransform: "uppercase" as const,
|
|
73
|
+
letterSpacing: "0.05em",
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
tooltipRow: {
|
|
77
|
+
display: "flex" as const,
|
|
78
|
+
justifyContent: "space-between" as const,
|
|
79
|
+
gap: "16px",
|
|
80
|
+
marginBottom: "6px",
|
|
81
|
+
alignItems: "center" as const,
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
tooltipLabel: {
|
|
85
|
+
color: "#6b7280",
|
|
86
|
+
fontSize: "12px",
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
tooltipValue: {
|
|
90
|
+
fontFamily:
|
|
91
|
+
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
|
92
|
+
fontSize: "12px",
|
|
93
|
+
color: "#111827",
|
|
94
|
+
fontWeight: 500,
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
tooltipValueBold: {
|
|
98
|
+
fontWeight: 700,
|
|
99
|
+
color: "#111827",
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
tooltipValueSuccess: {
|
|
103
|
+
color: "#10b981",
|
|
104
|
+
fontWeight: 600,
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
tooltipValueWarning: {
|
|
108
|
+
color: "#f59e0b",
|
|
109
|
+
fontWeight: 600,
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
tooltipActions: {
|
|
113
|
+
display: "flex" as const,
|
|
114
|
+
gap: "8px",
|
|
115
|
+
justifyContent: "space-between" as const,
|
|
116
|
+
paddingTop: "12px",
|
|
117
|
+
marginTop: "8px",
|
|
118
|
+
borderTop: "1px solid #f3f4f6",
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
tooltipLink: {
|
|
122
|
+
flex: 1,
|
|
123
|
+
textAlign: "center" as const,
|
|
124
|
+
padding: "6px 12px",
|
|
125
|
+
color: "#3b82f6",
|
|
126
|
+
textDecoration: "none",
|
|
127
|
+
borderRadius: "6px",
|
|
128
|
+
transition: "all 0.2s",
|
|
129
|
+
fontSize: "11px",
|
|
130
|
+
fontWeight: 500,
|
|
131
|
+
background: "#eff6ff",
|
|
132
|
+
border: "1px solid #dbeafe",
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
spinner: {
|
|
136
|
+
width: "16px",
|
|
137
|
+
height: "16px",
|
|
138
|
+
border: "2px solid #e5e7eb",
|
|
139
|
+
borderTopColor: "#3b82f6",
|
|
140
|
+
borderRadius: "50%",
|
|
141
|
+
animation: "spin 1s linear infinite",
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Inject keyframes animation for spinner
|
|
146
|
+
if (typeof document !== "undefined") {
|
|
147
|
+
const styleSheet = document.createElement("style");
|
|
148
|
+
styleSheet.textContent = `
|
|
149
|
+
@keyframes ai-spin {
|
|
150
|
+
from { transform: rotate(0deg); }
|
|
151
|
+
to { transform: rotate(360deg); }
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
154
|
+
document.head.appendChild(styleSheet);
|
|
155
|
+
}
|