@lastbrain/ai-ui-react 1.0.67 → 1.0.69
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 +8 -3
- package/dist/components/AiChipLabel.d.ts.map +1 -1
- package/dist/components/AiChipLabel.js +21 -70
- package/dist/components/AiContextButton.d.ts +5 -1
- package/dist/components/AiContextButton.d.ts.map +1 -1
- package/dist/components/AiContextButton.js +67 -291
- package/dist/components/AiImageButton.d.ts +5 -1
- package/dist/components/AiImageButton.d.ts.map +1 -1
- package/dist/components/AiImageButton.js +6 -142
- package/dist/components/AiInput.d.ts +5 -3
- package/dist/components/AiInput.d.ts.map +1 -1
- package/dist/components/AiInput.js +13 -25
- package/dist/components/AiPromptPanel.d.ts.map +1 -1
- package/dist/components/AiPromptPanel.js +58 -212
- package/dist/components/AiSelect.d.ts +5 -3
- package/dist/components/AiSelect.d.ts.map +1 -1
- package/dist/components/AiSelect.js +21 -30
- package/dist/components/AiStatusButton.d.ts +4 -1
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +198 -626
- package/dist/components/AiTextarea.d.ts +4 -2
- package/dist/components/AiTextarea.d.ts.map +1 -1
- package/dist/components/AiTextarea.js +14 -26
- package/dist/components/LBApiKeySelector.d.ts.map +1 -1
- package/dist/components/LBApiKeySelector.js +5 -166
- package/dist/components/LBConnectButton.d.ts +4 -7
- package/dist/components/LBConnectButton.d.ts.map +1 -1
- package/dist/components/LBConnectButton.js +17 -86
- package/dist/components/LBSigninModal.d.ts +1 -1
- package/dist/components/LBSigninModal.d.ts.map +1 -1
- package/dist/components/LBSigninModal.js +42 -320
- package/dist/examples/AiUiPremiumShowcase.d.ts +2 -0
- package/dist/examples/AiUiPremiumShowcase.d.ts.map +1 -0
- package/dist/examples/AiUiPremiumShowcase.js +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/styles/inline.d.ts +1 -0
- package/dist/styles/inline.d.ts.map +1 -1
- package/dist/styles/inline.js +25 -129
- package/dist/styles.css +1268 -369
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/AiChipLabel.tsx +64 -101
- package/src/components/AiContextButton.tsx +138 -430
- package/src/components/AiImageButton.tsx +29 -190
- package/src/components/AiInput.tsx +49 -74
- package/src/components/AiPromptPanel.tsx +71 -254
- package/src/components/AiSelect.tsx +61 -69
- package/src/components/AiStatusButton.tsx +477 -1219
- package/src/components/AiTextarea.tsx +49 -64
- package/src/components/LBApiKeySelector.tsx +86 -274
- package/src/components/LBConnectButton.tsx +46 -334
- package/src/components/LBSigninModal.tsx +140 -481
- package/src/examples/AiUiPremiumShowcase.tsx +91 -0
- package/src/index.ts +3 -0
- package/src/styles/inline.ts +27 -148
- package/src/styles.css +1268 -369
- package/src/types.ts +3 -0
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
Lock,
|
|
11
11
|
} from "lucide-react";
|
|
12
12
|
import type { BaseAiProps } from "../types";
|
|
13
|
+
import type { AiRadius, AiSize, AiVariant } from "../types";
|
|
13
14
|
import { useAiCallImage } from "../hooks/useAiCallImage";
|
|
14
15
|
import { AiPromptPanel } from "./AiPromptPanel";
|
|
15
16
|
import { useUsageToast } from "./UsageToast";
|
|
16
17
|
import { useErrorToast, ErrorToast } from "./ErrorToast";
|
|
17
|
-
import { aiStyles } from "../styles/inline";
|
|
18
18
|
import { useAiContext } from "../context/AiProvider";
|
|
19
19
|
import { handleAIError } from "../utils/errorHandler";
|
|
20
20
|
import { useLB } from "../context/LBAuthProvider";
|
|
@@ -36,6 +36,9 @@ export interface AiImageButtonProps
|
|
|
36
36
|
// Props optionnelles pour override du contexte
|
|
37
37
|
baseUrl?: string;
|
|
38
38
|
apiKeyId?: string;
|
|
39
|
+
size?: AiSize;
|
|
40
|
+
radius?: AiRadius;
|
|
41
|
+
variant?: AiVariant;
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
export function AiImageButton({
|
|
@@ -54,6 +57,9 @@ export function AiImageButton({
|
|
|
54
57
|
onImageSave,
|
|
55
58
|
storeOutputs,
|
|
56
59
|
artifactTitle,
|
|
60
|
+
size = "md",
|
|
61
|
+
radius = "full",
|
|
62
|
+
variant = "default",
|
|
57
63
|
...buttonProps
|
|
58
64
|
}: AiImageButtonProps) {
|
|
59
65
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -121,45 +127,6 @@ export function AiImageButton({
|
|
|
121
127
|
setGeneratedImage(null);
|
|
122
128
|
};
|
|
123
129
|
|
|
124
|
-
// Styles selon le thème
|
|
125
|
-
const getThemeStyles = () => {
|
|
126
|
-
// Détection automatique du thème comme dans les autres composants
|
|
127
|
-
const isDark =
|
|
128
|
-
typeof document !== "undefined" &&
|
|
129
|
-
(document.documentElement.classList.contains("dark") ||
|
|
130
|
-
(!document.documentElement.classList.contains("light") &&
|
|
131
|
-
window.matchMedia("(prefers-color-scheme: dark)").matches));
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
card: {
|
|
135
|
-
backgroundColor: isDark ? "#1f2937" : "white",
|
|
136
|
-
border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`,
|
|
137
|
-
color: isDark ? "#f3f4f6" : "#374151",
|
|
138
|
-
},
|
|
139
|
-
header: {
|
|
140
|
-
color: isDark ? "#f9fafb" : "#1f2937",
|
|
141
|
-
},
|
|
142
|
-
closeButton: {
|
|
143
|
-
color: isDark ? "#9ca3af" : "#6b7280",
|
|
144
|
-
hoverColor: isDark ? "#d1d5db" : "#374151",
|
|
145
|
-
},
|
|
146
|
-
imageContainer: {
|
|
147
|
-
backgroundColor: isDark ? "#111827" : "#f9fafb",
|
|
148
|
-
},
|
|
149
|
-
actionButton: {
|
|
150
|
-
backgroundColor: isDark ? "#374151" : "white",
|
|
151
|
-
border: `1px solid ${isDark ? "#4b5563" : "#e5e7eb"}`,
|
|
152
|
-
color: isDark ? "#d1d5db" : "#6b7280",
|
|
153
|
-
hoverBackground: isDark ? "#4b5563" : "#f3f4f6",
|
|
154
|
-
hoverColor: isDark ? "#f3f4f6" : "#1f2937",
|
|
155
|
-
},
|
|
156
|
-
metadata: {
|
|
157
|
-
borderTop: `1px solid ${isDark ? "#374151" : "#f3f4f6"}`,
|
|
158
|
-
color: isDark ? "#9ca3af" : "#6b7280",
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
};
|
|
162
|
-
|
|
163
130
|
const handleSubmit = async (
|
|
164
131
|
selectedModel: string,
|
|
165
132
|
selectedPrompt: string
|
|
@@ -216,107 +183,38 @@ export function AiImageButton({
|
|
|
216
183
|
}
|
|
217
184
|
};
|
|
218
185
|
|
|
186
|
+
const sizeClass = `ai-size-${size}`;
|
|
187
|
+
const radiusClass = `ai-radius-${radius}`;
|
|
188
|
+
const variantClass = variant === "light" ? "ai-btn--light" : "";
|
|
189
|
+
|
|
219
190
|
return (
|
|
220
191
|
<div className="flex items-start gap-4">
|
|
221
|
-
<div
|
|
192
|
+
<div className="relative inline-block ai-glow">
|
|
222
193
|
<button
|
|
223
194
|
{...buttonProps}
|
|
224
195
|
onClick={handleOpenPanel}
|
|
225
196
|
disabled={disabled || loading || !isAuthReady}
|
|
226
|
-
className={className}
|
|
227
|
-
style={
|
|
228
|
-
...aiStyles.button,
|
|
229
|
-
display: "flex",
|
|
230
|
-
alignItems: "center",
|
|
231
|
-
gap: "8px",
|
|
232
|
-
cursor:
|
|
233
|
-
disabled || loading || !isAuthReady ? "not-allowed" : "pointer",
|
|
234
|
-
opacity: disabled || loading || !isAuthReady ? 0.6 : 1,
|
|
235
|
-
backgroundColor: loading
|
|
236
|
-
? "#8b5cf6"
|
|
237
|
-
: !isAuthReady
|
|
238
|
-
? "#94a3b8"
|
|
239
|
-
: "#6366f1",
|
|
240
|
-
color: "white",
|
|
241
|
-
border: "none",
|
|
242
|
-
borderRadius: "12px",
|
|
243
|
-
padding: "12px 20px",
|
|
244
|
-
fontSize: "14px",
|
|
245
|
-
fontWeight: "600",
|
|
246
|
-
minWidth: "140px",
|
|
247
|
-
height: "44px",
|
|
248
|
-
transition: "all 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
|
|
249
|
-
boxShadow: loading
|
|
250
|
-
? "0 4px 12px rgba(139, 92, 246, 0.3)"
|
|
251
|
-
: "0 2px 8px rgba(99, 102, 241, 0.2)",
|
|
252
|
-
transform: "scale(1)",
|
|
253
|
-
...(loading && {
|
|
254
|
-
background: "linear-gradient(135deg, #6366f1, #8b5cf6)",
|
|
255
|
-
animation: "pulse 2s ease-in-out infinite",
|
|
256
|
-
}),
|
|
257
|
-
...buttonProps.style,
|
|
258
|
-
}}
|
|
259
|
-
onMouseEnter={(e) => {
|
|
260
|
-
if (!disabled && !loading && isAuthReady) {
|
|
261
|
-
e.currentTarget.style.transform = "scale(1.02)";
|
|
262
|
-
e.currentTarget.style.boxShadow =
|
|
263
|
-
"0 6px 16px rgba(99, 102, 241, 0.3)";
|
|
264
|
-
}
|
|
265
|
-
}}
|
|
266
|
-
onMouseLeave={(e) => {
|
|
267
|
-
if (!disabled && !loading && isAuthReady) {
|
|
268
|
-
e.currentTarget.style.transform = "scale(1)";
|
|
269
|
-
e.currentTarget.style.boxShadow = loading
|
|
270
|
-
? "0 4px 12px rgba(139, 92, 246, 0.3)"
|
|
271
|
-
: "0 2px 8px rgba(99, 102, 241, 0.2)";
|
|
272
|
-
}
|
|
273
|
-
}}
|
|
274
|
-
onMouseDown={(e) => {
|
|
275
|
-
if (!disabled && !loading && isAuthReady) {
|
|
276
|
-
e.currentTarget.style.transform = "scale(0.98)";
|
|
277
|
-
}
|
|
278
|
-
}}
|
|
279
|
-
onMouseUp={(e) => {
|
|
280
|
-
if (!disabled && !loading && isAuthReady) {
|
|
281
|
-
e.currentTarget.style.transform = "scale(1.02)";
|
|
282
|
-
}
|
|
283
|
-
}}
|
|
197
|
+
className={`ai-btn ai-image-btn ${variantClass} ${sizeClass} ${radiusClass} ${className || ""}`}
|
|
198
|
+
style={buttonProps.style}
|
|
284
199
|
data-ai-image-button
|
|
285
200
|
title={!isAuthReady ? "Authentication required" : "Générer une image"}
|
|
286
201
|
>
|
|
287
202
|
{loading ? (
|
|
288
203
|
<>
|
|
289
|
-
<Loader2
|
|
290
|
-
|
|
291
|
-
className="animate-spin"
|
|
292
|
-
style={{
|
|
293
|
-
color: "white",
|
|
294
|
-
filter: "drop-shadow(0 0 2px rgba(255,255,255,0.3))",
|
|
295
|
-
}}
|
|
296
|
-
/>
|
|
297
|
-
<span style={{ letterSpacing: "0.025em" }}>Génération...</span>
|
|
204
|
+
<Loader2 size={18} className="ai-spinner" />
|
|
205
|
+
<span className="ai-text-microtracking">Génération...</span>
|
|
298
206
|
</>
|
|
299
207
|
) : !isAuthReady ? (
|
|
300
208
|
<>
|
|
301
|
-
<Lock
|
|
302
|
-
|
|
303
|
-
style={{
|
|
304
|
-
color: "white",
|
|
305
|
-
filter: "drop-shadow(0 0 2px rgba(255,255,255,0.2))",
|
|
306
|
-
}}
|
|
307
|
-
/>
|
|
209
|
+
<Lock size={18} />
|
|
210
|
+
|
|
308
211
|
{children || <span>Connexion requise</span>}
|
|
309
212
|
</>
|
|
310
213
|
) : (
|
|
311
214
|
<>
|
|
312
|
-
<ImageIcon
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
color: "white",
|
|
316
|
-
filter: "drop-shadow(0 0 2px rgba(255,255,255,0.2))",
|
|
317
|
-
}}
|
|
318
|
-
/>
|
|
319
|
-
<span style={{ letterSpacing: "0.025em" }}>
|
|
215
|
+
<ImageIcon size={18} />
|
|
216
|
+
|
|
217
|
+
<span className="ai-text-microtracking">
|
|
320
218
|
{children || "Générer une image"}
|
|
321
219
|
</span>
|
|
322
220
|
</>
|
|
@@ -339,24 +237,11 @@ export function AiImageButton({
|
|
|
339
237
|
|
|
340
238
|
{/* Card d'affichage de l'image générée */}
|
|
341
239
|
{showImageCard && generatedImage && (
|
|
342
|
-
<div
|
|
343
|
-
className="relative"
|
|
344
|
-
style={{
|
|
345
|
-
maxWidth: "320px",
|
|
346
|
-
borderRadius: "12px",
|
|
347
|
-
padding: "16px",
|
|
348
|
-
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
|
|
349
|
-
...getThemeStyles().card,
|
|
350
|
-
}}
|
|
351
|
-
>
|
|
240
|
+
<div className="ai-surface ai-image-card relative">
|
|
352
241
|
{/* Header avec prompt et bouton fermer */}
|
|
353
242
|
<div className="flex items-start justify-between mb-3">
|
|
354
243
|
<h3
|
|
355
|
-
className="font-medium text-sm leading-tight"
|
|
356
|
-
style={{
|
|
357
|
-
maxWidth: "calc(100% - 32px)",
|
|
358
|
-
...getThemeStyles().header,
|
|
359
|
-
}}
|
|
244
|
+
className="font-medium text-sm leading-tight max-w-[calc(100%-32px)]"
|
|
360
245
|
title={generatedImage.prompt}
|
|
361
246
|
>
|
|
362
247
|
{generatedImage.prompt.length > 60
|
|
@@ -365,42 +250,18 @@ export function AiImageButton({
|
|
|
365
250
|
</h3>
|
|
366
251
|
<button
|
|
367
252
|
onClick={handleCloseImage}
|
|
368
|
-
className="
|
|
369
|
-
style={{
|
|
370
|
-
padding: "2px",
|
|
371
|
-
borderRadius: "4px",
|
|
372
|
-
backgroundColor: "transparent",
|
|
373
|
-
border: "none",
|
|
374
|
-
cursor: "pointer",
|
|
375
|
-
color: getThemeStyles().closeButton.color,
|
|
376
|
-
}}
|
|
377
|
-
onMouseEnter={(e) => {
|
|
378
|
-
e.currentTarget.style.color =
|
|
379
|
-
getThemeStyles().closeButton.hoverColor;
|
|
380
|
-
}}
|
|
381
|
-
onMouseLeave={(e) => {
|
|
382
|
-
e.currentTarget.style.color =
|
|
383
|
-
getThemeStyles().closeButton.color;
|
|
384
|
-
}}
|
|
253
|
+
className="ai-icon-btn flex-shrink-0"
|
|
385
254
|
>
|
|
386
255
|
<X size={16} />
|
|
387
256
|
</button>
|
|
388
257
|
</div>
|
|
389
258
|
|
|
390
259
|
{/* Image */}
|
|
391
|
-
<div
|
|
392
|
-
className="mb-4 rounded-lg overflow-hidden"
|
|
393
|
-
style={getThemeStyles().imageContainer}
|
|
394
|
-
>
|
|
260
|
+
<div className="ai-image-frame">
|
|
395
261
|
<img
|
|
396
262
|
src={generatedImage.url}
|
|
397
263
|
alt={generatedImage.prompt}
|
|
398
|
-
className="
|
|
399
|
-
style={{
|
|
400
|
-
maxHeight: "200px",
|
|
401
|
-
objectFit: "contain",
|
|
402
|
-
display: "block",
|
|
403
|
-
}}
|
|
264
|
+
className="ai-image-preview"
|
|
404
265
|
/>
|
|
405
266
|
</div>
|
|
406
267
|
|
|
@@ -408,24 +269,7 @@ export function AiImageButton({
|
|
|
408
269
|
<div className="flex items-center gap-2 flex-wrap">
|
|
409
270
|
<button
|
|
410
271
|
onClick={handleDownload}
|
|
411
|
-
className="
|
|
412
|
-
style={{
|
|
413
|
-
backgroundColor: "#10b981",
|
|
414
|
-
color: "white",
|
|
415
|
-
border: "none",
|
|
416
|
-
cursor: "pointer",
|
|
417
|
-
}}
|
|
418
|
-
onMouseEnter={(e) => {
|
|
419
|
-
e.currentTarget.style.backgroundColor = "#059669";
|
|
420
|
-
e.currentTarget.style.transform = "translateY(-1px)";
|
|
421
|
-
e.currentTarget.style.boxShadow =
|
|
422
|
-
"0 4px 12px rgba(16, 185, 129, 0.3)";
|
|
423
|
-
}}
|
|
424
|
-
onMouseLeave={(e) => {
|
|
425
|
-
e.currentTarget.style.backgroundColor = "#10b981";
|
|
426
|
-
e.currentTarget.style.transform = "translateY(0)";
|
|
427
|
-
e.currentTarget.style.boxShadow = "";
|
|
428
|
-
}}
|
|
272
|
+
className="ai-btn ai-btn--primary"
|
|
429
273
|
title="Télécharger l'image"
|
|
430
274
|
>
|
|
431
275
|
<Download size={16} />
|
|
@@ -435,7 +279,7 @@ export function AiImageButton({
|
|
|
435
279
|
{onImageSave && (
|
|
436
280
|
<button
|
|
437
281
|
onClick={handleSave}
|
|
438
|
-
className="
|
|
282
|
+
className="ai-btn"
|
|
439
283
|
title="Sauvegarder en base"
|
|
440
284
|
>
|
|
441
285
|
<ExternalLink size={14} />
|
|
@@ -445,12 +289,7 @@ export function AiImageButton({
|
|
|
445
289
|
</div>
|
|
446
290
|
|
|
447
291
|
{/* Metadata */}
|
|
448
|
-
<div
|
|
449
|
-
className="mt-3 pt-3 text-xs"
|
|
450
|
-
style={{
|
|
451
|
-
...getThemeStyles().metadata,
|
|
452
|
-
}}
|
|
453
|
-
>
|
|
292
|
+
<div className="ai-image-meta">
|
|
454
293
|
<div className="flex justify-center">
|
|
455
294
|
<span>ID: {generatedImage.requestId.slice(-8)}</span>
|
|
456
295
|
</div>
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import React, { useState, useRef, type InputHTMLAttributes } from "react";
|
|
4
|
-
import { Sparkles } from "lucide-react";
|
|
5
|
-
import type { BaseAiProps } from "../types";
|
|
4
|
+
import { Loader2, Lock, Sparkles } from "lucide-react";
|
|
5
|
+
import type { AiRadius, AiSize, BaseAiProps } from "../types";
|
|
6
6
|
import { useAiCallText } from "../hooks/useAiCallText";
|
|
7
7
|
import { useAiModels } from "../hooks/useAiModels";
|
|
8
8
|
import { AiPromptPanel } from "./AiPromptPanel";
|
|
9
9
|
import { UsageToast, useUsageToast } from "./UsageToast";
|
|
10
|
-
import { aiStyles } from "../styles/inline";
|
|
11
10
|
import { handleAIError } from "../utils/errorHandler";
|
|
12
11
|
import { useLB } from "../context/LBAuthProvider";
|
|
13
12
|
import { LBSigninModal } from "./LBSigninModal";
|
|
@@ -16,15 +15,19 @@ import { useAiContext } from "../context/AiProvider";
|
|
|
16
15
|
export interface AiInputProps
|
|
17
16
|
extends
|
|
18
17
|
Omit<BaseAiProps, "type">,
|
|
19
|
-
Omit<InputHTMLAttributes<HTMLInputElement>, "onValue"> {
|
|
18
|
+
Omit<InputHTMLAttributes<HTMLInputElement>, "onValue" | "size"> {
|
|
20
19
|
uiMode?: "modal" | "drawer";
|
|
21
20
|
enableModelManagement?: boolean;
|
|
21
|
+
size?: AiSize;
|
|
22
|
+
radius?: AiRadius;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export function AiInput({
|
|
25
26
|
baseUrl: propBaseUrl,
|
|
26
27
|
apiKeyId: propApiKeyId,
|
|
27
28
|
uiMode = "modal",
|
|
29
|
+
size = "md",
|
|
30
|
+
radius = "full",
|
|
28
31
|
context,
|
|
29
32
|
model,
|
|
30
33
|
prompt,
|
|
@@ -43,8 +46,6 @@ export function AiInput({
|
|
|
43
46
|
const [inputValue, setInputValue] = useState(
|
|
44
47
|
inputProps.value?.toString() || inputProps.defaultValue?.toString() || ""
|
|
45
48
|
);
|
|
46
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
47
|
-
const [isButtonHovered, setIsButtonHovered] = useState(false);
|
|
48
49
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
49
50
|
const { showUsageToast, toastData, toastKey, clearToast } = useUsageToast();
|
|
50
51
|
|
|
@@ -171,75 +172,49 @@ export function AiInput({
|
|
|
171
172
|
inputProps.onChange?.(e);
|
|
172
173
|
};
|
|
173
174
|
|
|
175
|
+
const sizeClass = `ai-size-${size}`;
|
|
176
|
+
const radiusClass = `ai-radius-${radius}`;
|
|
177
|
+
|
|
174
178
|
return (
|
|
175
|
-
<div
|
|
176
|
-
<
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
>
|
|
216
|
-
{loading ? (
|
|
217
|
-
<svg
|
|
218
|
-
style={aiStyles.spinner}
|
|
219
|
-
width="16"
|
|
220
|
-
height="16"
|
|
221
|
-
viewBox="0 0 24 24"
|
|
222
|
-
fill="none"
|
|
223
|
-
stroke="currentColor"
|
|
224
|
-
>
|
|
225
|
-
<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" />
|
|
226
|
-
</svg>
|
|
227
|
-
) : shouldShowSparkles ? (
|
|
228
|
-
<Sparkles size={16} />
|
|
229
|
-
) : (
|
|
230
|
-
<svg
|
|
231
|
-
width="16"
|
|
232
|
-
height="16"
|
|
233
|
-
viewBox="0 0 24 24"
|
|
234
|
-
fill="none"
|
|
235
|
-
stroke="currentColor"
|
|
236
|
-
strokeWidth="2"
|
|
237
|
-
>
|
|
238
|
-
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
|
|
239
|
-
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
|
|
240
|
-
</svg>
|
|
241
|
-
)}
|
|
242
|
-
</button>
|
|
179
|
+
<div className={`ai-control-group ai-glow ${className || ""}`}>
|
|
180
|
+
<div className={`ai-shell ${sizeClass} ${radiusClass}`}>
|
|
181
|
+
<input
|
|
182
|
+
ref={inputRef}
|
|
183
|
+
{...inputProps}
|
|
184
|
+
className={`ai-control ai-control-input ${sizeClass} ${radiusClass}`}
|
|
185
|
+
value={inputValue}
|
|
186
|
+
onChange={handleInputChange}
|
|
187
|
+
onFocus={(e) => {
|
|
188
|
+
inputProps.onFocus?.(e);
|
|
189
|
+
}}
|
|
190
|
+
onBlur={(e) => {
|
|
191
|
+
inputProps.onBlur?.(e);
|
|
192
|
+
}}
|
|
193
|
+
aria-invalid={Boolean(inputProps["aria-invalid"])}
|
|
194
|
+
disabled={disabled || loading}
|
|
195
|
+
/>
|
|
196
|
+
<button
|
|
197
|
+
className={`ai-control-action ai-spark ${sizeClass} ${radiusClass}`}
|
|
198
|
+
onClick={hasConfiguration ? handleQuickGenerate : handleOpenPanel}
|
|
199
|
+
disabled={disabled || loading}
|
|
200
|
+
type="button"
|
|
201
|
+
title={
|
|
202
|
+
!isAuthReady
|
|
203
|
+
? "Authentication required"
|
|
204
|
+
: hasConfiguration
|
|
205
|
+
? "Generate with AI"
|
|
206
|
+
: "Setup AI"
|
|
207
|
+
}
|
|
208
|
+
>
|
|
209
|
+
{loading ? (
|
|
210
|
+
<Loader2 size={16} className="ai-spinner" />
|
|
211
|
+
) : shouldShowSparkles ? (
|
|
212
|
+
<Sparkles size={16} />
|
|
213
|
+
) : (
|
|
214
|
+
<Lock size={16} />
|
|
215
|
+
)}
|
|
216
|
+
</button>
|
|
217
|
+
</div>
|
|
243
218
|
{isOpen && (
|
|
244
219
|
<AiPromptPanel
|
|
245
220
|
isOpen={isOpen}
|