@lastbrain/ai-ui-react 1.0.67 → 1.0.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) 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 +21 -70
  4. package/dist/components/AiContextButton.d.ts +5 -1
  5. package/dist/components/AiContextButton.d.ts.map +1 -1
  6. package/dist/components/AiContextButton.js +67 -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 +58 -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 +198 -626
  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/examples/AiUiPremiumShowcase.d.ts +2 -0
  33. package/dist/examples/AiUiPremiumShowcase.d.ts.map +1 -0
  34. package/dist/examples/AiUiPremiumShowcase.js +15 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +2 -0
  38. package/dist/styles/inline.d.ts +1 -0
  39. package/dist/styles/inline.d.ts.map +1 -1
  40. package/dist/styles/inline.js +25 -129
  41. package/dist/styles.css +1268 -369
  42. package/dist/types.d.ts +3 -0
  43. package/dist/types.d.ts.map +1 -1
  44. package/package.json +2 -2
  45. package/src/components/AiChipLabel.tsx +64 -101
  46. package/src/components/AiContextButton.tsx +138 -430
  47. package/src/components/AiImageButton.tsx +29 -190
  48. package/src/components/AiInput.tsx +49 -74
  49. package/src/components/AiPromptPanel.tsx +71 -254
  50. package/src/components/AiSelect.tsx +61 -69
  51. package/src/components/AiStatusButton.tsx +477 -1219
  52. package/src/components/AiTextarea.tsx +49 -64
  53. package/src/components/LBApiKeySelector.tsx +86 -274
  54. package/src/components/LBConnectButton.tsx +46 -334
  55. package/src/components/LBSigninModal.tsx +140 -481
  56. package/src/examples/AiUiPremiumShowcase.tsx +91 -0
  57. package/src/index.ts +3 -0
  58. package/src/styles/inline.ts +27 -148
  59. package/src/styles.css +1268 -369
  60. package/src/types.ts +3 -0
