@lastbrain/ai-ui-react 1.0.73 → 1.0.74

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 (83) hide show
  1. package/dist/components/AiChipLabel.d.ts.map +1 -1
  2. package/dist/components/AiChipLabel.js +10 -7
  3. package/dist/components/AiContextButton.d.ts +1 -1
  4. package/dist/components/AiContextButton.d.ts.map +1 -1
  5. package/dist/components/AiContextButton.js +25 -12
  6. package/dist/components/AiImageButton.d.ts.map +1 -1
  7. package/dist/components/AiImageButton.js +32 -16
  8. package/dist/components/AiInput.d.ts.map +1 -1
  9. package/dist/components/AiInput.js +15 -5
  10. package/dist/components/AiModelSelect.d.ts.map +1 -1
  11. package/dist/components/AiModelSelect.js +3 -1
  12. package/dist/components/AiPromptPanel.d.ts.map +1 -1
  13. package/dist/components/AiPromptPanel.js +72 -47
  14. package/dist/components/AiSelect.d.ts.map +1 -1
  15. package/dist/components/AiSelect.js +8 -3
  16. package/dist/components/AiStatusButton.d.ts.map +1 -1
  17. package/dist/components/AiStatusButton.js +23 -20
  18. package/dist/components/AiTextarea.d.ts.map +1 -1
  19. package/dist/components/AiTextarea.js +19 -6
  20. package/dist/components/ErrorToast.d.ts.map +1 -1
  21. package/dist/components/ErrorToast.js +4 -2
  22. package/dist/components/LBApiKeySelector.d.ts.map +1 -1
  23. package/dist/components/LBApiKeySelector.js +13 -5
  24. package/dist/components/LBConnectButton.d.ts.map +1 -1
  25. package/dist/components/LBConnectButton.js +8 -3
  26. package/dist/components/LBKeyPicker.d.ts.map +1 -1
  27. package/dist/components/LBKeyPicker.js +8 -4
  28. package/dist/components/LBSigninModal.d.ts.map +1 -1
  29. package/dist/components/LBSigninModal.js +13 -7
  30. package/dist/components/UsageToast.d.ts.map +1 -1
  31. package/dist/components/UsageToast.js +4 -2
  32. package/dist/context/I18nContext.d.ts +15 -0
  33. package/dist/context/I18nContext.d.ts.map +1 -0
  34. package/dist/context/I18nContext.js +44 -0
  35. package/dist/context/LBAuthProvider.d.ts +4 -1
  36. package/dist/context/LBAuthProvider.d.ts.map +1 -1
  37. package/dist/context/LBAuthProvider.js +3 -2
  38. package/dist/hooks/useAiCallImage.d.ts.map +1 -1
  39. package/dist/hooks/useAiCallImage.js +1 -107
  40. package/dist/hooks/useAiCallText.d.ts.map +1 -1
  41. package/dist/hooks/useAiCallText.js +1 -25
  42. package/dist/hooks/useLoadingTimer.d.ts +5 -0
  43. package/dist/hooks/useLoadingTimer.d.ts.map +1 -0
  44. package/dist/hooks/useLoadingTimer.js +27 -0
  45. package/dist/i18n/de.json +62 -0
  46. package/dist/i18n/en.json +128 -0
  47. package/dist/i18n/es.json +70 -0
  48. package/dist/i18n/fr.json +128 -0
  49. package/dist/i18n/it.json +62 -0
  50. package/dist/i18n/pt.json +62 -0
  51. package/dist/index.d.ts +2 -0
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +2 -0
  54. package/dist/styles.css +141 -1
  55. package/package.json +3 -3
  56. package/src/components/AiChipLabel.tsx +17 -8
  57. package/src/components/AiContextButton.tsx +44 -20
  58. package/src/components/AiImageButton.tsx +52 -25
  59. package/src/components/AiInput.tsx +20 -5
  60. package/src/components/AiModelSelect.tsx +3 -1
  61. package/src/components/AiPromptPanel.tsx +177 -59
  62. package/src/components/AiSelect.tsx +8 -3
  63. package/src/components/AiStatusButton.tsx +51 -40
  64. package/src/components/AiTextarea.tsx +24 -6
  65. package/src/components/ErrorToast.tsx +4 -2
  66. package/src/components/LBApiKeySelector.tsx +33 -13
  67. package/src/components/LBConnectButton.tsx +9 -3
  68. package/src/components/LBKeyPicker.tsx +10 -4
  69. package/src/components/LBSigninModal.tsx +31 -15
  70. package/src/components/UsageToast.tsx +4 -2
  71. package/src/context/I18nContext.tsx +71 -0
  72. package/src/context/LBAuthProvider.tsx +9 -1
  73. package/src/hooks/useAiCallImage.ts +1 -149
  74. package/src/hooks/useAiCallText.ts +1 -30
  75. package/src/hooks/useLoadingTimer.ts +32 -0
  76. package/src/i18n/de.json +62 -0
  77. package/src/i18n/en.json +128 -0
  78. package/src/i18n/es.json +70 -0
  79. package/src/i18n/fr.json +128 -0
  80. package/src/i18n/it.json +62 -0
  81. package/src/i18n/pt.json +62 -0
  82. package/src/index.ts +2 -0
  83. package/src/styles.css +141 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorToast.d.ts","sourceRoot":"","sources":["../../src/components/ErrorToast.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAI5B,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,eAAe;IACvB,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;IACrE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAyB,EACzB,UAAU,GACX,EAAE,eAAe,kDA4IjB;AAED,wBAAgB,aAAa;4BAII,cAAc;;;;EAgB9C"}
