@lastbrain/ai-ui-react 1.0.68 → 1.0.70

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 (76) hide show
  1. package/dist/components/AiChipLabel.d.ts +8 -3
  2. package/dist/components/AiChipLabel.d.ts.map +1 -1
  3. package/dist/components/AiChipLabel.js +23 -70
  4. package/dist/components/AiContextButton.d.ts +10 -2
  5. package/dist/components/AiContextButton.d.ts.map +1 -1
  6. package/dist/components/AiContextButton.js +73 -291
  7. package/dist/components/AiImageButton.d.ts +5 -1
  8. package/dist/components/AiImageButton.d.ts.map +1 -1
  9. package/dist/components/AiImageButton.js +6 -142
  10. package/dist/components/AiInput.d.ts +5 -3
  11. package/dist/components/AiInput.d.ts.map +1 -1
  12. package/dist/components/AiInput.js +13 -25
  13. package/dist/components/AiPromptPanel.d.ts.map +1 -1
  14. package/dist/components/AiPromptPanel.js +64 -212
  15. package/dist/components/AiSelect.d.ts +5 -3
  16. package/dist/components/AiSelect.d.ts.map +1 -1
  17. package/dist/components/AiSelect.js +21 -30
  18. package/dist/components/AiStatusButton.d.ts +4 -1
  19. package/dist/components/AiStatusButton.d.ts.map +1 -1
  20. package/dist/components/AiStatusButton.js +211 -676
  21. package/dist/components/AiTextarea.d.ts +4 -2
  22. package/dist/components/AiTextarea.d.ts.map +1 -1
  23. package/dist/components/AiTextarea.js +14 -26
  24. package/dist/components/LBApiKeySelector.d.ts.map +1 -1
  25. package/dist/components/LBApiKeySelector.js +5 -166
  26. package/dist/components/LBConnectButton.d.ts +4 -7
  27. package/dist/components/LBConnectButton.d.ts.map +1 -1
  28. package/dist/components/LBConnectButton.js +17 -86
  29. package/dist/components/LBSigninModal.d.ts +1 -1
  30. package/dist/components/LBSigninModal.d.ts.map +1 -1
  31. package/dist/components/LBSigninModal.js +42 -320
  32. package/dist/context/LBAuthProvider.d.ts +35 -3
  33. package/dist/context/LBAuthProvider.d.ts.map +1 -1
  34. package/dist/context/LBAuthProvider.js +2 -0
  35. package/dist/examples/AiUiPremiumShowcase.d.ts +2 -0
  36. package/dist/examples/AiUiPremiumShowcase.d.ts.map +1 -0
  37. package/dist/examples/AiUiPremiumShowcase.js +15 -0
  38. package/dist/hooks/useAiModels.d.ts.map +1 -1
  39. package/dist/hooks/useModelManagement.d.ts.map +1 -1
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +2 -0
  43. package/dist/styles/inline.d.ts +1 -0
  44. package/dist/styles/inline.d.ts.map +1 -1
  45. package/dist/styles/inline.js +25 -129
  46. package/dist/styles.css +1268 -369
  47. package/dist/types.d.ts +3 -0
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/utils/errorHandler.d.ts +2 -2
  50. package/dist/utils/errorHandler.d.ts.map +1 -1
  51. package/dist/utils/errorHandler.js +8 -1
  52. package/dist/utils/modelManagement.d.ts +13 -10
  53. package/dist/utils/modelManagement.d.ts.map +1 -1
  54. package/dist/utils/modelManagement.js +19 -2
  55. package/package.json +2 -2
  56. package/src/components/AiChipLabel.tsx +68 -101
  57. package/src/components/AiContextButton.tsx +142 -413
  58. package/src/components/AiImageButton.tsx +29 -190
  59. package/src/components/AiInput.tsx +49 -74
  60. package/src/components/AiPromptPanel.tsx +81 -260
  61. package/src/components/AiSelect.tsx +61 -69
  62. package/src/components/AiStatusButton.tsx +496 -1327
  63. package/src/components/AiTextarea.tsx +50 -63
  64. package/src/components/LBApiKeySelector.tsx +93 -271
  65. package/src/components/LBConnectButton.tsx +39 -336
  66. package/src/components/LBSigninModal.tsx +141 -472
  67. package/src/context/LBAuthProvider.tsx +45 -6
  68. package/src/examples/AiUiPremiumShowcase.tsx +94 -0
  69. package/src/hooks/useAiModels.ts +2 -1
  70. package/src/hooks/useModelManagement.ts +2 -1
  71. package/src/index.ts +3 -0
  72. package/src/styles/inline.ts +27 -148
  73. package/src/styles.css +1268 -369
  74. package/src/types.ts +3 -0
  75. package/src/utils/errorHandler.ts +16 -3
  76. package/src/utils/modelManagement.ts +53 -15
