@lastbrain/ai-ui-react 1.0.10 → 1.0.12

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.
Files changed (61) hide show
  1. package/dist/components/AiImageButton.d.ts.map +1 -1
  2. package/dist/components/AiImageButton.js +5 -2
  3. package/dist/components/AiInput.d.ts.map +1 -1
  4. package/dist/components/AiInput.js +20 -7
  5. package/dist/components/AiPromptPanel.d.ts +14 -1
  6. package/dist/components/AiPromptPanel.d.ts.map +1 -1
  7. package/dist/components/AiPromptPanel.js +516 -64
  8. package/dist/components/AiSelect.d.ts.map +1 -1
  9. package/dist/components/AiSelect.js +4 -1
  10. package/dist/components/AiSettingsButton.d.ts.map +1 -1
  11. package/dist/components/AiSettingsButton.js +1 -1
  12. package/dist/components/AiStatusButton.d.ts.map +1 -1
  13. package/dist/components/AiStatusButton.js +225 -38
  14. package/dist/components/AiTextarea.d.ts.map +1 -1
  15. package/dist/components/AiTextarea.js +35 -8
  16. package/dist/components/UsageToast.d.ts +14 -0
  17. package/dist/components/UsageToast.d.ts.map +1 -0
  18. package/dist/components/UsageToast.js +144 -0
  19. package/dist/examples/AiImageGenerator.d.ts +34 -0
  20. package/dist/examples/AiImageGenerator.d.ts.map +1 -0
  21. package/dist/examples/AiImageGenerator.js +85 -0
  22. package/dist/examples/AiPromptPanelAdvanced.d.ts +20 -0
  23. package/dist/examples/AiPromptPanelAdvanced.d.ts.map +1 -0
  24. package/dist/examples/AiPromptPanelAdvanced.js +222 -0
  25. package/dist/examples/ExternalIntegration.d.ts +2 -0
  26. package/dist/examples/ExternalIntegration.d.ts.map +1 -0
  27. package/dist/examples/ExternalIntegration.js +2 -0
  28. package/dist/hooks/useAiStatus.d.ts.map +1 -1
  29. package/dist/hooks/useAiStatus.js +3 -0
  30. package/dist/hooks/useModelManagement.d.ts +32 -0
  31. package/dist/hooks/useModelManagement.d.ts.map +1 -0
  32. package/dist/hooks/useModelManagement.js +135 -0
  33. package/dist/hooks/usePrompts.d.ts +1 -0
  34. package/dist/hooks/usePrompts.d.ts.map +1 -1
  35. package/dist/hooks/usePrompts.js +0 -1
  36. package/dist/index.d.ts +4 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +6 -0
  39. package/dist/styles/inline.d.ts.map +1 -1
  40. package/dist/styles/inline.js +129 -63
  41. package/dist/utils/modelManagement.d.ts +29 -0
  42. package/dist/utils/modelManagement.d.ts.map +1 -0
  43. package/dist/utils/modelManagement.js +80 -0
  44. package/package.json +3 -2
  45. package/src/components/AiImageButton.tsx +13 -2
  46. package/src/components/AiInput.tsx +35 -27
  47. package/src/components/AiPromptPanel.tsx +1000 -143
  48. package/src/components/AiSelect.tsx +11 -0
  49. package/src/components/AiSettingsButton.tsx +4 -2
  50. package/src/components/AiStatusButton.tsx +424 -163
  51. package/src/components/AiTextarea.tsx +55 -28
  52. package/src/components/UsageToast.tsx +182 -0
  53. package/src/examples/AiImageGenerator.tsx +214 -0
  54. package/src/examples/AiPromptPanelAdvanced.tsx +381 -0
  55. package/src/examples/ExternalIntegration.ts +55 -0
  56. package/src/hooks/useAiStatus.ts +4 -0
  57. package/src/hooks/useModelManagement.ts +210 -0
  58. package/src/hooks/usePrompts.ts +1 -1
  59. package/src/index.ts +8 -0
  60. package/src/styles/inline.ts +139 -64
  61. package/src/utils/modelManagement.ts +130 -0
@@ -1,9 +1,11 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useState, useEffect } from "react";
3
+ import { useState, useEffect, useRef, useLayoutEffect, } from "react";
4
+ import { BookOpen, Search, Sparkles, Star, Tag, Settings } from "lucide-react";
4
5
  import { aiStyles } from "../styles/inline";
