@lastbrain/ai-ui-react 1.0.49 → 1.0.52
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/AiChipLabel.d.ts.map +1 -1
- package/dist/components/AiChipLabel.js +27 -5
- package/dist/components/AiContextButton.d.ts.map +1 -1
- package/dist/components/AiContextButton.js +5 -3
- package/dist/components/AiImageButton.d.ts.map +1 -1
- package/dist/components/AiImageButton.js +5 -2
- package/dist/components/AiSelect.d.ts.map +1 -1
- package/dist/components/AiSelect.js +38 -2
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +24 -12
- package/dist/components/AiTextarea.d.ts.map +1 -1
- package/dist/components/AiTextarea.js +2 -2
- package/dist/components/LBApiKeySelector.d.ts.map +1 -1
- package/dist/components/LBApiKeySelector.js +21 -23
- package/dist/components/LBSigninModal.d.ts.map +1 -1
- package/dist/components/LBSigninModal.js +206 -115
- package/dist/context/LBAuthProvider.d.ts +5 -1
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +67 -0
- package/package.json +2 -2
- package/src/components/AiChipLabel.tsx +34 -5
- package/src/components/AiContextButton.tsx +9 -13
- package/src/components/AiImageButton.tsx +15 -12
- package/src/components/AiSelect.tsx +71 -1
- package/src/components/AiStatusButton.tsx +28 -15
- package/src/components/AiTextarea.tsx +2 -12
- package/src/components/LBApiKeySelector.tsx +21 -23
- package/src/components/LBSigninModal.tsx +278 -159
- package/src/context/LBAuthProvider.tsx +77 -3
- package/README.md +0 -147
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useState, useEffect } from "react";
|
|
4
4
|
import { useLB } from "../context/LBAuthProvider";
|
|
5
5
|
import { LBApiKeySelector } from "./LBApiKeySelector";
|
|
6
|
+
import { Mail, Lock, Sparkles, X, Loader2, AlertCircle } from "lucide-react";
|
|
6
7
|
export function LBSigninModal({ isOpen, onClose }) {
|
|
7
8
|
// Vérifier si LBProvider est disponible
|
|
8
9
|
let login;
|
|
@@ -90,187 +91,277 @@ export function LBSigninModal({ isOpen, onClose }) {
|
|
|
90
91
|
};
|
|
91
92
|
return (_jsxs("div", { style: {
|
|
92
93
|
position: "fixed",
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
top: 0,
|
|
95
|
+
left: 0,
|
|
96
|
+
right: 0,
|
|
97
|
+
bottom: 0,
|
|
98
|
+
width: "100vw",
|
|
99
|
+
height: "100vh",
|
|
100
|
+
backgroundColor: "rgba(0, 0, 0, 0.75)",
|
|
101
|
+
backdropFilter: "blur(12px)",
|
|
102
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
97
103
|
display: "flex",
|
|
98
104
|
alignItems: "center",
|
|
99
105
|
justifyContent: "center",
|
|
100
106
|
zIndex: 9999,
|
|
101
107
|
padding: "16px",
|
|
108
|
+
animation: "fadeIn 0.2s ease-out",
|
|
109
|
+
overflow: "auto",
|
|
102
110
|
}, onClick: onClose, onKeyDown: handleKeyDown, children: [_jsxs("div", { style: {
|
|
103
|
-
backgroundColor: "
|
|
104
|
-
borderRadius: "
|
|
105
|
-
boxShadow: "0
|
|
106
|
-
maxWidth: "
|
|
111
|
+
backgroundColor: "light-dark(#ffffff, #1e293b)",
|
|
112
|
+
borderRadius: "20px",
|
|
113
|
+
boxShadow: "0 0 0 1px rgba(139, 92, 246, 0.2), 0 20px 70px rgba(139, 92, 246, 0.25), 0 4px 6px rgba(0, 0, 0, 0.1)",
|
|
114
|
+
maxWidth: "440px",
|
|
107
115
|
width: "100%",
|
|
108
|
-
border: "1px solid
|
|
116
|
+
border: "1px solid light-dark(rgba(226, 232, 240, 0.8), rgba(139, 92, 246, 0.3))",
|
|
109
117
|
display: "flex",
|
|
110
118
|
flexDirection: "column",
|
|
111
|
-
maxHeight: "
|
|
119
|
+
maxHeight: "90vh",
|
|
112
120
|
overflow: "hidden",
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
121
|
+
position: "relative",
|
|
122
|
+
animation: "slideUp 0.3s ease-out",
|
|
123
|
+
}, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { style: {
|
|
124
|
+
position: "absolute",
|
|
125
|
+
top: 0,
|
|
126
|
+
left: 0,
|
|
127
|
+
right: 0,
|
|
128
|
+
height: "200px",
|
|
129
|
+
background: "radial-gradient(ellipse at top, rgba(139, 92, 246, 0.15), transparent 70%)",
|
|
130
|
+
pointerEvents: "none",
|
|
131
|
+
zIndex: 0,
|
|
132
|
+
} }), _jsxs("div", { style: {
|
|
133
|
+
padding: "32px 32px 24px",
|
|
116
134
|
display: "flex",
|
|
117
|
-
|
|
135
|
+
flexDirection: "column",
|
|
118
136
|
alignItems: "center",
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
137
|
+
gap: "16px",
|
|
138
|
+
position: "relative",
|
|
139
|
+
zIndex: 1,
|
|
140
|
+
}, children: [_jsx("div", { style: {
|
|
141
|
+
width: "64px",
|
|
142
|
+
height: "64px",
|
|
143
|
+
borderRadius: "16px",
|
|
144
|
+
background: "linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%)",
|
|
125
145
|
display: "flex",
|
|
126
146
|
alignItems: "center",
|
|
127
|
-
|
|
128
|
-
|
|
147
|
+
justifyContent: "center",
|
|
148
|
+
boxShadow: "0 8px 24px rgba(139, 92, 246, 0.3)",
|
|
149
|
+
animation: "pulse 2s ease-in-out infinite",
|
|
150
|
+
}, children: _jsx(Sparkles, { size: 32, color: "#ffffff", strokeWidth: 2.5 }) }), _jsxs("div", { style: { textAlign: "center" }, children: [_jsx("h2", { style: {
|
|
151
|
+
margin: "0 0 8px 0",
|
|
152
|
+
fontSize: "24px",
|
|
153
|
+
fontWeight: 700,
|
|
154
|
+
color: "light-dark(#1e293b, #f8fafc)",
|
|
155
|
+
letterSpacing: "-0.02em",
|
|
156
|
+
}, children: "Connexion LastBrain" }), _jsx("p", { style: {
|
|
157
|
+
margin: 0,
|
|
158
|
+
fontSize: "14px",
|
|
159
|
+
color: "light-dark(#64748b, #94a3b8)",
|
|
160
|
+
fontWeight: 400,
|
|
161
|
+
}, children: "Acc\u00E9dez \u00E0 vos outils d'intelligence artificielle" })] }), _jsx("button", { onClick: onClose, style: {
|
|
162
|
+
position: "absolute",
|
|
163
|
+
top: "24px",
|
|
164
|
+
right: "24px",
|
|
129
165
|
background: "transparent",
|
|
130
166
|
border: "none",
|
|
131
|
-
color: "
|
|
167
|
+
color: "light-dark(#64748b, #94a3b8)",
|
|
132
168
|
cursor: "pointer",
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
padding: "4px 8px",
|
|
136
|
-
borderRadius: "6px",
|
|
169
|
+
padding: "8px",
|
|
170
|
+
borderRadius: "10px",
|
|
137
171
|
transition: "all 0.2s ease",
|
|
172
|
+
display: "flex",
|
|
173
|
+
alignItems: "center",
|
|
174
|
+
justifyContent: "center",
|
|
138
175
|
}, onMouseEnter: (e) => {
|
|
139
176
|
e.currentTarget.style.background =
|
|
140
|
-
"
|
|
141
|
-
e.currentTarget.style.color = "
|
|
177
|
+
"light-dark(rgba(100, 116, 139, 0.1), rgba(148, 163, 184, 0.15))";
|
|
178
|
+
e.currentTarget.style.color = "light-dark(#1e293b, #f8fafc)";
|
|
142
179
|
}, onMouseLeave: (e) => {
|
|
143
180
|
e.currentTarget.style.background = "transparent";
|
|
144
|
-
e.currentTarget.style.color = "
|
|
145
|
-
}, "aria-label": "Close", children:
|
|
146
|
-
padding: "
|
|
181
|
+
e.currentTarget.style.color = "light-dark(#64748b, #94a3b8)";
|
|
182
|
+
}, "aria-label": "Close", children: _jsx(X, { size: 20, strokeWidth: 2 }) })] }), _jsx("div", { style: {
|
|
183
|
+
padding: "0 32px 32px",
|
|
147
184
|
overflow: "auto",
|
|
148
185
|
flex: 1,
|
|
149
|
-
|
|
150
|
-
|
|
186
|
+
position: "relative",
|
|
187
|
+
zIndex: 1,
|
|
188
|
+
}, children: _jsxs("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: "20px" }, children: [_jsxs("div", { children: [_jsxs("label", { style: {
|
|
189
|
+
display: "flex",
|
|
190
|
+
alignItems: "center",
|
|
191
|
+
gap: "8px",
|
|
151
192
|
fontSize: "13px",
|
|
152
193
|
fontWeight: 600,
|
|
153
|
-
color: "
|
|
154
|
-
marginBottom: "
|
|
155
|
-
letterSpacing: "0.02em",
|
|
156
|
-
}, children: "\uD83D\uDCE7 Email" }), _jsx("input", { type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, autoFocus: true, autoComplete: "email", placeholder: "votre@email.com", style: {
|
|
157
|
-
width: "100%",
|
|
158
|
-
padding: "10px 12px",
|
|
159
|
-
fontSize: "14px",
|
|
160
|
-
border: "1px solid var(--ai-border-primary, #374151)",
|
|
161
|
-
borderRadius: "8px",
|
|
162
|
-
background: "var(--ai-bg-secondary, #111827)",
|
|
163
|
-
color: "var(--ai-text-primary, #f9fafb)",
|
|
164
|
-
outline: "none",
|
|
165
|
-
transition: "all 0.2s ease",
|
|
194
|
+
color: "light-dark(#1e293b, #f8fafc)",
|
|
195
|
+
marginBottom: "10px",
|
|
166
196
|
letterSpacing: "0.01em",
|
|
167
|
-
},
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
"
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
"
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
197
|
+
}, children: [_jsx(Mail, { size: 16, strokeWidth: 2.5 }), "Email"] }), _jsx("div", { style: { position: "relative" }, children: _jsx("input", { type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, autoFocus: true, autoComplete: "email", placeholder: "votre@email.com", style: {
|
|
198
|
+
width: "100%",
|
|
199
|
+
padding: "14px 16px",
|
|
200
|
+
fontSize: "15px",
|
|
201
|
+
border: "2px solid light-dark(#e2e8f0, #334155)",
|
|
202
|
+
borderRadius: "12px",
|
|
203
|
+
background: "light-dark(#f8fafc, #0f172a)",
|
|
204
|
+
color: "light-dark(#1e293b, #f8fafc)",
|
|
205
|
+
outline: "none",
|
|
206
|
+
transition: "all 0.2s ease",
|
|
207
|
+
fontWeight: 500,
|
|
208
|
+
}, onFocus: (e) => {
|
|
209
|
+
e.currentTarget.style.borderColor =
|
|
210
|
+
"rgba(139, 92, 246, 0.6)";
|
|
211
|
+
e.currentTarget.style.boxShadow =
|
|
212
|
+
"0 0 0 4px rgba(139, 92, 246, 0.15)";
|
|
213
|
+
e.currentTarget.style.background =
|
|
214
|
+
"light-dark(#ffffff, #1e293b)";
|
|
215
|
+
}, onBlur: (e) => {
|
|
216
|
+
e.currentTarget.style.borderColor =
|
|
217
|
+
"light-dark(#e2e8f0, #334155)";
|
|
218
|
+
e.currentTarget.style.boxShadow = "none";
|
|
219
|
+
e.currentTarget.style.background =
|
|
220
|
+
"light-dark(#f8fafc, #0f172a)";
|
|
221
|
+
} }) })] }), _jsxs("div", { children: [_jsxs("label", { style: {
|
|
222
|
+
display: "flex",
|
|
223
|
+
alignItems: "center",
|
|
224
|
+
gap: "8px",
|
|
177
225
|
fontSize: "13px",
|
|
178
226
|
fontWeight: 600,
|
|
179
|
-
color: "
|
|
180
|
-
marginBottom: "
|
|
181
|
-
letterSpacing: "0.
|
|
182
|
-
}, children: "
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
e
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
227
|
+
color: "light-dark(#1e293b, #f8fafc)",
|
|
228
|
+
marginBottom: "10px",
|
|
229
|
+
letterSpacing: "0.01em",
|
|
230
|
+
}, children: [_jsx(Lock, { size: 16, strokeWidth: 2.5 }), "Mot de passe"] }), _jsx("div", { style: { position: "relative" }, children: _jsx("input", { type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", style: {
|
|
231
|
+
width: "100%",
|
|
232
|
+
padding: "14px 16px",
|
|
233
|
+
fontSize: "15px",
|
|
234
|
+
border: "2px solid light-dark(#e2e8f0, #334155)",
|
|
235
|
+
borderRadius: "12px",
|
|
236
|
+
background: "light-dark(#f8fafc, #0f172a)",
|
|
237
|
+
color: "light-dark(#1e293b, #f8fafc)",
|
|
238
|
+
outline: "none",
|
|
239
|
+
transition: "all 0.2s ease",
|
|
240
|
+
letterSpacing: "0.15em",
|
|
241
|
+
fontWeight: 500,
|
|
242
|
+
}, onFocus: (e) => {
|
|
243
|
+
e.currentTarget.style.borderColor =
|
|
244
|
+
"rgba(139, 92, 246, 0.6)";
|
|
245
|
+
e.currentTarget.style.boxShadow =
|
|
246
|
+
"0 0 0 4px rgba(139, 92, 246, 0.15)";
|
|
247
|
+
e.currentTarget.style.background =
|
|
248
|
+
"light-dark(#ffffff, #1e293b)";
|
|
249
|
+
}, onBlur: (e) => {
|
|
250
|
+
e.currentTarget.style.borderColor =
|
|
251
|
+
"light-dark(#e2e8f0, #334155)";
|
|
252
|
+
e.currentTarget.style.boxShadow = "none";
|
|
253
|
+
e.currentTarget.style.background =
|
|
254
|
+
"light-dark(#f8fafc, #0f172a)";
|
|
255
|
+
} }) })] }), error && (_jsxs("div", { style: {
|
|
256
|
+
padding: "14px 16px",
|
|
203
257
|
background: "rgba(239, 68, 68, 0.1)",
|
|
204
|
-
border: "
|
|
205
|
-
borderRadius: "
|
|
206
|
-
color: "#
|
|
207
|
-
fontSize: "
|
|
258
|
+
border: "2px solid rgba(239, 68, 68, 0.35)",
|
|
259
|
+
borderRadius: "12px",
|
|
260
|
+
color: "light-dark(#dc2626, #fca5a5)",
|
|
261
|
+
fontSize: "14px",
|
|
208
262
|
display: "flex",
|
|
209
263
|
alignItems: "start",
|
|
210
|
-
gap: "
|
|
211
|
-
|
|
264
|
+
gap: "12px",
|
|
265
|
+
animation: "shake 0.4s ease",
|
|
266
|
+
}, children: [_jsx(AlertCircle, { size: 20, style: { flexShrink: 0, marginTop: "2px" }, strokeWidth: 2.5 }), _jsx("span", { style: { flex: 1, lineHeight: "1.5", fontWeight: 500 }, children: error })] })), _jsx("button", { type: "submit", disabled: loading, style: {
|
|
212
267
|
width: "100%",
|
|
213
|
-
padding: "
|
|
214
|
-
fontSize: "
|
|
215
|
-
fontWeight:
|
|
268
|
+
padding: "16px",
|
|
269
|
+
fontSize: "15px",
|
|
270
|
+
fontWeight: 700,
|
|
216
271
|
color: "#ffffff",
|
|
217
272
|
background: loading
|
|
218
|
-
? "
|
|
273
|
+
? "light-dark(#cbd5e1, #475569)"
|
|
219
274
|
: "linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%)",
|
|
220
275
|
border: "none",
|
|
221
|
-
borderRadius: "
|
|
276
|
+
borderRadius: "12px",
|
|
222
277
|
cursor: loading ? "not-allowed" : "pointer",
|
|
223
278
|
transition: "all 0.2s ease",
|
|
224
279
|
display: "flex",
|
|
225
280
|
alignItems: "center",
|
|
226
281
|
justifyContent: "center",
|
|
227
|
-
gap: "
|
|
228
|
-
letterSpacing: "0.
|
|
282
|
+
gap: "10px",
|
|
283
|
+
letterSpacing: "0.01em",
|
|
229
284
|
opacity: loading ? 0.6 : 1,
|
|
285
|
+
boxShadow: loading
|
|
286
|
+
? "none"
|
|
287
|
+
: "0 4px 14px rgba(139, 92, 246, 0.4)",
|
|
230
288
|
}, onMouseEnter: (e) => {
|
|
231
289
|
if (!loading) {
|
|
232
|
-
e.currentTarget.style.transform = "translateY(-
|
|
290
|
+
e.currentTarget.style.transform = "translateY(-2px)";
|
|
233
291
|
e.currentTarget.style.boxShadow =
|
|
234
|
-
"0
|
|
292
|
+
"0 8px 24px rgba(139, 92, 246, 0.6)";
|
|
235
293
|
}
|
|
236
294
|
}, onMouseLeave: (e) => {
|
|
237
295
|
e.currentTarget.style.transform = "translateY(0)";
|
|
238
|
-
e.currentTarget.style.boxShadow =
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
width: "16px",
|
|
242
|
-
height: "16px",
|
|
243
|
-
}, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4", opacity: "0.25" }), _jsx("path", { d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z", fill: "currentColor", opacity: "0.75" })] }), "Connexion en cours..."] })) : (_jsxs(_Fragment, { children: [_jsx("span", { children: "\uD83D\uDE80" }), "Se connecter"] })) }), _jsxs("div", { style: {
|
|
296
|
+
e.currentTarget.style.boxShadow =
|
|
297
|
+
"0 4px 14px rgba(139, 92, 246, 0.4)";
|
|
298
|
+
}, children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 20, strokeWidth: 2.5, style: { animation: "spin 1s linear infinite" } }), "Connexion en cours..."] })) : (_jsxs(_Fragment, { children: [_jsx(Sparkles, { size: 20, strokeWidth: 2.5 }), "Se connecter"] })) }), _jsxs("div", { style: {
|
|
244
299
|
marginTop: "8px",
|
|
245
|
-
padding: "
|
|
300
|
+
padding: "20px",
|
|
246
301
|
background: "rgba(139, 92, 246, 0.05)",
|
|
247
302
|
border: "1px solid rgba(139, 92, 246, 0.2)",
|
|
248
|
-
borderRadius: "
|
|
303
|
+
borderRadius: "16px",
|
|
249
304
|
textAlign: "center",
|
|
250
305
|
}, children: [_jsx("p", { style: {
|
|
251
|
-
margin: "0 0
|
|
252
|
-
fontSize: "
|
|
253
|
-
color: "
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
306
|
+
margin: "0 0 14px 0",
|
|
307
|
+
fontSize: "14px",
|
|
308
|
+
color: "light-dark(#64748b, #94a3b8)",
|
|
309
|
+
fontWeight: 500,
|
|
310
|
+
}, children: "Pas encore de compte ?" }), _jsxs("a", { href: "https://lastbrain.io/signup", target: "_blank", rel: "noopener noreferrer", style: {
|
|
311
|
+
display: "inline-flex",
|
|
312
|
+
alignItems: "center",
|
|
313
|
+
gap: "8px",
|
|
314
|
+
padding: "10px 20px",
|
|
315
|
+
fontSize: "14px",
|
|
258
316
|
fontWeight: 600,
|
|
259
317
|
color: "#8b5cf6",
|
|
260
318
|
textDecoration: "none",
|
|
261
|
-
border: "
|
|
262
|
-
borderRadius: "
|
|
319
|
+
border: "2px solid rgba(139, 92, 246, 0.3)",
|
|
320
|
+
borderRadius: "10px",
|
|
263
321
|
transition: "all 0.2s ease",
|
|
264
322
|
}, onMouseEnter: (e) => {
|
|
265
323
|
e.currentTarget.style.background = "rgba(139, 92, 246, 0.1)";
|
|
266
|
-
e.currentTarget.style.borderColor = "
|
|
324
|
+
e.currentTarget.style.borderColor = "rgba(139, 92, 246, 0.5)";
|
|
325
|
+
e.currentTarget.style.transform = "translateY(-1px)";
|
|
267
326
|
}, onMouseLeave: (e) => {
|
|
268
327
|
e.currentTarget.style.background = "transparent";
|
|
269
328
|
e.currentTarget.style.borderColor = "rgba(139, 92, 246, 0.3)";
|
|
270
|
-
|
|
329
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
330
|
+
}, children: [_jsx(Sparkles, { size: 16, strokeWidth: 2.5 }), "Cr\u00E9er un compte gratuitement"] })] })] }) })] }), _jsx("style", { children: `
|
|
331
|
+
@keyframes fadeIn {
|
|
332
|
+
from { opacity: 0; }
|
|
333
|
+
to { opacity: 1; }
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
@keyframes slideUp {
|
|
337
|
+
from {
|
|
338
|
+
opacity: 0;
|
|
339
|
+
transform: translateY(20px) scale(0.95);
|
|
340
|
+
}
|
|
341
|
+
to {
|
|
342
|
+
opacity: 1;
|
|
343
|
+
transform: translateY(0) scale(1);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
271
347
|
@keyframes spin {
|
|
272
348
|
from { transform: rotate(0deg); }
|
|
273
349
|
to { transform: rotate(360deg); }
|
|
274
350
|
}
|
|
351
|
+
|
|
352
|
+
@keyframes pulse {
|
|
353
|
+
0%, 100% {
|
|
354
|
+
box-shadow: 0 8px 24px rgba(139, 92, 246, 0.3);
|
|
355
|
+
}
|
|
356
|
+
50% {
|
|
357
|
+
box-shadow: 0 8px 32px rgba(139, 92, 246, 0.5);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
@keyframes shake {
|
|
362
|
+
0%, 100% { transform: translateX(0); }
|
|
363
|
+
25% { transform: translateX(-8px); }
|
|
364
|
+
75% { transform: translateX(8px); }
|
|
365
|
+
}
|
|
275
366
|
` })] }));
|
|
276
367
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Gère l'état de connexion, la session et les appels IA
|
|
4
4
|
*/
|
|
5
5
|
import { type ReactNode } from "react";
|
|
6
|
-
import type { LBAuthState, LBApiKey } from "@lastbrain/ai-ui-core";
|
|
6
|
+
import type { LBAuthState, LBApiKey, AiStatus } from "@lastbrain/ai-ui-core";
|
|
7
7
|
interface LBProviderProps {
|
|
8
8
|
children: ReactNode;
|
|
9
9
|
/** URL de l'API LastBrain (ex: https://api.lastbrain.io) */
|
|
@@ -36,6 +36,10 @@ interface LBContextValue extends LBAuthState {
|
|
|
36
36
|
apiKeys: LBApiKey[];
|
|
37
37
|
/** Access token temporaire (après login) */
|
|
38
38
|
accessToken?: string;
|
|
39
|
+
/** Status API (balance, storage, API key info) */
|
|
40
|
+
apiStatus: AiStatus | null;
|
|
41
|
+
/** Fonction pour rafraîchir le status */
|
|
42
|
+
refreshStatus: () => Promise<void>;
|
|
39
43
|
}
|
|
40
44
|
export declare function LBProvider({ children, baseUrl: _baseUrl, proxyUrl, onStatusChange, onAuthChange, }: LBProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
41
45
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,
|
|
1
|
+
{"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAIR,QAAQ,EACT,MAAM,uBAAuB,CAAC;AAE/B,UAAU,eAAe;IACvB,QAAQ,EAAE,SAAS,CAAC;IACpB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IACzD,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,UAAU,cAAe,SAAQ,WAAW;IAC1C,4BAA4B;IAC5B,KAAK,EAAE,CACL,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC;QACX,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;KAC7B,CAAC,CAAC;IACH,8BAA8B;IAC9B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,6CAA6C;IAC7C,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC3D,gEAAgE;IAChE,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,mDAAmD;IACnD,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,oCAAoC;IACpC,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,2BAA2B;IAC3B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,yCAAyC;IACzC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAID,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAO,EAAE,QAA2B,EACpC,QAA2B,EAC3B,cAAc,EACd,YAAY,GACb,EAAE,eAAe,2CAkbjB;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,cAAc,CAMtC"}
|
|
@@ -12,6 +12,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
12
12
|
});
|
|
13
13
|
const [apiKeys, setApiKeys] = useState([]);
|
|
14
14
|
const [accessToken, setAccessToken] = useState();
|
|
15
|
+
const [apiStatus, setApiStatus] = useState(null);
|
|
15
16
|
/**
|
|
16
17
|
* Vérifie si une session existe au chargement
|
|
17
18
|
*/
|
|
@@ -290,6 +291,70 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
290
291
|
const refreshSession = useCallback(async () => {
|
|
291
292
|
await checkSession();
|
|
292
293
|
}, [checkSession]);
|
|
294
|
+
/**
|
|
295
|
+
* Récupère le status API (balance, storage, API key info)
|
|
296
|
+
*/
|
|
297
|
+
const refreshStatus = useCallback(async () => {
|
|
298
|
+
if (state.status !== "ready") {
|
|
299
|
+
setApiStatus(null);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
const response = await fetch(`${proxyUrl}/auth/status`, {
|
|
304
|
+
credentials: "include",
|
|
305
|
+
});
|
|
306
|
+
if (response.ok) {
|
|
307
|
+
const data = await response.json();
|
|
308
|
+
setApiStatus(data);
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
setApiStatus(null);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
console.error("[LBProvider] Failed to fetch status:", error);
|
|
316
|
+
setApiStatus(null);
|
|
317
|
+
}
|
|
318
|
+
}, [proxyUrl, state.status]);
|
|
319
|
+
/**
|
|
320
|
+
* Récupère les clés API avec la session active
|
|
321
|
+
*/
|
|
322
|
+
const fetchApiKeysWithSession = useCallback(async () => {
|
|
323
|
+
if (state.status !== "ready") {
|
|
324
|
+
setApiKeys([]);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
console.log("[LBProvider] Fetching API keys with session...");
|
|
329
|
+
const response = await fetch(`${proxyUrl}/auth/api-keys`, {
|
|
330
|
+
credentials: "include",
|
|
331
|
+
});
|
|
332
|
+
if (response.ok) {
|
|
333
|
+
const data = await response.json();
|
|
334
|
+
console.log("[LBProvider] API keys received:", data);
|
|
335
|
+
setApiKeys(data.apiKeys || []);
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
console.warn("[LBProvider] Failed to fetch API keys:", response.status);
|
|
339
|
+
setApiKeys([]);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
console.error("[LBProvider] Failed to fetch API keys:", error);
|
|
344
|
+
setApiKeys([]);
|
|
345
|
+
}
|
|
346
|
+
}, [proxyUrl, state.status]);
|
|
347
|
+
// Refresh status quand la session devient ready
|
|
348
|
+
useEffect(() => {
|
|
349
|
+
if (state.status === "ready") {
|
|
350
|
+
refreshStatus();
|
|
351
|
+
fetchApiKeysWithSession(); // Also fetch API keys list
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
setApiStatus(null);
|
|
355
|
+
setApiKeys([]);
|
|
356
|
+
}
|
|
357
|
+
}, [state.status, refreshStatus, fetchApiKeysWithSession]);
|
|
293
358
|
const value = {
|
|
294
359
|
...state,
|
|
295
360
|
login,
|
|
@@ -300,6 +365,8 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
300
365
|
refreshSession,
|
|
301
366
|
apiKeys,
|
|
302
367
|
accessToken,
|
|
368
|
+
apiStatus,
|
|
369
|
+
refreshStatus,
|
|
303
370
|
};
|
|
304
371
|
return _jsx(LBContext.Provider, { value: value, children: children });
|
|
305
372
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lastbrain/ai-ui-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.52",
|
|
4
4
|
"description": "Headless React components for LastBrain AI UI Kit",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"lucide-react": "^0.257.0",
|
|
51
|
-
"@lastbrain/ai-ui-core": "1.0.
|
|
51
|
+
"@lastbrain/ai-ui-core": "1.0.41"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/react": "^19.2.0",
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import React, { useState, useRef, KeyboardEvent } from "react";
|
|
4
|
-
import { X, Sparkles } from "lucide-react";
|
|
4
|
+
import { X, Sparkles, Lock } from "lucide-react";
|
|
5
5
|
import { aiStyles } from "../styles/inline";
|
|
6
6
|
import { AiPromptPanel } from "./AiPromptPanel";
|
|
7
|
+
import { LBSigninModal } from "./LBSigninModal";
|
|
7
8
|
import { useAiCallText } from "../hooks/useAiCallText";
|
|
8
9
|
import { useAiModels } from "../hooks/useAiModels";
|
|
9
10
|
import { useAiContext } from "../context/AiProvider";
|
|
11
|
+
import { useLB } from "../context/LBAuthProvider";
|
|
10
12
|
import { handleAIError } from "../utils/errorHandler";
|
|
11
13
|
|
|
12
14
|
export interface AiChipLabelProps {
|
|
@@ -85,6 +87,7 @@ export function AiChipInput({
|
|
|
85
87
|
}: AiChipInputProps) {
|
|
86
88
|
const [inputValue, setInputValue] = useState("");
|
|
87
89
|
const [showPromptPanel, setShowPromptPanel] = useState(false);
|
|
90
|
+
const [showSigninModal, setShowSigninModal] = useState(false);
|
|
88
91
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
89
92
|
|
|
90
93
|
// Récupérer le contexte AiProvider avec fallback sur les props
|
|
@@ -92,6 +95,16 @@ export function AiChipInput({
|
|
|
92
95
|
const baseUrl = propBaseUrl ?? aiContext.baseUrl;
|
|
93
96
|
const apiKeyId = propApiKeyId ?? aiContext.apiKeyId;
|
|
94
97
|
|
|
98
|
+
// Vérifier si l'utilisateur est connecté (session LB)
|
|
99
|
+
let isAuthenticated = false;
|
|
100
|
+
try {
|
|
101
|
+
const lbContext = useLB();
|
|
102
|
+
isAuthenticated = lbContext.status === "ready";
|
|
103
|
+
} catch {
|
|
104
|
+
// LBProvider n'est pas disponible, considérer non connecté
|
|
105
|
+
isAuthenticated = false;
|
|
106
|
+
}
|
|
107
|
+
|
|
95
108
|
// Hooks pour l'IA avec les valeurs du contexte
|
|
96
109
|
const { models } = useAiModels({
|
|
97
110
|
baseUrl,
|
|
@@ -205,7 +218,13 @@ Exemple de réponse attendue: javascript, react, frontend, api, development`;
|
|
|
205
218
|
}}
|
|
206
219
|
/>
|
|
207
220
|
<button
|
|
208
|
-
onClick={
|
|
221
|
+
onClick={() => {
|
|
222
|
+
if (isAuthenticated) {
|
|
223
|
+
handleGenerateChips();
|
|
224
|
+
} else {
|
|
225
|
+
setShowSigninModal(true);
|
|
226
|
+
}
|
|
227
|
+
}}
|
|
209
228
|
style={{
|
|
210
229
|
position: "absolute",
|
|
211
230
|
right: "8px",
|
|
@@ -218,11 +237,15 @@ Exemple de réponse attendue: javascript, react, frontend, api, development`;
|
|
|
218
237
|
borderRadius: "4px",
|
|
219
238
|
display: "flex",
|
|
220
239
|
alignItems: "center",
|
|
221
|
-
color: "#6366f1",
|
|
240
|
+
color: isAuthenticated ? "#6366f1" : "#ef4444",
|
|
222
241
|
}}
|
|
223
|
-
title=
|
|
242
|
+
title={
|
|
243
|
+
isAuthenticated
|
|
244
|
+
? "Générer des tags avec l'IA"
|
|
245
|
+
: "Se connecter pour utiliser l'IA"
|
|
246
|
+
}
|
|
224
247
|
>
|
|
225
|
-
<Sparkles size={16} />
|
|
248
|
+
{isAuthenticated ? <Sparkles size={16} /> : <Lock size={16} />}
|
|
226
249
|
</button>
|
|
227
250
|
</div>
|
|
228
251
|
|
|
@@ -274,6 +297,12 @@ Exemple de réponse attendue: javascript, react, frontend, api, development`;
|
|
|
274
297
|
baseUrl={baseUrl}
|
|
275
298
|
sourceText={context ? `Contexte: ${context}` : undefined}
|
|
276
299
|
/>
|
|
300
|
+
|
|
301
|
+
{/* Modal signin pour les utilisateurs non connectés */}
|
|
302
|
+
<LBSigninModal
|
|
303
|
+
isOpen={showSigninModal}
|
|
304
|
+
onClose={() => setShowSigninModal(false)}
|
|
305
|
+
/>
|
|
277
306
|
</div>
|
|
278
307
|
);
|
|
279
308
|
}
|