@@ -7,6 +7,7 @@ import {
7
7
  useLayoutEffect,
8
8
  type ReactNode,
9
9
  } from "react";
10
+ import { createPortal } from "react-dom";
10
11
  import { BookOpen, Search, Sparkles, Star, Tag, Settings } from "lucide-react";
11
12
  import type { ModelRef } from "@lastbrain/ai-ui-core";
12
13
  import type { UiMode } from "../types";
@@ -107,8 +108,6 @@ function AiPromptPanelInternal({
107
108
  const [prompt, setPrompt] = useState("");
108
109
  const [promptId, setPromptId] = useState<string | undefined>(undefined);
109
110
  const [isCloseHovered, setIsCloseHovered] = useState(false);
110
- const [isCancelHovered, setIsCancelHovered] = useState(false);
111
- const [isSubmitHovered, setIsSubmitHovered] = useState(false);
112
111
  const [promptFocused, setPromptFocused] = useState(false);
113
112
  const [modelFocused, setModelFocused] = useState(false);
114
113
  const [showPromptLibrary, setShowPromptLibrary] = useState(false);
@@ -116,6 +115,7 @@ function AiPromptPanelInternal({
116
115
  const [selectedTag, setSelectedTag] = useState<string | "all">("all");
117
116
  const [isGenerating, setIsGenerating] = useState(false);
118
117
  const [isClosing, setIsClosing] = useState(false);
118
+ const [portalRoot, setPortalRoot] = useState<HTMLElement | null>(null);
119
119
  const promptRef = useRef<HTMLTextAreaElement>(null);
120
120
  const closeTimeoutRef = useRef<number | null>(null);
121
121
 
@@ -272,6 +272,10 @@ function AiPromptPanelInternal({
272
272
  };
273
273
  }, []);
274
274
 
275
+ useEffect(() => {
276
+ setPortalRoot(document.body);
277
+ }, []);
278
+
275
279
  useEffect(() => {
276
280
  if (!isOpen) {
277
281
  return;
@@ -280,7 +284,9 @@ function AiPromptPanelInternal({
280
284
  setSelectedModel("");
281
285
  return;
282
286
  }
283
- const hasSelected = modelOptions.some((model) => model.id === selectedModel);
287
+ const hasSelected = modelOptions.some(
288
+ (model) => model.id === selectedModel
289
+ );
284
290
  if (!hasSelected) {
285
291
  setSelectedModel(modelOptions[0].id);
286
292
  }
@@ -380,15 +386,20 @@ function AiPromptPanelInternal({
380
386
  onModelToggle: handleModelToggle,
381
387
  };
382
388
 
389
+ if (!portalRoot) {
390
+ return null;
391
+ }
392
+
383
393
  if (children) {
384
- return (
394
+ return createPortal(
385
395
  <div style={aiStyles.modal} onKeyDown={handleKeyDown}>
386
396
  {children(renderProps)}
387
- </div>
397
+ </div>,
398
+ portalRoot
388
399
  );
389
400
  }
390
401
 
391
- return (
402
+ return createPortal(
392
403
  <div style={aiStyles.modal} onKeyDown={handleKeyDown}>
393
404
  <div
394
405
  style={{
@@ -432,22 +443,23 @@ function AiPromptPanelInternal({
432
443
  width: "64px",
433
444
  height: "64px",
434
445
  borderRadius: "999px",
435
- border: "2px solid #8b5cf620",
436
- borderTopColor: "#8b5cf6",
446
+ border:
447
+ "2px solid color-mix(in srgb, var(--ai-primary) 20%, transparent)",
448
+ borderTopColor: "var(--ai-primary)",
437
449
  animation: "ai-spin 1.1s linear infinite",
438
450
  display: "flex",
439
451
  alignItems: "center",
440
452
  justifyContent: "center",
441
- boxShadow: "0 12px 24px rgba(139, 92, 246, 0.15)",
453
+ boxShadow: "0 12px 24px var(--ai-glow)",
442
454
  }}
443
455
  >
444
- <Sparkles size={20} color="#8b5cf6" />
456
+ <Sparkles size={20} color="var(--ai-primary)" />
445
457
  </div>
446
458
  <div
447
459
  style={{
448
460
  fontSize: "13px",
449
461
  fontWeight: 600,
450
- color: "#6b7280",
462
+ color: "var(--ai-text-secondary)",
451
463
  letterSpacing: "0.02em",
452
464
  }}
453
465
  >
@@ -536,25 +548,7 @@ function AiPromptPanelInternal({
536
548
  {effectiveAvailableModels.length > 0 && (
537
549
  <button
538
550
  onClick={() => setIsModelManagementOpen(true)}
539
- style={{
540
- padding: "4px 12px",
541
- fontSize: "12px",
542
- color: "#8b5cf6",
543
- background: "#8b5cf610",
544
- border: "1px solid #8b5cf630",
545
- borderRadius: "6px",
546
- cursor: "pointer",
547
- transition: "all 0.2s",
548
- display: "flex",
549
- alignItems: "center",
550
- gap: "6px",
551
- }}
552
- onMouseEnter={(e) => {
553
- e.currentTarget.style.background = "#8b5cf620";
554
- }}
555
- onMouseLeave={(e) => {
556
- e.currentTarget.style.background = "#8b5cf610";
557
- }}
551
+ className="ai-inline-btn"
558
552
  title="Gérer les modèles"
559
553
  >
560
554
  <Settings size={14} />
@@ -569,7 +563,7 @@ function AiPromptPanelInternal({
569
563
  marginLeft: "2px",
570
564
  padding: "2px 6px",
571
565
  fontSize: "10px",
572
- background: "#8b5cf6",
566
+ background: "var(--ai-primary)",
573
567
  color: "white",
574
568
  borderRadius: "10px",
575
569
  fontWeight: "600",
@@ -627,7 +621,7 @@ function AiPromptPanelInternal({
627
621
  <div
628
622
  style={{
629
623
  fontSize: "11px",
630
- color: "#6b7280",
624
+ color: "var(--ai-text-secondary)",
631
625
  marginTop: "4px",
632
626
  }}
633
627
  >
@@ -678,7 +672,7 @@ function AiPromptPanelInternal({
678
672
  Prompt
679
673
  <span
680
674
  style={{
681
- color: "#6b7280",
675
+ color: "var(--ai-text-secondary)",
682
676
  marginLeft: "4px",
683
677
  fontSize: "12px",
684
678
  fontWeight: 400,
@@ -690,25 +684,7 @@ function AiPromptPanelInternal({
690
684
  {filteredPrompts.length > 0 && (
691
685
  <button
692
686
  onClick={() => setShowPromptLibrary(true)}
693
- style={{
694
- padding: "4px 12px",
695
- fontSize: "12px",
696
- color: "#8b5cf6",
697
- background: "#8b5cf610",
698
- border: "1px solid #8b5cf630",
699
- borderRadius: "6px",
700
- cursor: "pointer",
701
- transition: "all 0.2s",
702
- display: "flex",
703
- alignItems: "center",
704
- gap: "6px",
705
- }}
706
- onMouseEnter={(e) => {
707
- e.currentTarget.style.background = "#8b5cf620";
708
- }}
709
- onMouseLeave={(e) => {
710
- e.currentTarget.style.background = "#8b5cf610";
711
- }}
687
+ className="ai-inline-btn"
712
688
  >
713
689
  <BookOpen size={14} />
714
690
  Browse Prompts ({filteredPrompts.length})
@@ -743,7 +719,7 @@ function AiPromptPanelInternal({
743
719
  style={{
744
720
  padding: "8px 0",
745
721
  fontSize: "14px",
746
- color: "#8b5cf6",
722
+ color: "var(--ai-primary)",
747
723
  background: "transparent",
748
724
  border: "none",
749
725
  cursor: "pointer",
@@ -811,11 +787,11 @@ function AiPromptPanelInternal({
811
787
  ...aiStyles.chip,
812
788
  borderColor:
813
789
  selectedTag === "all"
814
- ? "#8b5cf6"
790
+ ? "var(--ai-primary)"
815
791
  : (aiStyles.chip.border as string),
816
792
  background:
817
793
  selectedTag === "all"
818
- ? "#8b5cf620"
794
+ ? "color-mix(in srgb, var(--ai-primary) 20%, transparent)"
819
795
  : (aiStyles.chip.background as string),
820
796
  }}
821
797
  >
@@ -829,11 +805,11 @@ function AiPromptPanelInternal({
829
805
  ...aiStyles.chip,
830
806
  borderColor:
831
807
  selectedTag === tag
832
- ? "#8b5cf6"
808
+ ? "var(--ai-primary)"
833
809
  : (aiStyles.chip.border as string),
834
810
  background:
835
811
  selectedTag === tag
836
- ? "#8b5cf620"
812
+ ? "color-mix(in srgb, var(--ai-primary) 20%, transparent)"
837
813
  : (aiStyles.chip.background as string),
838
814
  }}
839
815
  >
@@ -853,7 +829,7 @@ function AiPromptPanelInternal({
853
829
  style={{
854
830
  textAlign: "center",
855
831
  padding: "40px 0",
856
- color: "#6b7280",
832
+ color: "var(--ai-text-secondary)",
857
833
  }}
858
834
  >
859
835
  No prompts available for this model type
@@ -873,7 +849,7 @@ function AiPromptPanelInternal({
873
849
  <div
874
850
  style={{
875
851
  fontSize: "12px",
876
- color: "#6b7280",
852
+ color: "var(--ai-text-secondary)",
877
853
  fontWeight: 600,
878
854
  textTransform: "uppercase",
879
855
  marginBottom: "8px",
@@ -894,18 +870,21 @@ function AiPromptPanelInternal({
894
870
  onClick={() => handleSelectPrompt(promptData)}
895
871
  style={{
896
872
  padding: "16px",
897
- border: `1px solid #e5e7eb`,
873
+ border: `1px solid var(--ai-border)`,
898
874
  borderRadius: "8px",
899
875
  cursor: "pointer",
900
876
  transition: "all 0.2s",
901
877
  }}
902
878
  onMouseEnter={(e) => {
903
- e.currentTarget.style.background = "#8b5cf610";
904
- e.currentTarget.style.borderColor = "#8b5cf6";
879
+ e.currentTarget.style.background =
880
+ "color-mix(in srgb, var(--ai-primary) 10%, transparent)";
881
+ e.currentTarget.style.borderColor =
882
+ "var(--ai-primary)";
905
883
  }}
906
884
  onMouseLeave={(e) => {
907
885
  e.currentTarget.style.background = "transparent";
908
- e.currentTarget.style.borderColor = "#e5e7eb";
886
+ e.currentTarget.style.borderColor =
887
+ "var(--ai-border)";
909
888
  }}
910
889
  >
911
890
  <div
@@ -915,16 +894,16 @@ function AiPromptPanelInternal({
915
894
  gap: "8px",
916
895
  fontWeight: 600,
917
896
  marginBottom: "4px",
918
- color: "#9780a5",
897
+ color: "var(--ai-text)",
919
898
  }}
920
899
  >
921
- <Star size={14} color="#8b5cf6" />
900
+ <Star size={14} color="var(--ai-primary)" />
922
901
  {promptData.title}
923
902
  </div>
924
903
  <div
925
904
  style={{
926
905
  fontSize: "13px",
927
- color: "#6b7280",
906
+ color: "var(--ai-text-secondary)",
928
907
  overflow: "hidden",
929
908
  textOverflow: "ellipsis",
930
909
  display: "-webkit-box",
@@ -939,7 +918,7 @@ function AiPromptPanelInternal({
939
918
  style={{
940
919
  marginTop: "8px",
941
920
  fontSize: "11px",
942
- color: "#8b5cf6",
921
+ color: "var(--ai-primary)",
943
922
  }}
944
923
  >
945
924
  {String(promptData.category)}
@@ -956,7 +935,7 @@ function AiPromptPanelInternal({
956
935
  <div
957
936
  style={{
958
937
  fontSize: "12px",
959
- color: "#6b7280",
938
+ color: "var(--ai-text-secondary)",
960
939
  fontWeight: 600,
961
940
  textTransform: "uppercase",
962
941
  marginTop:
@@ -979,25 +958,28 @@ function AiPromptPanelInternal({
979
958
  onClick={() => handleSelectPrompt(promptData)}
980
959
  style={{
981
960
  padding: "16px",
982
- border: `1px solid #e5e7eb`,
961
+ border: `1px solid var(--ai-border)`,
983
962
  borderRadius: "8px",
984
963
  cursor: "pointer",
985
964
  transition: "all 0.2s",
986
965
  }}
987
966
  onMouseEnter={(e) => {
988
- e.currentTarget.style.background = "#8b5cf610";
989
- e.currentTarget.style.borderColor = "#8b5cf6";
967
+ e.currentTarget.style.background =
968
+ "color-mix(in srgb, var(--ai-primary) 10%, transparent)";
969
+ e.currentTarget.style.borderColor =
970
+ "var(--ai-primary)";
990
971
  }}
991
972
  onMouseLeave={(e) => {
992
973
  e.currentTarget.style.background = "transparent";
993
- e.currentTarget.style.borderColor = "#e5e7eb";
974
+ e.currentTarget.style.borderColor =
975
+ "var(--ai-border)";
994
976
  }}
995
977
  >
996
978
  <div
997
979
  style={{
998
980
  fontWeight: 600,
999
981
  marginBottom: "4px",
1000
- color: "#9780a5",
982
+ color: "var(--ai-text)",
1001
983
  }}
1002
984
  >
1003
985
  {promptData.title}
@@ -1005,7 +987,7 @@ function AiPromptPanelInternal({
1005
987
  <div
1006
988
  style={{
1007
989
  fontSize: "13px",
1008
- color: "#6b7280",
990
+ color: "var(--ai-text-secondary)",
1009
991
  overflow: "hidden",
1010
992
  textOverflow: "ellipsis",
1011
993
  display: "-webkit-box",
@@ -1020,7 +1002,7 @@ function AiPromptPanelInternal({
1020
1002
  style={{
1021
1003
  marginTop: "8px",
1022
1004
  fontSize: "11px",
1023
- color: "#8b5cf6",
1005
+ color: "var(--ai-primary)",
1024
1006
  }}
1025
1007
  >
1026
1008
  {String(promptData.category)}
@@ -1047,32 +1029,13 @@ function AiPromptPanelInternal({
1047
1029
  backdropFilter: "blur(8px)",
1048
1030
  }}
1049
1031
  >
1050
- <button
1051
- onClick={handleClose}
1052
- onMouseEnter={() => setIsCancelHovered(true)}
1053
- onMouseLeave={() => setIsCancelHovered(false)}
1054
- style={{
1055
- ...aiStyles.button,
1056
- ...aiStyles.buttonSecondary,
1057
- ...(isCancelHovered && aiStyles.buttonSecondaryHover),
1058
- }}
1059
- >
1032
+ <button onClick={handleClose} className="ai-btn ai-btn--ghost">
1060
1033
  Cancel
1061
1034
  </button>
1062
1035
  <button
1063
1036
  onClick={handleSubmit}
1064
1037
  disabled={!selectedModel || !prompt.trim()}
1065
- onMouseEnter={() => setIsSubmitHovered(true)}
1066
- onMouseLeave={() => setIsSubmitHovered(false)}
1067
- style={{
1068
- ...aiStyles.button,
1069
- ...(isSubmitHovered &&
1070
- !(!selectedModel || !prompt.trim()) &&
1071
- aiStyles.buttonHover),
1072
- ...(!selectedModel || !prompt.trim()
1073
- ? aiStyles.buttonDisabled
1074
- : {}),
1075
- }}
1038
+ className="ai-btn ai-btn--primary"
1076
1039
  >
1077
1040
  {sourceText ? "Transform with AI" : "Generate with AI"}
1078
1041
  </button>
@@ -1084,13 +1047,13 @@ function AiPromptPanelInternal({
1084
1047
  <div
1085
1048
  style={{
1086
1049
  ...aiStyles.modal,
1087
- zIndex: 1001, // Au-dessus du modal principal
1050
+ zIndex: 2147483646, // Au-dessus du modal principal
1088
1051
  }}
1089
1052
  >
1090
1053
  <div
1091
1054
  style={{
1092
1055
  ...aiStyles.modalOverlay,
1093
- backgroundColor: "rgba(0, 0, 0, 0.75)",
1056
+ backgroundColor: "var(--ai-overlay)",
1094
1057
  }}
1095
1058
  onClick={() => {
1096
1059
  setIsModelManagementOpen(false);
@@ -1105,8 +1068,7 @@ function AiPromptPanelInternal({
1105
1068
  overflow: "hidden",
1106
1069
  display: "flex",
1107
1070
  flexDirection: "column",
1108
-
1109
- boxShadow: "0 20px 40px rgba(0, 0, 0, 0.5)",
1071
+ boxShadow: "var(--ai-shadow-lg)",
1110
1072
  }}
1111
1073
  >
1112
1074
  <div style={aiStyles.modalHeader}>
@@ -1134,7 +1096,7 @@ function AiPromptPanelInternal({
1134
1096
  <p
1135
1097
  style={{
1136
1098
  fontSize: "14px",
1137
- color: "var(--ai-text-secondary, #6b7280)",
1099
+ color: "var(--ai-muted)",
1138
1100
  margin: "0 0 8px 0",
1139
1101
  }}
1140
1102
  >
@@ -1143,7 +1105,7 @@ function AiPromptPanelInternal({
1143
1105
  <p
1144
1106
  style={{
1145
1107
  fontSize: "12px",
1146
- color: "var(--ai-text-tertiary, #9ca3af)",
1108
+ color: "var(--ai-text-tertiary)",
1147
1109
  margin: "0 0 16px 0",
1148
1110
  }}
1149
1111
  >
@@ -1176,7 +1138,7 @@ function AiPromptPanelInternal({
1176
1138
  left: "12px",
1177
1139
  top: "50%",
1178
1140
  transform: "translateY(-50%)",
1179
- color: "var(--ai-text-tertiary, #9ca3af)",
1141
+ color: "var(--ai-text-tertiary)",
1180
1142
  }}
1181
1143
  />
1182
1144
  <input
@@ -1186,19 +1148,13 @@ function AiPromptPanelInternal({
1186
1148
  style={{
1187
1149
  ...aiStyles.input,
1188
1150
  padding: "10px 12px 10px 36px",
1189
- background: "var(--ai-bg-secondary, #f9fafb)",
1151
+ background: "var(--ai-bg)",
1190
1152
  }}
1191
1153
  />
1192
1154
  </div>
1193
1155
  </div>
1194
1156
 
1195
- <div
1196
- style={{
1197
- display: "flex",
1198
- flexDirection: "column",
1199
- gap: "8px",
1200
- }}
1201
- >
1157
+ <div className="ai-model-mgmt-list">
1202
1158
  {effectiveAvailableModels
1203
1159
  .filter((model) => {
1204
1160
  if (model.category !== modelCategory) return false;
@@ -1217,116 +1173,26 @@ function AiPromptPanelInternal({
1217
1173
  return (
1218
1174
  <div
1219
1175
  key={modelData.id}
1220
- style={{
1221
- display: "flex",
1222
- alignItems: "center",
1223
- justifyContent: "space-between",
1224
- padding: "16px 18px",
1225
- // border: "2px solid",
1226
- // borderColor: isActive
1227
- // ? "#10b981"
1228
- // : "var(--ai-border-primary, #374151)",
1229
- borderRadius: "10px",
1230
- backgroundColor: isActive
1231
- ? "rgba(16, 185, 129, 0.03)"
1232
- : "var(--ai-bg-secondary, rgba(31, 41, 55, 0.2))",
1233
- transition: "all 0.2s",
1234
- cursor: "pointer",
1235
- backdropFilter: "blur(8px)",
1236
- }}
1176
+ className={`ai-model-item ${isActive ? "ai-model-item--active" : ""}`}
1237
1177
  onClick={() =>
1238
1178
  !isLoading &&
1239
1179
  handleModelToggle(modelData.id, !isActive)
1240
1180
  }
1241
- onMouseEnter={(e) => {
1242
- // e.currentTarget.style.borderColor = isActive
1243
- // ? "#059669"
1244
- // : "#4b5563";
1245
- e.currentTarget.style.transform = "translateY(-2px)";
1246
- e.currentTarget.style.boxShadow = isActive
1247
- ? "0 8px 16px rgba(16, 185, 129, 0.2)"
1248
- : "0 8px 16px rgba(0, 0, 0, 0.15)";
1249
- }}
1250
- onMouseLeave={(e) => {
1251
- // e.currentTarget.style.borderColor = isActive
1252
- // ? "#10b981"
1253
- // : "var(--ai-border-primary, #374151)";
1254
- e.currentTarget.style.transform = "translateY(0)";
1255
- e.currentTarget.style.boxShadow = "none";
1256
- }}
1257
1181
  >
1258
- <div
1259
- style={{
1260
- display: "flex",
1261
- alignItems: "center",
1262
- gap: "14px",
1263
- flex: 1,
1264
- }}
1265
- >
1266
- {/* Status indicator */}
1182
+ <div className="ai-model-item-main">
1267
1183
  <div
1268
- style={{
1269
- width: "8px",
1270
- height: "8px",
1271
- borderRadius: "50%",
1272
- backgroundColor: isActive ? "#10b981" : "#6b7280",
1273
- boxShadow: isActive
1274
- ? "0 0 8px rgba(16, 185, 129, 0.6)"
1275
- : "none",
1276
- transition: "all 0.3s",
1277
- }}
1184
+ className={`ai-model-item-dot ${isActive ? "ai-model-item-dot--active" : ""}`}
1278
1185
  />
1279
1186
  <div style={{ flex: 1 }}>
1280
- <div
1281
- style={{
1282
- display: "flex",
1283
- alignItems: "center",
1284
- gap: "10px",
1285
- marginBottom: "6px",
1286
- }}
1287
- >
1288
- <span
1289
- style={{
1290
- fontWeight: "600",
1291
- fontSize: "15px",
1292
- color: "var(--ai-text-secondary, #6b7280)",
1293
-
1294
- letterSpacing: "-0.01em",
1295
- }}
1296
- >
1297
- {modelData.name}
1298
- </span>
1187
+ <div className="ai-model-item-title">
1188
+ <span>{modelData.name}</span>
1299
1189
  {modelData.isPro && (
1300
- <span
1301
- style={{
1302
- padding: "3px 10px",
1303
- fontSize: "10px",
1304
- backgroundColor: "#8b5cf6",
1305
- color: "white",
1306
- borderRadius: "12px",
1307
- fontWeight: "700",
1308
- textTransform: "uppercase",
1309
- letterSpacing: "0.05em",
1310
- boxShadow:
1311
- "0 2px 8px rgba(139, 92, 246, 0.3)",
1312
- }}
1313
- >
1190
+ <span className="ai-pill ai-pill--pro">
1314
1191
  PRO
1315
1192
  </span>
1316
1193
  )}
1317
1194
  </div>
1318
- <div
1319
- style={{
1320
- display: "flex",
1321
- alignItems: "center",
1322
- gap: "16px",
1323
- fontSize: "13px",
1324
- color: isActive
1325
- ? "#6ee7b7"
1326
- : "var(--ai-text-secondary, #d1d5db)",
1327
- fontWeight: "500",
1328
- }}
1329
- >
1195
+ <div className="ai-model-item-meta">
1330
1196
  <span
1331
1197
  style={{
1332
1198
  display: "flex",
@@ -1346,23 +1212,13 @@ function AiPromptPanelInternal({
1346
1212
  {modelData.provider}
1347
1213
  </span>
1348
1214
  {modelData.costPer1M && (
1349
- <span
1350
- style={{
1351
- padding: "2px 8px",
1352
- background: isActive
1353
- ? "rgba(16, 185, 129, 0.15)"
1354
- : "rgba(107, 114, 128, 0.2)",
1355
- borderRadius: "6px",
1356
- fontSize: "12px",
1357
- }}
1358
- >
1215
+ <span className="ai-pill ai-pill--cost">
1359
1216
  ${modelData.costPer1M}/1M
1360
1217
  </span>
1361
1218
  )}
1362
1219
  </div>
1363
1220
  </div>
1364
1221
  </div>
1365
- {/* Toggle Switch CSS amélioré */}
1366
1222
  <label
1367
1223
  style={{
1368
1224
  position: "relative",
@@ -1390,41 +1246,8 @@ function AiPromptPanelInternal({
1390
1246
  }}
1391
1247
  />
1392
1248
  <span
1393
- style={{
1394
- position: "absolute",
1395
- cursor: isLoading ? "not-allowed" : "pointer",
1396
- top: 0,
1397
- left: 0,
1398
- right: 0,
1399
- bottom: 0,
1400
- backgroundColor: isActive ? "#10b981" : "#4b5563",
1401
- transition: "0.3s",
1402
- borderRadius: "28px",
1403
- boxShadow: isActive
1404
- ? "0 0 12px rgba(16, 185, 129, 0.4), inset 0 1px 3px rgba(0, 0, 0, 0.2)"
1405
- : "inset 0 1px 3px rgba(0, 0, 0, 0.3)",
1406
- border: isActive
1407
- ? "2px solid #059669"
1408
- : "2px solid #374151",
1409
- }}
1410
- >
1411
- <span
1412
- style={{
1413
- position: "absolute",
1414
- content: "",
1415
- height: "22px",
1416
- width: "22px",
1417
- left: isActive ? "28px" : "2px",
1418
- bottom: "2px",
1419
- backgroundColor: "white",
1420
- transition: "0.3s cubic-bezier(0.4, 0, 0.2, 1)",
1421
- borderRadius: "50%",
1422
- boxShadow: isActive
1423
- ? "0 3px 8px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(16, 185, 129, 0.1)"
1424
- : "0 3px 8px rgba(0, 0, 0, 0.3)",
1425
- }}
1426
- />
1427
- </span>
1249
+ className={`ai-toggle ${isActive ? "ai-toggle--active" : ""}`}
1250
+ />
1428
1251
  </label>
1429
1252
  </div>
1430
1253
  );
@@ -1443,7 +1266,7 @@ function AiPromptPanelInternal({
1443
1266
  style={{
1444
1267
  textAlign: "center",
1445
1268
  padding: "32px 16px",
1446
- color: "var(--ai-text-tertiary, #9ca3af)",
1269
+ color: "var(--ai-text-tertiary)",
1447
1270
  fontSize: "14px",
1448
1271
  }}
1449
1272
  >
@@ -1461,10 +1284,7 @@ function AiPromptPanelInternal({
1461
1284
  setIsModelManagementOpen(false);
1462
1285
  setModelSearchQuery("");
1463
1286
  }}
1464
- style={{
1465
- ...aiStyles.button,
1466
- ...aiStyles.buttonSecondary,
1467
- }}
1287
+ className="ai-btn ai-btn--ghost"
1468
1288
  >
1469
1289
  Fermer
1470
1290
  </button>
@@ -1472,6 +1292,7 @@ function AiPromptPanelInternal({
1472
1292
  </div>
1473
1293
  </div>
1474
1294
  )}
1475
- </div>
1295
+ </div>,
1296
+ portalRoot
1476
1297
  );
1477
1298
  }