5
- import { usePrompts } from "../hooks/usePrompts";
6
- export function AiPromptPanel({ isOpen, onClose, onSubmit, uiMode = "modal", models = [], sourceText, children, }) {
6
+ import { usePrompts, } from "../hooks/usePrompts";
7
+ import { useModelManagement } from "../hooks/useModelManagement";
8
+ export function AiPromptPanel({ isOpen, onClose, onSubmit, uiMode: _uiMode = "modal", models = [], sourceText, children, enableModelManagement = false, availableModels = [], userModels = [], onModelToggle, apiKey, baseUrl, }) {
7
9
  const [selectedModel, setSelectedModel] = useState("");
8
10
  const [prompt, setPrompt] = useState("");
9
11
  const [promptId, setPromptId] = useState(undefined);
@@ -13,37 +15,113 @@ export function AiPromptPanel({ isOpen, onClose, onSubmit, uiMode = "modal", mod
13
15
  const [promptFocused, setPromptFocused] = useState(false);
14
16
  const [modelFocused, setModelFocused] = useState(false);
15
17
  const [showPromptLibrary, setShowPromptLibrary] = useState(false);
16
- const { prompts, loading: promptsLoading, fetchPrompts, incrementStat } = usePrompts();
17
- // Set initial model when models change
18
- useEffect(() => {
19
- if (models.length > 0 && !selectedModel) {
20
- setSelectedModel(models[0].id);
18
+ const [searchQuery, setSearchQuery] = useState("");
19
+ const [selectedTag, setSelectedTag] = useState("all");
20
+ const [isGenerating, setIsGenerating] = useState(false);
21
+ const [isClosing, setIsClosing] = useState(false);
22
+ const promptRef = useRef(null);
23
+ const closeTimeoutRef = useRef(null);
24
+ // États pour la gestion des modèles
25
+ const [showAllModels, setShowAllModels] = useState(false);
26
+ const [isModelManagementOpen, setIsModelManagementOpen] = useState(false);
27
+ const [loadingModels, setLoadingModels] = useState([]);
28
+ const { prompts, loading: promptsLoading, fetchPrompts, incrementStat, } = usePrompts();
29
+ // Hook de gestion des modèles (automatique si enableModelManagement et pas de props externes)
30
+ const autoModelManagement = useModelManagement({
31
+ apiKey,
32
+ baseUrl,
33
+ category: "text", // Par défaut pour AiPromptPanel
34
+ autoFetch: enableModelManagement && availableModels.length === 0 && !!apiKey,
35
+ });
36
+ // Utiliser soit les props externes soit la gestion automatique
37
+ const effectiveAvailableModels = availableModels.length > 0
38
+ ? availableModels
39
+ : autoModelManagement.availableModels;
40
+ const effectiveUserModels = userModels.length > 0 ? userModels : autoModelManagement.userModels;
41
+ const effectiveToggleModel = onModelToggle || autoModelManagement.toggleModel;
42
+ // Gestion des modèles
43
+ const handleModelToggle = async (modelId, isActive) => {
44
+ if (!effectiveToggleModel)
45
+ return;
46
+ setLoadingModels((prev) => [...prev, modelId]);
47
+ try {
48
+ await effectiveToggleModel(modelId, isActive);
21
49
  }
22
- }, [models, selectedModel]);
50
+ catch (error) {
51
+ console.error("Erreur lors du changement de modèle:", error);
52
+ }
53
+ finally {
54
+ setLoadingModels((prev) => prev.filter((id) => id !== modelId));
55
+ }
56
+ };
57
+ const getFilteredModels = () => {
58
+ if (!enableModelManagement || effectiveAvailableModels.length === 0) {
59
+ // Mode classique : transformer les ModelRef en AIModel
60
+ return models.map((m) => ({
61
+ id: m.id,
62
+ name: m.name,
63
+ category: m.type === "image" ? "image" : "text",
64
+ provider: "Unknown",
65
+ }));
66
+ }
67
+ const textModels = effectiveAvailableModels.filter((m) => m.category === "text");
68
+ if (showAllModels) {
69
+ return textModels;
70
+ }
71
+ else {
72
+ return textModels.filter((m) => effectiveUserModels.includes(m.id));
73
+ }
74
+ };
23
75
  // Fetch prompts when modal opens
24
76
  useEffect(() => {
25
77
  if (isOpen && models.length > 0) {
26
- const modelType = models.find((m) => m.id === selectedModel)?.type;
78
+ const activeModelId = selectedModel || models[0]?.id;
79
+ const modelType = models.find((m) => m.id === activeModelId)?.type;
27
80
  fetchPrompts({
28
81
  type: modelType === "image" ? "image" : "text",
29
82
  });
30
83
  }
31
84
  }, [isOpen, selectedModel, models, fetchPrompts]);
32
- if (!isOpen)
33
- return null;
34
- const handleSubmit = () => {
35
- if (!selectedModel || !prompt.trim())
85
+ const handleSubmit = async () => {
86
+ const activeModelId = selectedModel || models[0]?.id;
87
+ if (!activeModelId || !prompt.trim())
36
88
  return;
37
- onSubmit(selectedModel, prompt, promptId);
38
- setPrompt("");
39
- setPromptId(undefined);
89
+ setIsGenerating(true);
90
+ try {
91
+ await Promise.resolve(onSubmit(activeModelId, prompt, promptId));
92
+ setPrompt("");
93
+ setPromptId(undefined);
94
+ }
95
+ finally {
96
+ setIsGenerating(false);
97
+ handleClose();
98
+ }
40
99
  };
41
- const handleClose = () => {
100
+ const finalizeClose = () => {
42
101
  onClose();
43
102
  setPrompt("");
44
103
  setPromptId(undefined);
45
104
  setShowPromptLibrary(false);
105
+ setSearchQuery("");
106
+ setSelectedTag("all");
107
+ setIsClosing(false);
108
+ };
109
+ const handleClose = () => {
110
+ if (isClosing)
111
+ return;
112
+ setIsClosing(true);
113
+ if (closeTimeoutRef.current) {
114
+ window.clearTimeout(closeTimeoutRef.current);
115
+ }
116
+ closeTimeoutRef.current = window.setTimeout(finalizeClose, 220);
46
117
  };
118
+ useEffect(() => {
119
+ return () => {
120
+ if (closeTimeoutRef.current) {
121
+ window.clearTimeout(closeTimeoutRef.current);
122
+ }
123
+ };
124
+ }, []);
47
125
  const handleKeyDown = (e) => {
48
126
  if (e.key === "Escape") {
49
127
  handleClose();
@@ -56,27 +134,109 @@ export function AiPromptPanel({ isOpen, onClose, onSubmit, uiMode = "modal", mod
56
134
  setPrompt(promptData.content);
57
135
  setPromptId(promptData.id);
58
136
  incrementStat(promptData.id, "picked");
137
+ if (promptData.model) {
138
+ setSelectedModel(promptData.model);
139
+ }
59
140
  setShowPromptLibrary(false);
60
141
  };
61
- const currentModelType = models.find((m) => m.id === selectedModel)?.type;
142
+ const adjustPromptHeight = () => {
143
+ const element = promptRef.current;
144
+ if (!element) {
145
+ return;
146
+ }
147
+ element.style.height = "auto";
148
+ element.style.height = `${element.scrollHeight}px`;
149
+ };
150
+ useLayoutEffect(() => {
151
+ adjustPromptHeight();
152
+ }, [prompt]);
153
+ if (!isOpen)
154
+ return null;
155
+ const activeModelId = selectedModel || models[0]?.id || "";
156
+ const currentModelType = models.find((m) => m.id === activeModelId)?.type;
62
157
  const filteredPrompts = prompts.filter((p) => {
63
158
  const matchesType = currentModelType === "image" ? p.type === "image" : p.type !== "image";
64
159
  return matchesType;
65
160
  });
161
+ const availableTags = Array.from(new Set(filteredPrompts.flatMap((p) => (Array.isArray(p.tags) ? p.tags : [])))).sort((a, b) => a.localeCompare(b));
162
+ const normalizedSearch = searchQuery.trim().toLowerCase();
163
+ const visiblePrompts = filteredPrompts
164
+ .filter((promptData) => {
165
+ if (!normalizedSearch) {
166
+ return true;
167
+ }
168
+ return (promptData.title.toLowerCase().includes(normalizedSearch) ||
169
+ promptData.content.toLowerCase().includes(normalizedSearch));
170
+ })
171
+ .filter((promptData) => {
172
+ if (selectedTag === "all") {
173
+ return true;
174
+ }
175
+ return promptData.tags?.includes(selectedTag);
176
+ })
177
+ .slice()
178
+ .sort((a, b) => Number(b.favorite) - Number(a.favorite));
179
+ const favoritePrompts = visiblePrompts.filter((promptData) => Boolean(promptData.favorite));
180
+ const nonFavoritePrompts = visiblePrompts.filter((promptData) => !promptData.favorite);
66
181
  const renderProps = {
67
182
  models,
68
- selectedModel,
183
+ selectedModel: activeModelId,
69
184
  setSelectedModel,
70
185
  prompt,
71
186
  setPrompt,
72
187
  sourceText,
73
188
  handleSubmit,
74
189
  handleClose,
190
+ // Nouvelles props pour la gestion des modèles
191
+ enableModelManagement,
192
+ availableModels: effectiveAvailableModels,
193
+ userModels: effectiveUserModels,
194
+ showAllModels,
195
+ setShowAllModels,
196
+ onModelToggle: handleModelToggle,
75
197
  };
76
198
  if (children) {
77
199
  return (_jsx("div", { style: aiStyles.modal, onKeyDown: handleKeyDown, children: children(renderProps) }));
78
200
  }
79
- return (_jsxs("div", { style: aiStyles.modal, onKeyDown: handleKeyDown, children: [_jsx("div", { style: aiStyles.modalOverlay, onClick: handleClose }), _jsxs("div", { style: aiStyles.modalContent, children: [_jsxs("div", { style: aiStyles.modalHeader, children: [_jsx("h2", { style: aiStyles.modalTitle, children: showPromptLibrary ? "Select a Prompt" : "AI Prompt Configuration" }), _jsx("button", { style: {
201
+ return (_jsxs("div", { style: aiStyles.modal, onKeyDown: handleKeyDown, children: [_jsx("div", { style: {
202
+ ...aiStyles.modalOverlay,
203
+ opacity: isClosing ? 0 : 1,
204
+ transition: "opacity 200ms ease",
205
+ }, onClick: handleClose }), _jsxs("div", { style: {
206
+ ...aiStyles.modalContent,
207
+ opacity: isClosing ? 0 : 1,
208
+ transform: isClosing ? "translateY(12px)" : "translateY(0)",
209
+ transition: "opacity 200ms ease, transform 200ms ease",
210
+ }, children: [isGenerating && (_jsxs("div", { style: {
211
+ position: "absolute",
212
+ inset: 0,
213
+ background: "var(--ai-bg-tertiary)",
214
+ backdropFilter: "blur(6px)",
215
+ WebkitBackdropFilter: "blur(6px)",
216
+ display: "flex",
217
+ alignItems: "center",
218
+ justifyContent: "center",
219
+ flexDirection: "column",
220
+ gap: "12px",
221
+ zIndex: 10,
222
+ borderRadius: "12px",
223
+ }, children: [_jsx("div", { style: {
224
+ width: "64px",
225
+ height: "64px",
226
+ borderRadius: "999px",
227
+ border: "2px solid #8b5cf620",
228
+ borderTopColor: "#8b5cf6",
229
+ animation: "ai-spin 1.1s linear infinite",
230
+ display: "flex",
231
+ alignItems: "center",
232
+ justifyContent: "center",
233
+ boxShadow: "0 12px 24px rgba(139, 92, 246, 0.15)",
234
+ }, children: _jsx(Sparkles, { size: 20, color: "#8b5cf6" }) }), _jsx("div", { style: {
235
+ fontSize: "13px",
236
+ fontWeight: 600,
237
+ color: "#6b7280",
238
+ letterSpacing: "0.02em",
239
+ }, children: "G\u00E9n\u00E9ration en cours\u2026" })] })), _jsxs("div", { style: aiStyles.modalHeader, children: [_jsx("h2", { style: aiStyles.modalTitle, children: showPromptLibrary ? "Select a Prompt" : "AI Prompt Configuration" }), _jsx("button", { style: {
80
240
  ...aiStyles.modalCloseButton,
81
241
  ...(isCloseHovered && aiStyles.modalCloseButtonHover),
82
242
  }, onClick: handleClose, onMouseEnter: () => setIsCloseHovered(true), onMouseLeave: () => setIsCloseHovered(false), "aria-label": "Close", children: "\u00D7" })] }), _jsx("div", { style: aiStyles.modalBody, children: !showPromptLibrary ? (_jsxs(_Fragment, { children: [sourceText && (_jsxs("div", { style: {
@@ -93,10 +253,74 @@ export function AiPromptPanel({ isOpen, onClose, onSubmit, uiMode = "modal", mod
93
253
  overflow: "auto",
94
254
  whiteSpace: "pre-wrap",
95
255
  wordBreak: "break-word",
96
- }, children: sourceText })] })), _jsxs("div", { style: aiStyles.modalInputGroup, children: [_jsx("label", { htmlFor: "model-select", style: aiStyles.modalLabel, children: "AI Model" }), _jsxs("select", { id: "model-select", value: selectedModel, onChange: (e) => setSelectedModel(e.target.value), onFocus: () => setModelFocused(true), onBlur: () => setModelFocused(false), style: {
97
- ...aiStyles.select,
98
- ...(modelFocused && aiStyles.selectFocus),
99
- }, children: [models.length === 0 && (_jsx("option", { value: "", children: "Loading models..." })), models.map((model) => (_jsx("option", { value: model.id, children: model.name }, model.id)))] })] }), _jsxs("div", { style: aiStyles.modalInputGroup, children: [_jsxs("div", { style: {
256
+ }, children: sourceText })] })), _jsx("div", { style: aiStyles.modalInputGroup, children: enableModelManagement ? (
257
+ // Version avancée avec gestion des modèles
258
+ _jsxs("div", { style: { marginBottom: "16px" }, children: [_jsxs("div", { style: {
259
+ display: "flex",
260
+ justifyContent: "space-between",
261
+ alignItems: "center",
262
+ marginBottom: "8px",
263
+ }, children: [_jsx("label", { htmlFor: "model-select", style: aiStyles.modalLabel, children: "AI Model" }), _jsxs("div", { style: {
264
+ display: "flex",
265
+ alignItems: "center",
266
+ gap: "8px",
267
+ }, children: [effectiveAvailableModels.length > 0 && (_jsxs("button", { onClick: () => setShowAllModels(!showAllModels), style: {
268
+ padding: "4px 8px",
269
+ fontSize: "12px",
270
+ color: "#8b5cf6",
271
+ background: "#8b5cf610",
272
+ border: "1px solid #8b5cf630",
273
+ borderRadius: "6px",
274
+ cursor: "pointer",
275
+ transition: "all 0.2s",
276
+ }, onMouseEnter: (e) => {
277
+ e.currentTarget.style.background = "#8b5cf620";
278
+ }, onMouseLeave: (e) => {
279
+ e.currentTarget.style.background = "#8b5cf610";
280
+ }, children: [showAllModels ? "Mes modèles" : "Tous les modèles", !showAllModels &&
281
+ effectiveAvailableModels.filter((m) => m.category === "text" &&
282
+ !effectiveUserModels.includes(m.id)).length > 0 && (_jsxs("span", { style: {
283
+ marginLeft: "4px",
284
+ padding: "2px 6px",
285
+ fontSize: "10px",
286
+ background: "#8b5cf6",
287
+ color: "white",
288
+ borderRadius: "10px",
289
+ }, children: ["+", effectiveAvailableModels.filter((m) => m.category === "text" &&
290
+ !effectiveUserModels.includes(m.id)).length] }))] })), _jsx("button", { onClick: () => setIsModelManagementOpen(true), style: {
291
+ padding: "4px 8px",
292
+ fontSize: "12px",
293
+ color: "#8b5cf6",
294
+ background: "#8b5cf610",
295
+ border: "1px solid #8b5cf630",
296
+ borderRadius: "6px",
297
+ cursor: "pointer",
298
+ transition: "all 0.2s",
299
+ display: "flex",
300
+ alignItems: "center",
301
+ gap: "4px",
302
+ }, onMouseEnter: (e) => {
303
+ e.currentTarget.style.background = "#8b5cf620";
304
+ }, onMouseLeave: (e) => {
305
+ e.currentTarget.style.background = "#8b5cf610";
306
+ }, children: _jsx(Settings, { size: 12 }) })] })] }), _jsxs("select", { id: "model-select", value: activeModelId, onChange: (e) => setSelectedModel(e.target.value), onFocus: () => setModelFocused(true), onBlur: () => setModelFocused(false), style: {
307
+ ...aiStyles.select,
308
+ ...(modelFocused && aiStyles.selectFocus),
309
+ }, children: [getFilteredModels().length === 0 && (_jsx("option", { value: "", children: "Loading models..." })), getFilteredModels().map((model) => {
310
+ const isActive = effectiveUserModels.includes(model.id);
311
+ return (_jsxs("option", { value: model.id, style: {
312
+ opacity: showAllModels && !isActive ? 0.6 : 1,
313
+ }, children: [model.name, showAllModels && isActive && " ✓", showAllModels && !isActive && " (Désactivé)"] }, model.id));
314
+ })] }), showAllModels && onModelToggle && (_jsx("div", { style: {
315
+ fontSize: "11px",
316
+ color: "#6b7280",
317
+ marginTop: "4px",
318
+ }, children: "\uD83D\uDCA1 Cliquez sur \"\u2699\uFE0F\" pour activer/d\u00E9sactiver les mod\u00E8les" }))] })) : (
319
+ // Version classique
320
+ _jsxs(_Fragment, { children: [_jsx("label", { htmlFor: "model-select", style: aiStyles.modalLabel, children: "AI Model" }), _jsxs("select", { id: "model-select", value: activeModelId, onChange: (e) => setSelectedModel(e.target.value), onFocus: () => setModelFocused(true), onBlur: () => setModelFocused(false), style: {
321
+ ...aiStyles.select,
322
+ ...(modelFocused && aiStyles.selectFocus),
323
+ }, children: [models.length === 0 && (_jsx("option", { value: "", children: "Loading models..." })), models.map((model) => (_jsx("option", { value: model.id, children: model.name }, model.id)))] })] })) }), _jsxs("div", { style: aiStyles.modalInputGroup, children: [_jsxs("div", { style: {
100
324
  display: "flex",
101
325
  justifyContent: "space-between",
102
326
  alignItems: "center",
@@ -109,17 +333,20 @@ export function AiPromptPanel({ isOpen, onClose, onSubmit, uiMode = "modal", mod
109
333
  }, children: "(Cmd/Ctrl + Enter to submit)" })] }), filteredPrompts.length > 0 && (_jsxs("button", { onClick: () => setShowPromptLibrary(true), style: {
110
334
  padding: "4px 12px",
111
335
  fontSize: "12px",
112
- color: "#ffffff",
113
- background: "#8b5cf620",
114
- border: "none",
336
+ color: "#8b5cf6",
337
+ background: "#8b5cf610",
338
+ border: "1px solid #8b5cf630",
115
339
  borderRadius: "6px",
116
340
  cursor: "pointer",
117
341
  transition: "all 0.2s",
342
+ display: "flex",
343
+ alignItems: "center",
344
+ gap: "6px",
118
345
  }, onMouseEnter: (e) => {
119
- e.currentTarget.style.background = "#8b5cf630";
120
- }, onMouseLeave: (e) => {
121
346
  e.currentTarget.style.background = "#8b5cf620";
122
- }, children: ["\uD83D\uDCDA Browse Prompts (", filteredPrompts.length, ")"] }))] }), _jsx("textarea", { id: "prompt-input", value: prompt, onChange: (e) => setPrompt(e.target.value), onFocus: () => setPromptFocused(true), onBlur: () => setPromptFocused(false), placeholder: sourceText
347
+ }, onMouseLeave: (e) => {
348
+ e.currentTarget.style.background = "#8b5cf610";
349
+ }, children: [_jsx(BookOpen, { size: 14 }), "Browse Prompts (", filteredPrompts.length, ")"] }))] }), _jsx("textarea", { id: "prompt-input", ref: promptRef, value: prompt, onChange: (e) => setPrompt(e.target.value), onFocus: () => setPromptFocused(true), onBlur: () => setPromptFocused(false), placeholder: sourceText
123
350
  ? "Enter your AI prompt... e.g., 'Correct spelling and grammar', 'Make it more professional', 'Translate to English'"
124
351
  : "Enter your AI prompt... e.g., 'Write a blog post about AI', 'Generate product description'", rows: 6, style: {
125
352
  ...aiStyles.textarea,
@@ -136,47 +363,272 @@ export function AiPromptPanel({ isOpen, onClose, onSubmit, uiMode = "modal", mod
136
363
  display: "flex",
137
364
  alignItems: "center",
138
365
  gap: "4px",
139
- }, children: "\u2190 Back to form" }), promptsLoading ? (_jsx("div", { style: { textAlign: "center", padding: "40px 0" }, children: "Loading prompts..." })) : filteredPrompts.length === 0 ? (_jsx("div", { style: { textAlign: "center", padding: "40px 0", color: "#6b7280" }, children: "No prompts available for this model type" })) : (_jsx("div", { style: {
366
+ }, children: "\u2190 Back to form" }), _jsxs("div", { style: { marginBottom: "12px" }, children: [_jsxs("div", { style: {
367
+ ...aiStyles.inputWrapper,
368
+ marginBottom: "10px",
369
+ }, children: [_jsx(Search, { size: 16, style: {
370
+ position: "absolute",
371
+ left: "12px",
372
+ top: "50%",
373
+ transform: "translateY(-50%)",
374
+ color: aiStyles.tooltipLabel.color,
375
+ } }), _jsx("input", { value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search prompts...", style: {
376
+ ...aiStyles.input,
377
+ padding: "10px 12px 10px 36px",
378
+ } })] }), availableTags.length > 0 && (_jsxs("div", { style: {
379
+ display: "flex",
380
+ flexWrap: "wrap",
381
+ gap: "8px",
382
+ alignItems: "center",
383
+ }, children: [_jsxs("span", { style: {
384
+ display: "inline-flex",
385
+ alignItems: "center",
386
+ gap: "6px",
387
+ fontSize: "12px",
388
+ color: aiStyles.tooltipLabel.color,
389
+ }, children: [_jsx(Tag, { size: 14 }), "Tags"] }), _jsx("button", { onClick: () => setSelectedTag("all"), style: {
390
+ ...aiStyles.chip,
391
+ borderColor: selectedTag === "all"
392
+ ? "#8b5cf6"
393
+ : aiStyles.chip.border,
394
+ background: selectedTag === "all"
395
+ ? "#8b5cf620"
396
+ : aiStyles.chip.background,
397
+ }, children: "All" }), availableTags.map((tag) => (_jsx("button", { onClick: () => setSelectedTag(tag), style: {
398
+ ...aiStyles.chip,
399
+ borderColor: selectedTag === tag
400
+ ? "#8b5cf6"
401
+ : aiStyles.chip.border,
402
+ background: selectedTag === tag
403
+ ? "#8b5cf620"
404
+ : aiStyles.chip.background,
405
+ }, children: tag }, tag)))] }))] }), promptsLoading ? (_jsx("div", { style: { textAlign: "center", padding: "40px 0" }, children: "Loading prompts..." })) : visiblePrompts.length === 0 ? (_jsx("div", { style: {
406
+ textAlign: "center",
407
+ padding: "40px 0",
408
+ color: "#6b7280",
409
+ }, children: "No prompts available for this model type" })) : (_jsxs("div", { style: {
140
410
  display: "flex",
141
411
  flexDirection: "column",
142
412
  gap: "12px",
143
413
  maxHeight: "400px",
144
414
  overflow: "auto",
145
- }, children: filteredPrompts.map((promptData) => (_jsxs("div", { onClick: () => handleSelectPrompt(promptData), style: {
146
- padding: "16px",
147
- border: `1px solid #e5e7eb`,
148
- borderRadius: "8px",
149
- cursor: "pointer",
150
- transition: "all 0.2s",
151
- }, onMouseEnter: (e) => {
152
- e.currentTarget.style.background = "#8b5cf610";
153
- e.currentTarget.style.borderColor = "#8b5cf6";
154
- }, onMouseLeave: (e) => {
155
- e.currentTarget.style.background = "transparent";
156
- e.currentTarget.style.borderColor = "#e5e7eb";
157
- }, children: [_jsx("div", { style: {
158
- fontWeight: 600,
159
- marginBottom: "4px",
160
- color: "#111827",
161
- }, children: promptData.title }), _jsx("div", { style: {
162
- fontSize: "13px",
163
- color: "#6b7280",
164
- overflow: "hidden",
165
- textOverflow: "ellipsis",
166
- display: "-webkit-box",
167
- WebkitLineClamp: 2,
168
- WebkitBoxOrient: "vertical",
169
- }, children: promptData.content }), ("category" in promptData && promptData.category) ? (_jsx("div", { style: {
170
- marginTop: "8px",
171
- fontSize: "11px",
172
- color: "#8b5cf6",
173
- }, children: String(promptData.category) })) : null] }, promptData.id))) }))] })) }), _jsxs("div", { style: aiStyles.modalFooter, children: [_jsx("button", { onClick: handleClose, onMouseEnter: () => setIsCancelHovered(true), onMouseLeave: () => setIsCancelHovered(false), style: {
415
+ }, children: [favoritePrompts.length > 0 && (_jsxs("div", { children: [_jsx("div", { style: {
416
+ fontSize: "12px",
417
+ color: "#6b7280",
418
+ fontWeight: 600,
419
+ textTransform: "uppercase",
420
+ marginBottom: "8px",
421
+ }, children: "Favorites" }), _jsx("div", { style: {
422
+ display: "flex",
423
+ flexDirection: "column",
424
+ gap: "12px",
425
+ }, children: favoritePrompts.map((promptData) => (_jsxs("div", { onClick: () => handleSelectPrompt(promptData), style: {
426
+ padding: "16px",
427
+ border: `1px solid #e5e7eb`,
428
+ borderRadius: "8px",
429
+ cursor: "pointer",
430
+ transition: "all 0.2s",
431
+ }, onMouseEnter: (e) => {
432
+ e.currentTarget.style.background = "#8b5cf610";
433
+ e.currentTarget.style.borderColor = "#8b5cf6";
434
+ }, onMouseLeave: (e) => {
435
+ e.currentTarget.style.background = "transparent";
436
+ e.currentTarget.style.borderColor = "#e5e7eb";
437
+ }, children: [_jsxs("div", { style: {
438
+ display: "flex",
439
+ alignItems: "center",
440
+ gap: "8px",
441
+ fontWeight: 600,
442
+ marginBottom: "4px",
443
+ color: "#9780a5",
444
+ }, children: [_jsx(Star, { size: 14, color: "#8b5cf6" }), promptData.title] }), _jsx("div", { style: {
445
+ fontSize: "13px",
446
+ color: "#6b7280",
447
+ overflow: "hidden",
448
+ textOverflow: "ellipsis",
449
+ display: "-webkit-box",
450
+ WebkitLineClamp: 2,
451
+ WebkitBoxOrient: "vertical",
452
+ }, children: promptData.content }), "category" in promptData && promptData.category ? (_jsx("div", { style: {
453
+ marginTop: "8px",
454
+ fontSize: "11px",
455
+ color: "#8b5cf6",
456
+ }, children: String(promptData.category) })) : null] }, promptData.id))) })] })), nonFavoritePrompts.length > 0 && (_jsxs("div", { children: [_jsx("div", { style: {
457
+ fontSize: "12px",
458
+ color: "#6b7280",
459
+ fontWeight: 600,
460
+ textTransform: "uppercase",
461
+ marginTop: favoritePrompts.length > 0 ? "12px" : undefined,
462
+ marginBottom: "8px",
463
+ }, children: "All prompts" }), _jsx("div", { style: {
464
+ display: "flex",
465
+ flexDirection: "column",
466
+ gap: "12px",
467
+ }, children: nonFavoritePrompts.map((promptData) => (_jsxs("div", { onClick: () => handleSelectPrompt(promptData), style: {
468
+ padding: "16px",
469
+ border: `1px solid #e5e7eb`,
470
+ borderRadius: "8px",
471
+ cursor: "pointer",
472
+ transition: "all 0.2s",
473
+ }, onMouseEnter: (e) => {
474
+ e.currentTarget.style.background = "#8b5cf610";
475
+ e.currentTarget.style.borderColor = "#8b5cf6";
476
+ }, onMouseLeave: (e) => {
477
+ e.currentTarget.style.background = "transparent";
478
+ e.currentTarget.style.borderColor = "#e5e7eb";
479
+ }, children: [_jsx("div", { style: {
480
+ fontWeight: 600,
481
+ marginBottom: "4px",
482
+ color: "#9780a5",
483
+ }, children: promptData.title }), _jsx("div", { style: {
484
+ fontSize: "13px",
485
+ color: "#6b7280",
486
+ overflow: "hidden",
487
+ textOverflow: "ellipsis",
488
+ display: "-webkit-box",
489
+ WebkitLineClamp: 2,
490
+ WebkitBoxOrient: "vertical",
491
+ }, children: promptData.content }), "category" in promptData && promptData.category ? (_jsx("div", { style: {
492
+ marginTop: "8px",
493
+ fontSize: "11px",
494
+ color: "#8b5cf6",
495
+ }, children: String(promptData.category) })) : null] }, promptData.id))) })] }))] }))] })) }), _jsxs("div", { style: aiStyles.modalFooter, children: [_jsx("button", { onClick: handleClose, onMouseEnter: () => setIsCancelHovered(true), onMouseLeave: () => setIsCancelHovered(false), style: {
174
496
  ...aiStyles.button,
175
497
  ...aiStyles.buttonSecondary,
176
498
  ...(isCancelHovered && aiStyles.buttonSecondaryHover),
177
499
  }, children: "Cancel" }), _jsx("button", { onClick: handleSubmit, disabled: !selectedModel || !prompt.trim(), onMouseEnter: () => setIsSubmitHovered(true), onMouseLeave: () => setIsSubmitHovered(false), style: {
178
500
  ...aiStyles.button,
179
- ...(isSubmitHovered && !(!selectedModel || !prompt.trim()) && aiStyles.buttonHover),
180
- ...(!selectedModel || !prompt.trim() ? aiStyles.buttonDisabled : {}),
181
- }, children: sourceText ? "Transform with AI" : "Generate with AI" })] })] })] }));
501
+ ...(isSubmitHovered &&
502
+ !(!selectedModel || !prompt.trim()) &&
503
+ aiStyles.buttonHover),
504
+ ...(!selectedModel || !prompt.trim()
505
+ ? aiStyles.buttonDisabled
506
+ : {}),
507
+ }, children: sourceText ? "Transform with AI" : "Generate with AI" })] })] }), enableModelManagement && isModelManagementOpen && (_jsxs("div", { style: {
508
+ ...aiStyles.modal,
509
+ zIndex: 1001, // Au-dessus du modal principal
510
+ }, children: [_jsx("div", { style: {
511
+ ...aiStyles.modalOverlay,
512
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
513
+ }, onClick: () => setIsModelManagementOpen(false) }), _jsxs("div", { style: {
514
+ ...aiStyles.modalContent,
515
+ maxWidth: "600px",
516
+ maxHeight: "80vh",
517
+ overflow: "auto",
518
+ }, children: [_jsxs("div", { style: aiStyles.modalHeader, children: [_jsx("h2", { style: aiStyles.modalTitle, children: "Gestion des mod\u00E8les IA" }), _jsx("button", { style: aiStyles.modalCloseButton, onClick: () => setIsModelManagementOpen(false), "aria-label": "Close", children: "\u00D7" })] }), _jsxs("div", { style: aiStyles.modalBody, children: [_jsx("div", { style: { marginBottom: "16px" }, children: _jsx("p", { style: {
519
+ fontSize: "14px",
520
+ color: "#6b7280",
521
+ margin: "0 0 16px 0",
522
+ }, children: "Activez ou d\u00E9sactivez les mod\u00E8les selon vos besoins" }) }), _jsx("div", { style: {
523
+ display: "flex",
524
+ flexDirection: "column",
525
+ gap: "12px",
526
+ }, children: effectiveAvailableModels
527
+ .filter((model) => model.category === "text")
528
+ .map((modelData) => {
529
+ const isActive = effectiveUserModels.includes(modelData.id);
530
+ const isLoading = loadingModels.includes(modelData.id);
531
+ return (_jsxs("div", { style: {
532
+ display: "flex",
533
+ alignItems: "center",
534
+ justifyContent: "space-between",
535
+ padding: "16px",
536
+ border: "1px solid #e5e7eb",
537
+ borderRadius: "8px",
538
+ backgroundColor: isActive ? "#f0fdf4" : "#ffffff",
539
+ transition: "all 0.2s",
540
+ }, children: [_jsxs("div", { style: {
541
+ display: "flex",
542
+ alignItems: "center",
543
+ gap: "12px",
544
+ }, children: [_jsx("div", { style: {
545
+ width: "12px",
546
+ height: "12px",
547
+ borderRadius: "50%",
548
+ backgroundColor: isActive ? "#10b981" : "#d1d5db",
549
+ } }), _jsxs("div", { children: [_jsxs("div", { style: {
550
+ display: "flex",
551
+ alignItems: "center",
552
+ gap: "8px",
553
+ marginBottom: "4px",
554
+ }, children: [_jsx("span", { style: {
555
+ fontWeight: "500",
556
+ color: "#111827",
557
+ }, children: modelData.name }), modelData.isPro && (_jsx("span", { style: {
558
+ padding: "2px 8px",
559
+ fontSize: "11px",
560
+ backgroundColor: "#8b5cf6",
561
+ color: "white",
562
+ borderRadius: "12px",
563
+ fontWeight: "500",
564
+ }, children: "PRO" }))] }), modelData.description && (_jsx("p", { style: {
565
+ fontSize: "13px",
566
+ color: "#6b7280",
567
+ margin: "0 0 4px 0",
568
+ }, children: modelData.description })), _jsxs("div", { style: {
569
+ display: "flex",
570
+ alignItems: "center",
571
+ gap: "16px",
572
+ fontSize: "12px",
573
+ color: "#9ca3af",
574
+ }, children: [_jsxs("span", { children: ["Fournisseur: ", modelData.provider] }), modelData.costPer1M && (_jsxs("span", { children: ["Co\u00FBt: $", modelData.costPer1M, "/1M tokens"] }))] })] })] }), _jsx("button", { onClick: () => handleModelToggle(modelData.id, !isActive), disabled: isLoading, style: {
575
+ padding: "8px 16px",
576
+ fontSize: "13px",
577
+ fontWeight: "500",
578
+ borderRadius: "6px",
579
+ border: "1px solid",
580
+ cursor: isLoading ? "not-allowed" : "pointer",
581
+ transition: "all 0.2s",
582
+ minWidth: "80px",
583
+ ...(isActive
584
+ ? {
585
+ backgroundColor: "#fef2f2",
586
+ borderColor: "#fecaca",
587
+ color: "#dc2626",
588
+ }
589
+ : {
590
+ backgroundColor: "#f0fdf4",
591
+ borderColor: "#bbf7d0",
592
+ color: "#16a34a",
593
+ }),
594
+ opacity: isLoading ? 0.6 : 1,
595
+ }, onMouseEnter: (e) => {
596
+ if (!isLoading) {
597
+ if (isActive) {
598
+ e.currentTarget.style.backgroundColor =
599
+ "#fee2e2";
600
+ }
601
+ else {
602
+ e.currentTarget.style.backgroundColor =
603
+ "#dcfce7";
604
+ }
605
+ }
606
+ }, onMouseLeave: (e) => {
607
+ if (!isLoading) {
608
+ if (isActive) {
609
+ e.currentTarget.style.backgroundColor =
610
+ "#fef2f2";
611
+ }
612
+ else {
613
+ e.currentTarget.style.backgroundColor =
614
+ "#f0fdf4";
615
+ }
616
+ }
617
+ }, children: isLoading ? (_jsx("div", { style: {
618
+ display: "flex",
619
+ alignItems: "center",
620
+ justifyContent: "center",
621
+ gap: "4px",
622
+ }, children: _jsx("div", { style: {
623
+ width: "12px",
624
+ height: "12px",
625
+ border: "2px solid currentColor",
626
+ borderTop: "2px solid transparent",
627
+ borderRadius: "50%",
628
+ animation: "ai-spin 1s linear infinite",
629
+ } }) })) : isActive ? ("Désactiver") : ("Activer") })] }, modelData.id));
630
+ }) })] }), _jsx("div", { style: aiStyles.modalFooter, children: _jsx("button", { onClick: () => setIsModelManagementOpen(false), style: {
631
+ ...aiStyles.button,
632
+ ...aiStyles.buttonSecondary,
633
+ }, children: "Fermer" }) })] })] }))] }));
182
634
  }