@@ -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;
@@ -380,15 +384,20 @@ function AiPromptPanelInternal({
380
384
  onModelToggle: handleModelToggle,
381
385
  };
382
386
 
387
+ if (!portalRoot) {
388
+ return null;
389
+ }
390
+
383
391
  if (children) {
384
- return (
392
+ return createPortal(
385
393
  <div style={aiStyles.modal} onKeyDown={handleKeyDown}>
386
394
  {children(renderProps)}
387
- </div>
395
+ </div>,
396
+ portalRoot
388
397
  );
389
398
  }
390
399
 
391
- return (
400
+ return createPortal(
392
401
  <div style={aiStyles.modal} onKeyDown={handleKeyDown}>
393
402
  <div
394
403
  style={{
@@ -432,22 +441,22 @@ function AiPromptPanelInternal({
432
441
  width: "64px",
433
442
  height: "64px",
434
443
  borderRadius: "999px",
435
- border: "2px solid #8b5cf620",
436
- borderTopColor: "#8b5cf6",
444
+ border: "2px solid color-mix(in srgb, var(--ai-primary) 20%, transparent)",
445
+ borderTopColor: "var(--ai-primary)",
437
446
  animation: "ai-spin 1.1s linear infinite",
438
447
  display: "flex",
439
448
  alignItems: "center",
440
449
  justifyContent: "center",
441
- boxShadow: "0 12px 24px rgba(139, 92, 246, 0.15)",
450
+ boxShadow: "0 12px 24px var(--ai-glow)",
442
451
  }}
443
452
  >
444
- <Sparkles size={20} color="#8b5cf6" />
453
+ <Sparkles size={20} color="var(--ai-primary)" />
445
454
  </div>
446
455
  <div
447
456
  style={{
448
457
  fontSize: "13px",
449
458
  fontWeight: 600,
450
- color: "#6b7280",
459
+ color: "var(--ai-text-secondary)",
451
460
  letterSpacing: "0.02em",
452
461
  }}
453
462
  >
@@ -536,25 +545,7 @@ function AiPromptPanelInternal({
536
545
  {effectiveAvailableModels.length > 0 && (
537
546
  <button
538
547
  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
- }}
548
+ className="ai-inline-btn"
558
549
  title="Gérer les modèles"
559
550
  >
560
551
  <Settings size={14} />
@@ -569,7 +560,7 @@ function AiPromptPanelInternal({
569
560
  marginLeft: "2px",
570
561
  padding: "2px 6px",
571
562
  fontSize: "10px",
572
- background: "#8b5cf6",
563
+ background: "var(--ai-primary)",
573
564
  color: "white",
574
565
  borderRadius: "10px",
575
566
  fontWeight: "600",
@@ -627,7 +618,7 @@ function AiPromptPanelInternal({
627
618
  <div
628
619
  style={{
629
620
  fontSize: "11px",
630
- color: "#6b7280",
621
+ color: "var(--ai-text-secondary)",
631
622
  marginTop: "4px",
632
623
  }}
633
624
  >
@@ -678,7 +669,7 @@ function AiPromptPanelInternal({
678
669
  Prompt
679
670
  <span
680
671
  style={{
681
- color: "#6b7280",
672
+ color: "var(--ai-text-secondary)",
682
673
  marginLeft: "4px",
683
674
  fontSize: "12px",
684
675
  fontWeight: 400,
@@ -690,25 +681,7 @@ function AiPromptPanelInternal({
690
681
  {filteredPrompts.length > 0 && (
691
682
  <button
692
683
  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
- }}
684
+ className="ai-inline-btn"
712
685
  >
713
686
  <BookOpen size={14} />
714
687
  Browse Prompts ({filteredPrompts.length})
@@ -743,7 +716,7 @@ function AiPromptPanelInternal({
743
716
  style={{
744
717
  padding: "8px 0",
745
718
  fontSize: "14px",
746
- color: "#8b5cf6",
719
+ color: "var(--ai-primary)",
747
720
  background: "transparent",
748
721
  border: "none",
749
722
  cursor: "pointer",
@@ -811,11 +784,11 @@ function AiPromptPanelInternal({
811
784
  ...aiStyles.chip,
812
785
  borderColor:
813
786
  selectedTag === "all"
814
- ? "#8b5cf6"
787
+ ? "var(--ai-primary)"
815
788
  : (aiStyles.chip.border as string),
816
789
  background:
817
790
  selectedTag === "all"
818
- ? "#8b5cf620"
791
+ ? "color-mix(in srgb, var(--ai-primary) 20%, transparent)"
819
792
  : (aiStyles.chip.background as string),
820
793
  }}
821
794
  >
@@ -829,11 +802,11 @@ function AiPromptPanelInternal({
829
802
  ...aiStyles.chip,
830
803
  borderColor:
831
804
  selectedTag === tag
832
- ? "#8b5cf6"
805
+ ? "var(--ai-primary)"
833
806
  : (aiStyles.chip.border as string),
834
807
  background:
835
808
  selectedTag === tag
836
- ? "#8b5cf620"
809
+ ? "color-mix(in srgb, var(--ai-primary) 20%, transparent)"
837
810
  : (aiStyles.chip.background as string),
838
811
  }}
839
812
  >
@@ -853,7 +826,7 @@ function AiPromptPanelInternal({
853
826
  style={{
854
827
  textAlign: "center",
855
828
  padding: "40px 0",
856
- color: "#6b7280",
829
+ color: "var(--ai-text-secondary)",
857
830
  }}
858
831
  >
859
832
  No prompts available for this model type
@@ -873,7 +846,7 @@ function AiPromptPanelInternal({
873
846
  <div
874
847
  style={{
875
848
  fontSize: "12px",
876
- color: "#6b7280",
849
+ color: "var(--ai-text-secondary)",
877
850
  fontWeight: 600,
878
851
  textTransform: "uppercase",
879
852
  marginBottom: "8px",
@@ -894,18 +867,18 @@ function AiPromptPanelInternal({
894
867
  onClick={() => handleSelectPrompt(promptData)}
895
868
  style={{
896
869
  padding: "16px",
897
- border: `1px solid #e5e7eb`,
870
+ border: `1px solid var(--ai-border)`,
898
871
  borderRadius: "8px",
899
872
  cursor: "pointer",
900
873
  transition: "all 0.2s",
901
874
  }}
902
875
  onMouseEnter={(e) => {
903
- e.currentTarget.style.background = "#8b5cf610";
904
- e.currentTarget.style.borderColor = "#8b5cf6";
876
+ e.currentTarget.style.background = "color-mix(in srgb, var(--ai-primary) 10%, transparent)";
877
+ e.currentTarget.style.borderColor = "var(--ai-primary)";
905
878
  }}
906
879
  onMouseLeave={(e) => {
907
880
  e.currentTarget.style.background = "transparent";
908
- e.currentTarget.style.borderColor = "#e5e7eb";
881
+ e.currentTarget.style.borderColor = "var(--ai-border)";
909
882
  }}
910
883
  >
911
884
  <div
@@ -915,16 +888,16 @@ function AiPromptPanelInternal({
915
888
  gap: "8px",
916
889
  fontWeight: 600,
917
890
  marginBottom: "4px",
918
- color: "#9780a5",
891
+ color: "var(--ai-text)",
919
892
  }}
920
893
  >
921
- <Star size={14} color="#8b5cf6" />
894
+ <Star size={14} color="var(--ai-primary)" />
922
895
  {promptData.title}
923
896
  </div>
924
897
  <div
925
898
  style={{
926
899
  fontSize: "13px",
927
- color: "#6b7280",
900
+ color: "var(--ai-text-secondary)",
928
901
  overflow: "hidden",
929
902
  textOverflow: "ellipsis",
930
903
  display: "-webkit-box",
@@ -939,7 +912,7 @@ function AiPromptPanelInternal({
939
912
  style={{
940
913
  marginTop: "8px",
941
914
  fontSize: "11px",
942
- color: "#8b5cf6",
915
+ color: "var(--ai-primary)",
943
916
  }}
944
917
  >
945
918
  {String(promptData.category)}
@@ -956,7 +929,7 @@ function AiPromptPanelInternal({
956
929
  <div
957
930
  style={{
958
931
  fontSize: "12px",
959
- color: "#6b7280",
932
+ color: "var(--ai-text-secondary)",
960
933
  fontWeight: 600,
961
934
  textTransform: "uppercase",
962
935
  marginTop:
@@ -979,25 +952,25 @@ function AiPromptPanelInternal({
979
952
  onClick={() => handleSelectPrompt(promptData)}
980
953
  style={{
981
954
  padding: "16px",
982
- border: `1px solid #e5e7eb`,
955
+ border: `1px solid var(--ai-border)`,
983
956
  borderRadius: "8px",
984
957
  cursor: "pointer",
985
958
  transition: "all 0.2s",
986
959
  }}
987
960
  onMouseEnter={(e) => {
988
- e.currentTarget.style.background = "#8b5cf610";
989
- e.currentTarget.style.borderColor = "#8b5cf6";
961
+ e.currentTarget.style.background = "color-mix(in srgb, var(--ai-primary) 10%, transparent)";
962
+ e.currentTarget.style.borderColor = "var(--ai-primary)";
990
963
  }}
991
964
  onMouseLeave={(e) => {
992
965
  e.currentTarget.style.background = "transparent";
993
- e.currentTarget.style.borderColor = "#e5e7eb";
966
+ e.currentTarget.style.borderColor = "var(--ai-border)";
994
967
  }}
995
968
  >
996
969
  <div
997
970
  style={{
998
971
  fontWeight: 600,
999
972
  marginBottom: "4px",
1000
- color: "#9780a5",
973
+ color: "var(--ai-text)",
1001
974
  }}
1002
975
  >
1003
976
  {promptData.title}
@@ -1005,7 +978,7 @@ function AiPromptPanelInternal({
1005
978
  <div
1006
979
  style={{
1007
980
  fontSize: "13px",
1008
- color: "#6b7280",
981
+ color: "var(--ai-text-secondary)",
1009
982
  overflow: "hidden",
1010
983
  textOverflow: "ellipsis",
1011
984
  display: "-webkit-box",
@@ -1020,7 +993,7 @@ function AiPromptPanelInternal({
1020
993
  style={{
1021
994
  marginTop: "8px",
1022
995
  fontSize: "11px",
1023
- color: "#8b5cf6",
996
+ color: "var(--ai-primary)",
1024
997
  }}
1025
998
  >
1026
999
  {String(promptData.category)}
@@ -1049,30 +1022,14 @@ function AiPromptPanelInternal({
1049
1022
  >
1050
1023
  <button
1051
1024
  onClick={handleClose}
1052
- onMouseEnter={() => setIsCancelHovered(true)}
1053
- onMouseLeave={() => setIsCancelHovered(false)}
1054
- style={{
1055
- ...aiStyles.button,
1056
- ...aiStyles.buttonSecondary,
1057
- ...(isCancelHovered && aiStyles.buttonSecondaryHover),
1058
- }}
1025
+ className="ai-btn ai-btn--ghost"
1059
1026
  >
1060
1027
  Cancel
1061
1028
  </button>
1062
1029
  <button
1063
1030
  onClick={handleSubmit}
1064
1031
  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
- }}
1032
+ className="ai-btn ai-btn--primary"
1076
1033
  >
1077
1034
  {sourceText ? "Transform with AI" : "Generate with AI"}
1078
1035
  </button>
@@ -1084,13 +1041,13 @@ function AiPromptPanelInternal({
1084
1041
  <div
1085
1042
  style={{
1086
1043
  ...aiStyles.modal,
1087
- zIndex: 1001, // Au-dessus du modal principal
1044
+ zIndex: 2147483646, // Au-dessus du modal principal
1088
1045
  }}
1089
1046
  >
1090
1047
  <div
1091
1048
  style={{
1092
1049
  ...aiStyles.modalOverlay,
1093
- backgroundColor: "rgba(0, 0, 0, 0.75)",
1050
+ backgroundColor: "var(--ai-overlay)",
1094
1051
  }}
1095
1052
  onClick={() => {
1096
1053
  setIsModelManagementOpen(false);
@@ -1105,8 +1062,7 @@ function AiPromptPanelInternal({
1105
1062
  overflow: "hidden",
1106
1063
  display: "flex",
1107
1064
  flexDirection: "column",
1108
-
1109
- boxShadow: "0 20px 40px rgba(0, 0, 0, 0.5)",
1065
+ boxShadow: "var(--ai-shadow-lg)",
1110
1066
  }}
1111
1067
  >
1112
1068
  <div style={aiStyles.modalHeader}>
@@ -1134,7 +1090,7 @@ function AiPromptPanelInternal({
1134
1090
  <p
1135
1091
  style={{
1136
1092
  fontSize: "14px",
1137
- color: "var(--ai-text-secondary, #6b7280)",
1093
+ color: "var(--ai-muted)",
1138
1094
  margin: "0 0 8px 0",
1139
1095
  }}
1140
1096
  >
@@ -1143,7 +1099,7 @@ function AiPromptPanelInternal({
1143
1099
  <p
1144
1100
  style={{
1145
1101
  fontSize: "12px",
1146
- color: "var(--ai-text-tertiary, #9ca3af)",
1102
+ color: "var(--ai-text-tertiary)",
1147
1103
  margin: "0 0 16px 0",
1148
1104
  }}
1149
1105
  >
@@ -1176,7 +1132,7 @@ function AiPromptPanelInternal({
1176
1132
  left: "12px",
1177
1133
  top: "50%",
1178
1134
  transform: "translateY(-50%)",
1179
- color: "var(--ai-text-tertiary, #9ca3af)",
1135
+ color: "var(--ai-text-tertiary)",
1180
1136
  }}
1181
1137
  />
1182
1138
  <input
@@ -1186,19 +1142,13 @@ function AiPromptPanelInternal({
1186
1142
  style={{
1187
1143
  ...aiStyles.input,
1188
1144
  padding: "10px 12px 10px 36px",
1189
- background: "var(--ai-bg-secondary, #f9fafb)",
1145
+ background: "var(--ai-bg)",
1190
1146
  }}
1191
1147
  />
1192
1148
  </div>
1193
1149
  </div>
1194
1150
 
1195
- <div
1196
- style={{
1197
- display: "flex",
1198
- flexDirection: "column",
1199
- gap: "8px",
1200
- }}
1201
- >
1151
+ <div className="ai-model-mgmt-list">
1202
1152
  {effectiveAvailableModels
1203
1153
  .filter((model) => {
1204
1154
  if (model.category !== modelCategory) return false;
@@ -1217,116 +1167,28 @@ function AiPromptPanelInternal({
1217
1167
  return (
1218
1168
  <div
1219
1169
  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
- }}
1170
+ className={`ai-model-item ${isActive ? "ai-model-item--active" : ""}`}
1237
1171
  onClick={() =>
1238
1172
  !isLoading &&
1239
1173
  handleModelToggle(modelData.id, !isActive)
1240
1174
  }
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
1175
  >
1258
- <div
1259
- style={{
1260
- display: "flex",
1261
- alignItems: "center",
1262
- gap: "14px",
1263
- flex: 1,
1264
- }}
1265
- >
1266
- {/* Status indicator */}
1176
+ <div className="ai-model-item-main">
1267
1177
  <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
- }}
1178
+ className={`ai-model-item-dot ${isActive ? "ai-model-item-dot--active" : ""}`}
1278
1179
  />
1279
1180
  <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
- >
1181
+ <div className="ai-model-item-title">
1182
+ <span>
1297
1183
  {modelData.name}
1298
1184
  </span>
1299
1185
  {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
- >
1186
+ <span className="ai-pill ai-pill--pro">
1314
1187
  PRO
1315
1188
  </span>
1316
1189
  )}
1317
1190
  </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
- >
1191
+ <div className="ai-model-item-meta">
1330
1192
  <span
1331
1193
  style={{
1332
1194
  display: "flex",
@@ -1346,23 +1208,13 @@ function AiPromptPanelInternal({
1346
1208
  {modelData.provider}
1347
1209
  </span>
1348
1210
  {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
- >
1211
+ <span className="ai-pill ai-pill--cost">
1359
1212
  ${modelData.costPer1M}/1M
1360
1213
  </span>
1361
1214
  )}
1362
1215
  </div>
1363
1216
  </div>
1364
1217
  </div>
1365
- {/* Toggle Switch CSS amélioré */}
1366
1218
  <label
1367
1219
  style={{
1368
1220
  position: "relative",
@@ -1390,41 +1242,8 @@ function AiPromptPanelInternal({
1390
1242
  }}
1391
1243
  />
1392
1244
  <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>
1245
+ className={`ai-toggle ${isActive ? "ai-toggle--active" : ""}`}
1246
+ />
1428
1247
  </label>
1429
1248
  </div>
1430
1249
  );
@@ -1443,7 +1262,7 @@ function AiPromptPanelInternal({
1443
1262
  style={{
1444
1263
  textAlign: "center",
1445
1264
  padding: "32px 16px",
1446
- color: "var(--ai-text-tertiary, #9ca3af)",
1265
+ color: "var(--ai-text-tertiary)",
1447
1266
  fontSize: "14px",
1448
1267
  }}
1449
1268
  >
@@ -1461,10 +1280,7 @@ function AiPromptPanelInternal({
1461
1280
  setIsModelManagementOpen(false);
1462
1281
  setModelSearchQuery("");
1463
1282
  }}
1464
- style={{
1465
- ...aiStyles.button,
1466
- ...aiStyles.buttonSecondary,
1467
- }}
1283
+ className="ai-btn ai-btn--ghost"
1468
1284
  >
1469
1285
  Fermer
1470
1286
  </button>
@@ -1472,6 +1288,7 @@ function AiPromptPanelInternal({
1472
1288
  </div>
1473
1289
  </div>
1474
1290
  )}
1475
- </div>
1291
+ </div>,
1292
+ portalRoot
1476
1293
  );
1477
1294
  }