1
+ {"version":3,"file":"ErrorToast.d.ts","sourceRoot":"","sources":["../../src/components/ErrorToast.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAK5B,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,eAAe;IACvB,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;IACrE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAyB,EACzB,UAAU,GACX,EAAE,eAAe,kDA6IjB;AAED,wBAAgB,aAAa;4BAII,cAAc;;;;EAgB9C"}
@@ -3,7 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import "../styles/register";
4
4
  import { useEffect, useRef, useState } from "react";
5
5
  import { X, AlertCircle } from "lucide-react";
6
+ import { useI18n } from "../context/I18nContext";
6
7
  export function ErrorToast({ error, position = "bottom-right", onComplete, }) {
8
+ const { t } = useI18n();
7
9
  const [isVisible, setIsVisible] = useState(false);
8
10
  const [isClosing, setIsClosing] = useState(false);
9
11
  const fadeTimeoutRef = useRef(null);
@@ -81,7 +83,7 @@ export function ErrorToast({ error, position = "bottom-right", onComplete, }) {
81
83
  WebkitBackdropFilter: "blur(8px)",
82
84
  maxWidth: "400px",
83
85
  minWidth: "280px",
84
- }, children: [_jsx(AlertCircle, { size: 16, style: { marginTop: "2px", flexShrink: 0 } }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsxs("div", { style: { fontWeight: 600, marginBottom: "2px" }, children: ["Erreur", error.code && (_jsxs("span", { style: {
86
+ }, children: [_jsx(AlertCircle, { size: 16, style: { marginTop: "2px", flexShrink: 0 } }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsxs("div", { style: { fontWeight: 600, marginBottom: "2px" }, children: [t("common.errorTitle", "Error"), error.code && (_jsxs("span", { style: {
85
87
  marginLeft: "8px",
86
88
  fontSize: "10px",
87
89
  opacity: 0.7,
@@ -102,7 +104,7 @@ export function ErrorToast({ error, position = "bottom-right", onComplete, }) {
102
104
  e.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.2)";
103
105
  }, onMouseLeave: (e) => {
104
106
  e.currentTarget.style.backgroundColor = "transparent";
105
- }, title: "Fermer", children: _jsx(X, { size: 14 }) })] }));
107
+ }, title: t("common.closeLabel", "Close"), children: _jsx(X, { size: 14 }) })] }));
106
108
  }
107
109
  export function useErrorToast() {
108
110
  const [errorData, setErrorData] = useState(null);
@@ -1 +1 @@
1
- {"version":3,"file":"LBApiKeySelector.d.ts","sourceRoot":"","sources":["../../src/components/LBApiKeySelector.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,MAAM,GACP,EAAE,qBAAqB,kDAsIvB"}
1
+ {"version":3,"file":"LBApiKeySelector.d.ts","sourceRoot":"","sources":["../../src/components/LBApiKeySelector.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,MAAM,GACP,EAAE,qBAAqB,kDAuJvB"}
@@ -1,7 +1,10 @@
1
+ "use client";
1
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
3
  import { useState } from "react";
3
4
  import { CheckCircle2, KeyRound, Loader2, XCircle } from "lucide-react";
5
+ import { useI18n } from "../context/I18nContext";
4
6
  export function LBApiKeySelector({ apiKeys, onSelect, onCancel, isOpen, }) {
7
+ const { t } = useI18n();
5
8
  const [selectedKeyId, setSelectedKeyId] = useState(apiKeys.find((k) => k.isActive)?.id || apiKeys[0]?.id || "");
6
9
  const [loading, setLoading] = useState(false);
7
10
  const [error, setError] = useState("");
@@ -10,7 +13,7 @@ export function LBApiKeySelector({ apiKeys, onSelect, onCancel, isOpen, }) {
10
13
  const handleSubmit = async (e) => {
11
14
  e.preventDefault();
12
15
  if (!selectedKeyId) {
13
- setError("Veuillez sélectionner une clé API");
16
+ setError(t("status.selectApiKey", "Select an API key"));
14
17
  return;
15
18
  }
16
19
  setLoading(true);
@@ -19,13 +22,18 @@ export function LBApiKeySelector({ apiKeys, onSelect, onCancel, isOpen, }) {
19
22
  await onSelect(selectedKeyId);
20
23
  }
21
24
  catch (err) {
22
- setError(err instanceof Error ? err.message : "Erreur lors de la sélection");
25
+ setError(err instanceof Error
26
+ ? err.message
27
+ : t("auth.modal.selectionError", "Selection error"));
23
28
  setLoading(false);
24
29
  }
25
30
  };
26
- return (_jsx("div", { className: "ai-signin-overlay", onClick: onCancel, children: _jsxs("div", { className: "ai-signin-panel ai-key-modal-panel", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "ai-signin-header", children: [_jsx("div", { className: "ai-center mb-3", children: _jsx("span", { className: "ai-icon-badge", children: _jsx(KeyRound, { size: 20 }) }) }), _jsx("h2", { className: "ai-signin-title", children: "S\u00E9lectionnez une cl\u00E9 API" }), _jsx("p", { className: "ai-signin-subtitle", children: "Choisissez la cl\u00E9 API \u00E0 utiliser pour vos requ\u00EAtes IA." })] }), _jsx("div", { className: "ai-signin-content", children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx("div", { className: "ai-model-mgmt-list", style: { maxHeight: 300, overflowY: "auto", marginBottom: 16 }, children: apiKeys.map((key) => {
31
+ return (_jsx("div", { className: "ai-signin-overlay", onClick: onCancel, children: _jsxs("div", { className: "ai-signin-panel ai-key-modal-panel", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "ai-signin-header", children: [_jsx("div", { className: "ai-center mb-3", children: _jsx("span", { className: "ai-icon-badge", children: _jsx(KeyRound, { size: 20 }) }) }), _jsx("h2", { className: "ai-signin-title", children: t("status.selectApiKey", "Select an API key") }), _jsx("p", { className: "ai-signin-subtitle", children: t("status.selectApiKeySubtitle", "Choose the API key to use for your AI requests.") })] }), _jsx("div", { className: "ai-signin-content", children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx("div", { className: "ai-model-mgmt-list", style: { maxHeight: 300, overflowY: "auto", marginBottom: 16 }, children: apiKeys.map((key) => {
27
32
  const isSelected = key.id === selectedKeyId;
28
33
  const isActive = key.isActive;
29
- return (_jsxs("label", { className: `ai-model-item ${isSelected ? "ai-model-item--active" : ""} ${!isActive ? "ai-model-item--disabled" : ""}`, children: [_jsxs("div", { className: "ai-model-item-main", children: [_jsx("input", { type: "radio", name: "apiKey", value: key.id, checked: isSelected, disabled: !isActive, onChange: (e) => setSelectedKeyId(e.target.value), className: "ai-key-radio" }), _jsxs("div", { children: [_jsx("div", { className: "ai-model-item-title", children: key.name }), _jsx("div", { className: "ai-model-item-meta", children: _jsx("span", { children: key.keyPrefix || key.id.substring(0, 12) + "..." }) })] })] }), isActive ? (_jsxs("span", { className: "ai-pill ai-pill--cost", children: [_jsx(CheckCircle2, { size: 12 }), "Active"] })) : (_jsxs("span", { className: "ai-pill ai-pill--cost", children: [_jsx(XCircle, { size: 12 }), "Inactive"] }))] }, key.id));
30
- }) }), error ? (_jsxs("div", { className: "ai-signin-error", role: "alert", children: [_jsx(XCircle, { size: 16 }), _jsx("span", { children: error })] })) : null, _jsxs("div", { className: "ai-signin-actions", children: [_jsx("button", { type: "button", onClick: onCancel, disabled: loading, className: "ai-btn ai-btn--ghost", children: "Annuler" }), _jsx("button", { type: "submit", disabled: loading || !selectedKeyId, className: "ai-btn ai-btn--primary", children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), "Connexion..."] })) : ("Continuer") })] })] }) })] }) }));
34
+ const rawEnv = key.env;
35
+ const keyEnv = rawEnv === "dev" ? "DEV" : "PROD";
36
+ const isDev = rawEnv === "dev";
37
+ return (_jsxs("label", { className: `ai-model-item ${isSelected ? "ai-model-item--active" : ""} ${!isActive ? "ai-model-item--disabled" : ""}`, children: [_jsxs("div", { className: "ai-model-item-main", children: [_jsx("input", { type: "radio", name: "apiKey", value: key.id, checked: isSelected, disabled: !isActive, onChange: (e) => setSelectedKeyId(e.target.value), className: "ai-key-radio" }), _jsxs("div", { children: [_jsx("div", { className: "ai-model-item-title", children: key.name }), _jsxs("div", { className: "ai-model-item-meta", children: [_jsx("span", { children: key.keyPrefix || key.id.substring(0, 12) + "..." }), _jsx("span", { className: `ai-pill ai-pill--cost ${isDev ? "ai-pill--warning" : ""}`, style: { marginLeft: 8 }, children: keyEnv })] })] })] }), isActive ? (_jsxs("span", { className: "ai-pill ai-pill--cost", children: [_jsx(CheckCircle2, { size: 12 }), t("common.active", "Active")] })) : (_jsxs("span", { className: "ai-pill ai-pill--cost", children: [_jsx(XCircle, { size: 12 }), t("common.inactive", "Inactive")] }))] }, key.id));
38
+ }) }), error ? (_jsxs("div", { className: "ai-signin-error", role: "alert", children: [_jsx(XCircle, { size: 16 }), _jsx("span", { children: error })] })) : null, _jsxs("div", { className: "ai-signin-actions", children: [_jsx("button", { type: "button", onClick: onCancel, disabled: loading, className: "ai-btn ai-btn--ghost", children: t("common.cancel", "Cancel") }), _jsx("button", { type: "submit", disabled: loading || !selectedKeyId, className: "ai-btn ai-btn--primary", children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), t("auth.modal.connecting", "Signing in...")] })) : (t("common.continue", "Continue")) })] })] }) })] }) }));
31
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LBConnectButton.d.ts","sourceRoot":"","sources":["../../src/components/LBConnectButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAM5B,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAsB,EACtB,SAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE,oBAAoB,2CAoDtB;AAED;;;GAGG;AACH,UAAU,gBAAgB;IACxB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAExD"}
1
+ {"version":3,"file":"LBConnectButton.d.ts","sourceRoot":"","sources":["../../src/components/LBConnectButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAO5B,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,SAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE,oBAAoB,2CAyDtB;AAED;;;GAGG;AACH,UAAU,gBAAgB;IACxB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAExD"}
@@ -5,7 +5,9 @@ import React from "react";
5
5
  import { Loader2, LogIn, LogOut } from "lucide-react";
6
6
  import { useLB } from "../context/LBAuthProvider";
7
7
  import { LBSigninModal } from "./LBSigninModal";
8
- export function LBConnectButton({ label = "Se connecter", className = "", onConnected, onOpenModal, }) {
8
+ import { useI18n } from "../context/I18nContext";
9
+ export function LBConnectButton({ label, className = "", onConnected, onOpenModal, }) {
10
+ const { t } = useI18n();
9
11
  const { status, user, logout } = useLB();
10
12
  const [showModal, setShowModal] = React.useState(false);
11
13
  React.useEffect(() => {
@@ -22,8 +24,11 @@ export function LBConnectButton({ label = "Se connecter", className = "", onConn
22
24
  setShowModal(true);
23
25
  onOpenModal?.();
24
26
  };
25
- const buttonLabel = status === "ready" && user ? "Déconnexion" : label;
26
- return (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: handleClick, className: className || "ai-btn ai-btn--auth", disabled: status === "loading", children: status === "loading" ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "animate-spin" }), "Chargement..."] })) : status === "ready" && user ? (_jsxs(_Fragment, { children: [_jsx(LogOut, { size: 16 }), buttonLabel] })) : (_jsxs(_Fragment, { children: [_jsx(LogIn, { size: 16 }), buttonLabel] })) }), _jsx(LBSigninModal, { isOpen: showModal, onClose: () => setShowModal(false) })] }));
27
+ const connectLabel = label || t("auth.signIn", "Sign in");
28
+ const buttonLabel = status === "ready" && user
29
+ ? t("auth.signOut", "Sign out")
30
+ : connectLabel;
31
+ return (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: handleClick, className: className || "ai-btn ai-btn--auth", disabled: status === "loading", children: status === "loading" ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "animate-spin" }), t("common.loading", "Loading...")] })) : status === "ready" && user ? (_jsxs(_Fragment, { children: [_jsx(LogOut, { size: 16 }), buttonLabel] })) : (_jsxs(_Fragment, { children: [_jsx(LogIn, { size: 16 }), buttonLabel] })) }), _jsx(LBSigninModal, { isOpen: showModal, onClose: () => setShowModal(false) })] }));
27
32
  }
28
33
  export function LBAuthModal({ onClose }) {
29
34
  return _jsx(LBSigninModal, { isOpen: true, onClose: () => onClose(false) });
@@ -1 +1 @@
1
- {"version":3,"file":"LBKeyPicker.d.ts","sourceRoot":"","sources":["../../src/components/LBKeyPicker.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAQ5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,UAAU,gBAAgB;IACxB,+BAA+B;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;CACxC;AAED,wBAAgB,WAAW,CAAC,EAC1B,SAAc,EACd,YAAY,GACb,EAAE,gBAAgB,kDA2HlB"}
1
+ {"version":3,"file":"LBKeyPicker.d.ts","sourceRoot":"","sources":["../../src/components/LBKeyPicker.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAQ5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,UAAU,gBAAgB;IACxB,+BAA+B;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;CACxC;AAED,wBAAgB,WAAW,CAAC,EAC1B,SAAc,EACd,YAAY,GACb,EAAE,gBAAgB,kDAgIlB"}
@@ -7,7 +7,9 @@ import "../styles/register";
7
7
  */
8
8
  import { useEffect, useState } from "react";
9
9
  import { useLB } from "../hooks/useLB";
10
+ import { useI18n } from "../context/I18nContext";
10
11
  export function LBKeyPicker({ className = "", onKeyChanged, }) {
12
+ const { t } = useI18n();
11
13
  const { status, selectedKey, fetchApiKeys, selectApiKey, accessToken } = useLB();
12
14
  const [apiKeys, setApiKeys] = useState([]);
13
15
  const [loading, setLoading] = useState(false);
@@ -27,7 +29,7 @@ export function LBKeyPicker({ className = "", onKeyChanged, }) {
27
29
  setApiKeys(keys);
28
30
  }
29
31
  catch (err) {
30
- setError("Impossible de charger les clés API");
32
+ setError(t("lb.keypicker.loadError", "Unable to load API keys"));
31
33
  }
32
34
  finally {
33
35
  setLoading(false);
@@ -47,7 +49,9 @@ export function LBKeyPicker({ className = "", onKeyChanged, }) {
47
49
  setShowDropdown(false);
48
50
  }
49
51
  catch (err) {
50
- setError(err instanceof Error ? err.message : "Échec du changement de clé");
52
+ setError(err instanceof Error
53
+ ? err.message
54
+ : t("lb.keypicker.switchError", "Failed to switch API key"));
51
55
  }
52
56
  finally {
53
57
  setLoading(false);
@@ -56,7 +60,7 @@ export function LBKeyPicker({ className = "", onKeyChanged, }) {
56
60
  if (status !== "ready" || !selectedKey) {
57
61
  return null;
58
62
  }
59
- return (_jsxs("div", { className: `relative ${className}`, children: [_jsxs("button", { onClick: () => setShowDropdown(!showDropdown), disabled: loading, className: "px-4 py-2 border rounded hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 flex items-center gap-2", children: [_jsxs("span", { className: "font-mono text-sm", children: [selectedKey.keyPrefix, "..."] }), _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })] }), showDropdown && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-10", onClick: () => setShowDropdown(false) }), _jsxs("div", { className: "absolute right-0 mt-2 w-64 bg-white dark:bg-gray-800 border rounded-lg shadow-lg z-20", children: [_jsxs("div", { className: "p-2", children: [_jsx("div", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 px-3 py-2", children: "Changer de cl\u00E9 API" }), _jsx("div", { className: "space-y-1", children: apiKeys.map((key) => (_jsxs("button", { onClick: () => handleSelectKey(key.id), disabled: !key.isActive || loading || key.id === selectedKey.id, className: `w-full text-left px-3 py-2 rounded text-sm ${key.id === selectedKey.id
63
+ return (_jsxs("div", { className: `relative ${className}`, children: [_jsxs("button", { onClick: () => setShowDropdown(!showDropdown), disabled: loading, className: "px-4 py-2 border rounded hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 flex items-center gap-2", children: [_jsxs("span", { className: "font-mono text-sm", children: [selectedKey.keyPrefix, "..."] }), _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })] }), showDropdown && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-10", onClick: () => setShowDropdown(false) }), _jsxs("div", { className: "absolute right-0 mt-2 w-64 bg-white dark:bg-gray-800 border rounded-lg shadow-lg z-20", children: [_jsxs("div", { className: "p-2", children: [_jsx("div", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 px-3 py-2", children: t("lb.keypicker.changeApiKey", "Switch API key") }), _jsx("div", { className: "space-y-1", children: apiKeys.map((key) => (_jsxs("button", { onClick: () => handleSelectKey(key.id), disabled: !key.isActive || loading || key.id === selectedKey.id, className: `w-full text-left px-3 py-2 rounded text-sm ${key.id === selectedKey.id
60
64
  ? "bg-blue-100 dark:bg-blue-900"
61
- : "hover:bg-gray-100 dark:hover:bg-gray-700"} disabled:opacity-50 disabled:cursor-not-allowed`, children: [_jsx("div", { className: "font-medium", children: key.name }), _jsxs("div", { className: "text-xs text-gray-500 font-mono", children: [key.keyPrefix, "..."] }), !key.isActive && (_jsx("div", { className: "text-xs text-red-600", children: "Inactive" }))] }, key.id))) })] }), error && (_jsx("div", { className: "px-3 py-2 text-xs text-red-600 border-t", children: error }))] })] }))] }));
65
+ : "hover:bg-gray-100 dark:hover:bg-gray-700"} disabled:opacity-50 disabled:cursor-not-allowed`, children: [_jsx("div", { className: "font-medium", children: key.name }), _jsxs("div", { className: "text-xs text-gray-500 font-mono", children: [key.keyPrefix, "..."] }), !key.isActive && (_jsx("div", { className: "text-xs text-red-600", children: t("common.inactive", "Inactive") }))] }, key.id))) })] }), error && (_jsx("div", { className: "px-3 py-2 text-xs text-red-600 border-t", children: error }))] })] }))] }));
62
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LBSigninModal.d.ts","sourceRoot":"","sources":["../../src/components/LBSigninModal.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAO5B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,sCAqOpE"}
1
+ {"version":3,"file":"LBSigninModal.d.ts","sourceRoot":"","sources":["../../src/components/LBSigninModal.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAQ5B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,sCAoPpE"}
@@ -6,8 +6,10 @@ import { createPortal } from "react-dom";
6
6
  import { AlertCircle, Loader2, Lock, Mail, Sparkles, X } from "lucide-react";
7
7
  import { useLB } from "../context/LBAuthProvider";
8
8
  import { LBApiKeySelector } from "./LBApiKeySelector";
9
+ import { useI18n } from "../context/I18nContext";
9
10
  export function LBSigninModal({ isOpen, onClose }) {
10
11
  const lbContext = useLB();
12
+ const { t } = useI18n();
11
13
  const [portalRoot, setPortalRoot] = useState(null);
12
14
  const [email, setEmail] = useState("");
13
15
  const [password, setPassword] = useState("");
@@ -17,7 +19,7 @@ export function LBSigninModal({ isOpen, onClose }) {
17
19
  const [currentApiKeys, setCurrentApiKeys] = useState([]);
18
20
  const { login, selectApiKeyWithToken, fetchApiKeys } = lbContext || {};
19
21
  const canRender = Boolean(isOpen && lbContext && login);
20
- const panelTitle = useMemo(() => "Connexion LastBrain", []);
22
+ const panelTitle = useMemo(() => t("auth.modal.title", "LastBrain Sign In"), [t]);
21
23
  useEffect(() => {
22
24
  setPortalRoot(document.body);
23
25
  }, []);
@@ -34,7 +36,7 @@ export function LBSigninModal({ isOpen, onClose }) {
34
36
  try {
35
37
  const result = await login(email, password);
36
38
  if (!result.success) {
37
- setError(result.error || "Échec de la connexion");
39
+ setError(result.error || t("auth.modal.loginFailed", "Login failed"));
38
40
  return;
39
41
  }
40
42
  if (!result.needsKeySelection) {
@@ -42,7 +44,7 @@ export function LBSigninModal({ isOpen, onClose }) {
42
44
  return;
43
45
  }
44
46
  if (!fetchApiKeys || !result.accessToken) {
45
- setError("Token d'accès non disponible");
47
+ setError(t("auth.modal.tokenMissing", "Access token unavailable"));
46
48
  return;
47
49
  }
48
50
  try {
@@ -52,11 +54,13 @@ export function LBSigninModal({ isOpen, onClose }) {
52
54
  }
53
55
  catch (keyError) {
54
56
  console.error("Failed to fetch API keys:", keyError);
55
- setError("Erreur lors de la récupération des clés API");
57
+ setError(t("auth.modal.apiKeysFetchError", "Failed to fetch API keys"));
56
58
  }
57
59
  }
58
60
  catch (err) {
59
- setError(err instanceof Error ? err.message : "Une erreur s'est produite");
61
+ setError(err instanceof Error
62
+ ? err.message
63
+ : t("auth.modal.genericError", "An error occurred"));
60
64
  }
61
65
  finally {
62
66
  setLoading(false);
@@ -72,7 +76,9 @@ export function LBSigninModal({ isOpen, onClose }) {
72
76
  onClose();
73
77
  }
74
78
  catch (err) {
75
- setError(err instanceof Error ? err.message : "Erreur lors de la sélection");
79
+ setError(err instanceof Error
80
+ ? err.message
81
+ : t("auth.modal.selectionError", "Selection error"));
76
82
  setShowKeySelector(false);
77
83
  }
78
84
  };
@@ -87,5 +93,5 @@ export function LBSigninModal({ isOpen, onClose }) {
87
93
  if (e.key === "Escape") {
88
94
  onClose();
89
95
  }
90
- }, role: "dialog", "aria-modal": "true", "aria-label": panelTitle, children: _jsxs("div", { className: "ai-signin-panel", onClick: (e) => e.stopPropagation(), children: [_jsx("button", { type: "button", className: "ai-icon-btn ai-signin-close", onClick: onClose, "aria-label": "Fermer", children: _jsx(X, { size: 16 }) }), _jsxs("div", { className: "ai-signin-header", children: [_jsx("div", { className: "ai-center mb-3", children: _jsx("span", { className: "ai-icon-badge", children: _jsx(Sparkles, { size: 22 }) }) }), _jsx("h2", { className: "ai-signin-title", children: panelTitle }), _jsx("p", { className: "ai-signin-subtitle", children: "Connectez-vous pour activer les composants IA dans votre app." })] }), _jsx("div", { className: "ai-signin-content", children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsxs("div", { className: "ai-input-row", children: [_jsxs("label", { htmlFor: "lb-signin-email", className: "ai-input-label ai-row", children: [_jsx(Mail, { size: 14, className: "ai-inline-icon" }), "Email"] }), _jsx("div", { className: "ai-control-group ai-glow", children: _jsx("div", { className: "ai-shell ai-size-md ai-radius-full", children: _jsx("input", { id: "lb-signin-email", className: "ai-control ai-control-input ai-size-md ai-radius-full", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, autoFocus: true, autoComplete: "email", placeholder: "votre@email.com" }) }) })] }), _jsxs("div", { className: "ai-input-row", children: [_jsxs("label", { htmlFor: "lb-signin-password", className: "ai-input-label ai-row", children: [_jsx(Lock, { size: 14, className: "ai-inline-icon" }), "Mot de passe"] }), _jsx("div", { className: "ai-control-group ai-glow", children: _jsx("div", { className: "ai-shell ai-size-md ai-radius-full", children: _jsx("input", { id: "lb-signin-password", className: "ai-control ai-control-input ai-size-md ai-radius-full", type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }) }) })] }), error ? (_jsxs("div", { className: "ai-signin-error", role: "alert", children: [_jsx(AlertCircle, { size: 16 }), _jsx("span", { children: error })] })) : null, _jsxs("div", { className: "ai-signin-actions", children: [_jsx("button", { type: "submit", className: "ai-btn ai-btn--auth", disabled: loading, children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), "Connexion..."] })) : (_jsxs(_Fragment, { children: [_jsx(Sparkles, { size: 16 }), "Se connecter"] })) }), _jsx("a", { href: "https://prompt.lastbrain.io/signup", target: "_blank", rel: "noopener noreferrer", className: "ai-btn ai-btn--ghost", children: "Cr\u00E9er un compte" })] })] }) })] }) }), portalRoot);
96
+ }, role: "dialog", "aria-modal": "true", "aria-label": panelTitle, children: _jsxs("div", { className: "ai-signin-panel", onClick: (e) => e.stopPropagation(), children: [_jsx("button", { type: "button", className: "ai-icon-btn ai-signin-close", onClick: onClose, "aria-label": t("common.close", "Close"), children: _jsx(X, { size: 16 }) }), _jsxs("div", { className: "ai-signin-header", children: [_jsx("div", { className: "ai-center mb-3", children: _jsx("span", { className: "ai-icon-badge", children: _jsx(Sparkles, { size: 22 }) }) }), _jsx("h2", { className: "ai-signin-title", children: panelTitle }), _jsx("p", { className: "ai-signin-subtitle", children: t("auth.modal.subtitle", "Sign in to enable AI components in your app.") })] }), _jsx("div", { className: "ai-signin-content", children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsxs("div", { className: "ai-input-row", children: [_jsxs("label", { htmlFor: "lb-signin-email", className: "ai-input-label ai-row", children: [_jsx(Mail, { size: 14, className: "ai-inline-icon" }), t("auth.modal.email", "Email")] }), _jsx("div", { className: "ai-control-group ai-glow", children: _jsx("div", { className: "ai-shell ai-size-md ai-radius-full", children: _jsx("input", { id: "lb-signin-email", className: "ai-control ai-control-input ai-size-md ai-radius-full", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, autoFocus: true, autoComplete: "email", placeholder: t("auth.modal.emailPlaceholder", "your@email.com") }) }) })] }), _jsxs("div", { className: "ai-input-row", children: [_jsxs("label", { htmlFor: "lb-signin-password", className: "ai-input-label ai-row", children: [_jsx(Lock, { size: 14, className: "ai-inline-icon" }), t("auth.modal.password", "Password")] }), _jsx("div", { className: "ai-control-group ai-glow", children: _jsx("div", { className: "ai-shell ai-size-md ai-radius-full", children: _jsx("input", { id: "lb-signin-password", className: "ai-control ai-control-input ai-size-md ai-radius-full", type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password", placeholder: t("auth.modal.passwordPlaceholder", "••••••••") }) }) })] }), error ? (_jsxs("div", { className: "ai-signin-error", role: "alert", children: [_jsx(AlertCircle, { size: 16 }), _jsx("span", { children: error })] })) : null, _jsxs("div", { className: "ai-signin-actions", children: [_jsx("button", { type: "submit", className: "ai-btn ai-btn--auth", disabled: loading, children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), t("auth.modal.connecting", "Signing in...")] })) : (_jsxs(_Fragment, { children: [_jsx(Sparkles, { size: 16 }), t("auth.signIn", "Sign in")] })) }), _jsx("a", { href: "https://prompt.lastbrain.io/signup", target: "_blank", rel: "noopener noreferrer", className: "ai-btn ai-btn--ghost", children: t("auth.modal.createAccount", "Create account") })] })] }) })] }) }), portalRoot);
91
97
  }
@@ -1 +1 @@
1
- {"version":3,"file":"UsageToast.d.ts","sourceRoot":"","sources":["../../src/components/UsageToast.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAI5B,UAAU,eAAe;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;IACrE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAyB,EACzB,UAAU,GACX,EAAE,eAAe,kDAkJjB;AAED,wBAAgB,aAAa;6BAIK,OAAO;;;;EAgBxC"}
1
+ {"version":3,"file":"UsageToast.d.ts","sourceRoot":"","sources":["../../src/components/UsageToast.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAK5B,UAAU,eAAe;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;IACrE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAyB,EACzB,UAAU,GACX,EAAE,eAAe,kDAmJjB;AAED,wBAAgB,aAAa;6BAIK,OAAO;;;;EAgBxC"}
@@ -3,7 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import "../styles/register";
4
4
  import { useEffect, useRef, useState } from "react";
5
5
  import { X } from "lucide-react";
6
+ import { useI18n } from "../context/I18nContext";
6
7
  export function UsageToast({ result, position = "bottom-right", onComplete, }) {
8
+ const { t } = useI18n();
7
9
  const [isVisible, setIsVisible] = useState(false);
8
10
  const [isClosing, setIsClosing] = useState(false);
9
11
  const fadeTimeoutRef = useRef(null);
@@ -67,7 +69,7 @@ export function UsageToast({ result, position = "bottom-right", onComplete, }) {
67
69
  }
68
70
  // Remove trailing zeros
69
71
  formatted = parseFloat(formatted).toString();
70
- return `${formatted}$ used`;
72
+ return t("usage.toast.used", "{amount}$ used", { amount: formatted });
71
73
  };
72
74
  const message = extractUsageMessage(result);
73
75
  if (!result)
@@ -125,7 +127,7 @@ export function UsageToast({ result, position = "bottom-right", onComplete, }) {
125
127
  e.currentTarget.style.backgroundColor = "rgba(22, 163, 74, 0.2)";
126
128
  }, onMouseLeave: (e) => {
127
129
  e.currentTarget.style.backgroundColor = "transparent";
128
- }, title: "Close", children: _jsx(X, { size: 12 }) })] }));
130
+ }, title: t("common.closeLabel", "Close"), children: _jsx(X, { size: 12 }) })] }));
129
131
  }
130
132
  export function useUsageToast() {
131
133
  const [toastData, setToastData] = useState(null);
@@ -0,0 +1,15 @@
1
+ import { type ReactNode } from "react";
2
+ export type LBSupportedLang = "fr" | "en" | "es" | "it" | "de" | "pt";
3
+ type TranslateParams = Record<string, string | number>;
4
+ interface I18nContextValue {
5
+ lang: LBSupportedLang;
6
+ t: (key: string, fallback?: string, params?: TranslateParams) => string;
7
+ }
8
+ export interface I18nProviderProps {
9
+ children: ReactNode;
10
+ lang?: LBSupportedLang;
11
+ }
12
+ export declare function I18nProvider({ children, lang }: I18nProviderProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function useI18n(): I18nContextValue;
14
+ export {};
15
+ //# sourceMappingURL=I18nContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"I18nContext.d.ts","sourceRoot":"","sources":["../../src/context/I18nContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAQ3E,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAatE,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEvD,UAAU,gBAAgB;IACxB,IAAI,EAAE,eAAe,CAAC;IACtB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,KAAK,MAAM,CAAC;CACzE;AAeD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,IAAkB,EAAE,EAAE,iBAAiB,2CAkB/E;AAED,wBAAgB,OAAO,qBAEtB"}
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useMemo } from "react";
4
+ import fr from "../i18n/fr.json";
5
+ import en from "../i18n/en.json";
6
+ import es from "../i18n/es.json";
7
+ import it from "../i18n/it.json";
8
+ import de from "../i18n/de.json";
9
+ import pt from "../i18n/pt.json";
10
+ const dictionaries = {
11
+ fr,
12
+ en,
13
+ es,
14
+ it,
15
+ de,
16
+ pt,
17
+ };
18
+ const defaultLang = "fr";
19
+ const I18nContext = createContext({
20
+ lang: defaultLang,
21
+ t: (key, fallback, params) => {
22
+ const template = dictionaries[defaultLang][key] || fallback || key;
23
+ if (!params)
24
+ return template;
25
+ return template.replace(/\{(\w+)\}/g, (_, p) => params[p] !== undefined ? String(params[p]) : `{${p}}`);
26
+ },
27
+ });
28
+ export function I18nProvider({ children, lang = defaultLang }) {
29
+ const safeLang = dictionaries[lang] ? lang : defaultLang;
30
+ const value = useMemo(() => {
31
+ const dict = dictionaries[safeLang] || dictionaries[defaultLang];
32
+ const t = (key, fallback, params) => {
33
+ const template = dict[key] || dictionaries[defaultLang][key] || fallback || key;
34
+ if (!params)
35
+ return template;
36
+ return template.replace(/\{(\w+)\}/g, (_, p) => params[p] !== undefined ? String(params[p]) : `{${p}}`);
37
+ };
38
+ return { lang: safeLang, t };
39
+ }, [safeLang]);
40
+ return _jsx(I18nContext.Provider, { value: value, children: children });
41
+ }
42
+ export function useI18n() {
43
+ return useContext(I18nContext);
44
+ }
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { type ReactNode } from "react";
6
6
  import type { LBAuthState, LBApiKey, AiStatus } from "@lastbrain/ai-ui-core";
7
+ import { type LBSupportedLang } from "./I18nContext";
7
8
  export interface ApiKeyUser {
8
9
  id?: string;
9
10
  name?: string;
@@ -44,6 +45,8 @@ interface LBProviderProps {
44
45
  onStatusChange?: (status: LBAuthState["status"]) => void;
45
46
  /** Fonction appelée après signin/logout pour refresh les providers */
46
47
  onAuthChange?: () => void;
48
+ /** Langue UI globale des composants ai-ui-react */
49
+ lang?: LBSupportedLang;
47
50
  }
48
51
  interface LBContextValue extends LBAuthState {
49
52
  /** Fonction de connexion */
@@ -88,7 +91,7 @@ interface LBContextValue extends LBAuthState {
88
91
  }
89
92
  declare const LBContext: import("react").Context<LBContextValue | undefined>;
90
93
  export { LBContext };
91
- export declare function LBProvider({ children, baseUrl: _baseUrl, proxyUrl, onStatusChange, onAuthChange, }: LBProviderProps): import("react/jsx-runtime").JSX.Element;
94
+ export declare function LBProvider({ children, baseUrl: _baseUrl, proxyUrl, onStatusChange, onAuthChange, lang, }: LBProviderProps): import("react/jsx-runtime").JSX.Element;
92
95
  /**
93
96
  * Hook pour accéder au contexte LastBrain
94
97
  */
@@ -1 +1 @@
1
- {"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LBAuthProvider.d.ts","sourceRoot":"","sources":["../../src/context/LBAuthProvider.tsx"],"names":[],"mappings":"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"}
@@ -6,10 +6,11 @@ import { jsx as _jsx } from "react/jsx-runtime";
6
6
  */
7
7
  import { createContext, useContext, useEffect, useCallback, useMemo, useState, } from "react";
8
8
  import { createLBClient } from "@lastbrain/ai-ui-core";
9
+ import { I18nProvider } from "./I18nContext";
9
10
  const LBContext = createContext(undefined);
10
11
  // Export pour usage dans d'autres composants
11
12
  export { LBContext };
12
- export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", proxyUrl = "/api/lastbrain", onStatusChange, onAuthChange, }) {
13
+ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", proxyUrl = "/api/lastbrain", onStatusChange, onAuthChange, lang = "fr", }) {
13
14
  const [state, setState] = useState({
14
15
  status: "loading",
15
16
  });
@@ -453,7 +454,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
453
454
  isLoadingStatus,
454
455
  isLoadingStorage,
455
456
  };
456
- return _jsx(LBContext.Provider, { value: value, children: children });
457
+ return (_jsx(I18nProvider, { lang: lang, children: _jsx(LBContext.Provider, { value: value, children: children }) }));
457
458
  }
458
459
  /**
459
460
  * Hook pour accéder au contexte LastBrain
@@ -1 +1 @@
1
- {"version":3,"file":"useAiCallImage.d.ts","sourceRoot":"","sources":["../../src/hooks/useAiCallImage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AA8H7E,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,cAAc,CAC5B,OAAO,CAAC,EAAE,qBAAqB,GAC9B,oBAAoB,CAsDtB"}
1
+ {"version":3,"file":"useAiCallImage.d.ts","sourceRoot":"","sources":["../../src/hooks/useAiCallImage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7E,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,cAAc,CAC5B,OAAO,CAAC,EAAE,qBAAqB,GAC9B,oBAAoB,CA6BtB"}
@@ -1,95 +1,6 @@
1
1
  "use client";
2
2
  import { useState, useCallback } from "react";
3
3
  import { useAiClient } from "./useAiClient";
4
- /**
5
- * Génère une image Canvas pour l'environnement de développement
6
- */
7
- async function generateDevImage(prompt, width, height) {
8
- // Créer un canvas
9
- const canvas = document.createElement("canvas");
10
- const ctx = canvas.getContext("2d");
11
- if (!ctx) {
12
- throw new Error("Could not create canvas context");
13
- }
14
- canvas.width = width;
15
- canvas.height = height;
16
- // Générer des couleurs basées sur le prompt
17
- const promptHash = prompt
18
- .split("")
19
- .reduce((hash, char) => (hash * 31 + char.charCodeAt(0)) % 255, 0);
20
- // Couleurs de base dégradées
21
- const colors = [
22
- `hsl(${(promptHash * 7) % 360}, 70%, 60%)`,
23
- `hsl(${(promptHash * 11) % 360}, 60%, 70%)`,
24
- `hsl(${(promptHash * 13) % 360}, 50%, 80%)`,
25
- ];
26
- // Créer un dégradé radial
27
- const gradient = ctx.createRadialGradient(width / 2, height / 2, 0, width / 2, height / 2, Math.max(width, height) / 2);
28
- gradient.addColorStop(0, colors[0]);
29
- gradient.addColorStop(0.5, colors[1]);
30
- gradient.addColorStop(1, colors[2]);
31
- // Remplir le fond
32
- ctx.fillStyle = gradient;
33
- ctx.fillRect(0, 0, width, height);
34
- // Ajouter des formes géométriques basées sur le prompt
35
- const shapes = prompt.split(" ").slice(0, 5);
36
- shapes.forEach((word, index) => {
37
- const wordHash = word
38
- .split("")
39
- .reduce((hash, char) => (hash * 31 + char.charCodeAt(0)) % 1000, 0);
40
- ctx.save();
41
- ctx.globalAlpha = 0.3 + index * 0.1;
42
- ctx.fillStyle = `hsl(${(wordHash * 17) % 360}, 80%, 50%)`;
43
- // Formes différentes selon l'index
44
- const x = (wordHash % (width - 100)) + 50;
45
- const y = ((wordHash * 3) % (height - 100)) + 50;
46
- const size = 30 + (wordHash % 50);
47
- switch (index % 4) {
48
- case 0: // Cercle
49
- ctx.beginPath();
50
- ctx.arc(x, y, size, 0, Math.PI * 2);
51
- ctx.fill();
52
- break;
53
- case 1: // Carré
54
- ctx.fillRect(x - size / 2, y - size / 2, size, size);
55
- break;
56
- case 2: // Triangle
57
- ctx.beginPath();
58
- ctx.moveTo(x, y - size / 2);
59
- ctx.lineTo(x - size / 2, y + size / 2);
60
- ctx.lineTo(x + size / 2, y + size / 2);
61
- ctx.closePath();
62
- ctx.fill();
63
- break;
64
- case 3: // Losange
65
- ctx.save();
66
- ctx.translate(x, y);
67
- ctx.rotate((wordHash / 100) % (Math.PI * 2));
68
- ctx.fillRect(-size / 2, -size / 2, size, size);
69
- ctx.restore();
70
- break;
71
- }
72
- ctx.restore();
73
- });
74
- // Ajouter le texte du prompt en overlay
75
- ctx.save();
76
- ctx.fillStyle = "rgba(255, 255, 255, 0.9)";
77
- ctx.font = `bold ${Math.min(width, height) / 30}px system-ui, -apple-system, sans-serif`;
78
- ctx.textAlign = "center";
79
- ctx.textBaseline = "middle";
80
- // Fond semi-transparent pour le texte
81
- const textMetrics = ctx.measureText(prompt);
82
- const textWidth = textMetrics.width;
83
- const textHeight = parseInt(ctx.font);
84
- ctx.fillStyle = "rgba(0, 0, 0, 0.6)";
85
- ctx.fillRect(width / 2 - textWidth / 2 - 20, height / 2 - textHeight / 2 - 10, textWidth + 40, textHeight + 20);
86
- // Texte du prompt
87
- ctx.fillStyle = "white";
88
- ctx.fillText(prompt, width / 2, height / 2);
89
- ctx.restore();
90
- // Convertir en data URL
91
- return canvas.toDataURL("image/png", 0.8);
92
- }
93
4
  export function useAiCallImage(options) {
94
5
  const client = useAiClient(options);
95
6
  const [loading, setLoading] = useState(false);
@@ -98,23 +9,6 @@ export function useAiCallImage(options) {
98
9
  setLoading(true);
99
10
  setError(null);
100
11
  try {
101
- // Vérifier si on est en mode dev (API key contient "dev")
102
- if (options?.apiKeyId?.includes("dev")) {
103
- // Simulation complète pour l'environnement dev
104
- await new Promise((resolve) => setTimeout(resolve, 2000)); // Délai réaliste pour simuler l'API
105
- // Parse size format "1024x1024" or default to "1024x1024"
106
- const sizeMatch = request.size?.match(/(\d+)x(\d+)/);
107
- const width = sizeMatch ? parseInt(sizeMatch[1]) : 1024;
108
- const height = sizeMatch ? parseInt(sizeMatch[2]) : 1024;
109
- // Créer une image générée avec Canvas
110
- const imageUrl = await generateDevImage(request.prompt, width, height);
111
- return {
112
- requestId: `dev-img-${Date.now()}`,
113
- url: imageUrl,
114
- debitTokens: 30, // Coût simulé
115
- };
116
- }
117
- // Mode production : appel API normal
118
12
  const result = await client.generateImage(request);
119
13
  return result;
120
14
  }
@@ -126,7 +20,7 @@ export function useAiCallImage(options) {
126
20
  finally {
127
21
  setLoading(false);
128
22
  }
129
- }, [client, options?.apiKeyId]);
23
+ }, [client]);
130
24
  return {
131
25
  generateImage,
132
26
  loading,
@@ -1 +1 @@
1
- {"version":3,"file":"useAiCallText.d.ts","sourceRoot":"","sources":["../../src/hooks/useAiCallText.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG3E,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAC3B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,mBAAmB,CA0DrB"}
1
+ {"version":3,"file":"useAiCallText.d.ts","sourceRoot":"","sources":["../../src/hooks/useAiCallText.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG3E,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAC3B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,mBAAmB,CA6BrB"}
@@ -9,30 +9,6 @@ export function useAiCallText(options) {
9
9
  setLoading(true);
10
10
  setError(null);
11
11
  try {
12
- // Vérifier si on est en mode dev (API key contient "dev")
13
- if (options?.apiKeyId?.includes("dev")) {
14
- // Simulation pour l'environnement dev
15
- await new Promise((resolve) => setTimeout(resolve, 1000)); // Délai pour simuler l'API
16
- let simulatedResult = "";
17
- // Si le prompt contient des mots-clés pour les chips
18
- if (request.prompt.toLowerCase().includes("tags") ||
19
- request.prompt.toLowerCase().includes("chip") ||
20
- request.prompt.toLowerCase().includes("virgule")) {
21
- simulatedResult =
22
- "react, typescript, javascript, frontend, backend, api, development, web, mobile, database";
23
- }
24
- else {
25
- // Lorem ipsum pour les autres cas
26
- simulatedResult =
27
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.";
28
- }
29
- return {
30
- requestId: `dev-${Date.now()}`,
31
- text: simulatedResult,
32
- debitTokens: 150,
33
- };
34
- }
35
- // Mode production : appel API normal
36
12
  const result = await client.generateText(request);
37
13
  return result;
38
14
  }
@@ -44,7 +20,7 @@ export function useAiCallText(options) {
44
20
  finally {
45
21
  setLoading(false);
46
22
  }
47
- }, [client, options?.apiKeyId]);
23
+ }, [client]);
48
24
  return {
49
25
  generateText,
50
26
  loading,