Abmacode12 commited on
Commit
ce4176c
·
verified ·
1 Parent(s): 5ca5f94

Manual changes saved

Browse files
Files changed (1) hide show
  1. index.html +920 -1
index.html CHANGED
@@ -793,4 +793,923 @@ export async function llmChat(messages: Msg[]) {
793
 
794
  const data: any = await res.json();
795
  return data?.message?.content ?? "Rosalinda: (réponse vide)";
796
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
793
 
794
  const data: any = await res.json();
795
  return data?.message?.content ?? "Rosalinda: (réponse vide)";
796
+ }
797
+ html
798
+ <!DOCTYPE html>
799
+ <html lang="fr">
800
+ <head>
801
+ <meta charset="UTF-8">
802
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
803
+ <title>Mini Constructeur de Site Web IA</title>
804
+ <style>
805
+ * {
806
+ box-sizing: border-box;
807
+ margin: 0;
808
+ padding: 0;
809
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
810
+ }
811
+
812
+ body {
813
+ display: flex;
814
+ flex-direction: column;
815
+ height: 100vh;
816
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
817
+ color: #333;
818
+ }
819
+
820
+ header {
821
+ background: linear-gradient(90deg, #4b6cb7 0%, #182848 100%);
822
+ color: white;
823
+ padding: 20px;
824
+ text-align: center;
825
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
826
+ }
827
+
828
+ header h1 {
829
+ font-size: 2.5rem;
830
+ margin-bottom: 10px;
831
+ }
832
+
833
+ header p {
834
+ font-size: 1.2rem;
835
+ opacity: 0.9;
836
+ }
837
+
838
+ .container {
839
+ display: flex;
840
+ flex: 1;
841
+ padding: 20px;
842
+ gap: 20px;
843
+ }
844
+
845
+ .toolbox {
846
+ width: 250px;
847
+ background: white;
848
+ border-radius: 15px;
849
+ padding: 20px;
850
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
851
+ display: flex;
852
+ flex-direction: column;
853
+ gap: 15px;
854
+ }
855
+
856
+ .toolbox h2 {
857
+ color: #4b6cb7;
858
+ margin-bottom: 10px;
859
+ font-size: 1.8rem;
860
+ }
861
+
862
+ .toolbox button {
863
+ padding: 15px;
864
+ border: none;
865
+ border-radius: 10px;
866
+ background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
867
+ color: white;
868
+ font-size: 1.1rem;
869
+ cursor: pointer;
870
+ transition: transform 0.3s, box-shadow 0.3s;
871
+ display: flex;
872
+ align-items: center;
873
+ justify-content: center;
874
+ gap: 10px;
875
+ }
876
+
877
+ .toolbox button:hover {
878
+ transform: translateY(-5px);
879
+ box-shadow: 0 5px 15px rgba(106, 17, 203, 0.4);
880
+ }
881
+
882
+ .toolbox button i {
883
+ font-size: 1.5rem;
884
+ }
885
+
886
+ .canvas {
887
+ flex: 1;
888
+ background: white;
889
+ border-radius: 15px;
890
+ padding: 20px;
891
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
892
+ overflow-y: auto;
893
+ position: relative;
894
+ min-height: 600px;
895
+ }
896
+
897
+ .canvas h2 {
898
+ color: #4b6cb7;
899
+ margin-bottom: 20px;
900
+ font-size: 1.8rem;
901
+ }
902
+
903
+ .element {
904
+ border: 2px dashed #4b6cb7;
905
+ border-radius: 10px;
906
+ padding: 20px;
907
+ margin-bottom: 20px;
908
+ cursor: move;
909
+ transition: all 0.3s;
910
+ position: relative;
911
+ background: white;
912
+ }
913
+
914
+ .element:hover {
915
+ border-color: #2575fc;
916
+ background: #f8f9ff;
917
+ }
918
+
919
+ .element.selected {
920
+ border: 2px solid #2575fc;
921
+ background: #f0f4ff;
922
+ }
923
+
924
+ .element .delete-btn {
925
+ position: absolute;
926
+ top: 10px;
927
+ right: 10px;
928
+ background: #ff4757;
929
+ color: white;
930
+ border: none;
931
+ border-radius: 5px;
932
+ padding: 5px 10px;
933
+ cursor: pointer;
934
+ display: none;
935
+ }
936
+
937
+ .element:hover .delete-btn {
938
+ display: block;
939
+ }
940
+
941
+ .element .edit-btn {
942
+ position: absolute;
943
+ top: 10px;
944
+ right: 60px;
945
+ background: #2ed573;
946
+ color: white;
947
+ border: none;
948
+ border-radius: 5px;
949
+ padding: 5px 10px;
950
+ cursor: pointer;
951
+ display: none;
952
+ }
953
+
954
+ .element:hover .edit-btn {
955
+ display: block;
956
+ }
957
+
958
+ .properties {
959
+ width: 300px;
960
+ background: white;
961
+ border-radius: 15px;
962
+ padding: 20px;
963
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
964
+ display: flex;
965
+ flex-direction: column;
966
+ gap: 15px;
967
+ }
968
+
969
+ .properties h2 {
970
+ color: #4b6cb7;
971
+ margin-bottom: 10px;
972
+ font-size: 1.8rem;
973
+ }
974
+
975
+ .properties input, .properties select, .properties textarea {
976
+ padding: 12px;
977
+ border: 2px solid #ddd;
978
+ border-radius: 8px;
979
+ font-size: 1rem;
980
+ transition: border 0.3s;
981
+ }
982
+
983
+ .properties input:focus, .properties select:focus, .properties textarea:focus {
984
+ border-color: #4b6cb7;
985
+ outline: none;
986
+ }
987
+
988
+ .properties label {
989
+ font-weight: bold;
990
+ color: #555;
991
+ margin-top: 10px;
992
+ }
993
+
994
+ .ai-panel {
995
+ background: white;
996
+ border-radius: 15px;
997
+ padding: 20px;
998
+ margin: 20px;
999
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
1000
+ display: flex;
1001
+ flex-direction: column;
1002
+ gap: 15px;
1003
+ }
1004
+
1005
+ .ai-panel h2 {
1006
+ color: #4b6cb7;
1007
+ font-size: 1.8rem;
1008
+ }
1009
+
1010
+ .ai-panel textarea {
1011
+ padding: 12px;
1012
+ border: 2px solid #ddd;
1013
+ border-radius: 8px;
1014
+ font-size: 1rem;
1015
+ min-height: 100px;
1016
+ resize: vertical;
1017
+ }
1018
+
1019
+ .ai-panel button {
1020
+ padding: 15px;
1021
+ border: none;
1022
+ border-radius: 10px;
1023
+ background: linear-gradient(135deg, #ff7e5f 0%, #feb47b 100%);
1024
+ color: white;
1025
+ font-size: 1.1rem;
1026
+ cursor: pointer;
1027
+ transition: transform 0.3s, box-shadow 0.3s;
1028
+ }
1029
+
1030
+ .ai-panel button:hover {
1031
+ transform: translateY(-5px);
1032
+ box-shadow: 0 5px 15px rgba(255, 126, 95, 0.4);
1033
+ }
1034
+
1035
+ footer {
1036
+ background: linear-gradient(90deg, #182848 0%, #4b6cb7 100%);
1037
+ color: white;
1038
+ text-align: center;
1039
+ padding: 15px;
1040
+ font-size: 1.1rem;
1041
+ }
1042
+
1043
+ .modal {
1044
+ display: none;
1045
+ position: fixed;
1046
+ z-index: 1000;
1047
+ left: 0;
1048
+ top: 0;
1049
+ width: 100%;
1050
+ height: 100%;
1051
+ background-color: rgba(0, 0, 0, 0.5);
1052
+ justify-content: center;
1053
+ align-items: center;
1054
+ }
1055
+
1056
+ .modal-content {
1057
+ background: white;
1058
+ padding: 30px;
1059
+ border-radius: 15px;
1060
+ width: 500px;
1061
+ max-width: 90%;
1062
+ box-shadow: 0 15px 50px rgba(0, 0, 0, 0.2);
1063
+ position: relative;
1064
+ }
1065
+
1066
+ .close-modal {
1067
+ position: absolute;
1068
+ top: 20px;
1069
+ right: 20px;
1070
+ font-size: 2rem;
1071
+ cursor: pointer;
1072
+ color: #aaa;
1073
+ }
1074
+
1075
+ .close-modal:hover {
1076
+ color: #000;
1077
+ }
1078
+
1079
+ .modal h2 {
1080
+ color: #4b6cb7;
1081
+ margin-bottom: 20px;
1082
+ font-size: 2rem;
1083
+ }
1084
+
1085
+ .modal textarea {
1086
+ width: 100%;
1087
+ min-height: 200px;
1088
+ padding: 15px;
1089
+ border: 2px solid #ddd;
1090
+ border-radius: 10px;
1091
+ font-family: monospace;
1092
+ font-size: 1rem;
1093
+ margin-bottom: 20px;
1094
+ resize: vertical;
1095
+ }
1096
+
1097
+ .modal button {
1098
+ padding: 15px 30px;
1099
+ border: none;
1100
+ border-radius: 10px;
1101
+ background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
1102
+ color: white;
1103
+ font-size: 1.2rem;
1104
+ cursor: pointer;
1105
+ transition: transform 0.3s, box-shadow 0.3s;
1106
+ width: 100%;
1107
+ }
1108
+
1109
+ .modal button:hover {
1110
+ transform: translateY(-5px);
1111
+ box-shadow: 0 5px 15px rgba(106, 17, 203, 0.4);
1112
+ }
1113
+
1114
+ .generate-btn {
1115
+ padding: 20px;
1116
+ border: none;
1117
+ border-radius: 15px;
1118
+ background: linear-gradient(135deg, #00b09b 0%, #96c93d 100%);
1119
+ color: white;
1120
+ font-size: 1.5rem;
1121
+ cursor: pointer;
1122
+ transition: transform 0.3s, box-shadow 0.3s;
1123
+ margin: 20px;
1124
+ display: flex;
1125
+ align-items: center;
1126
+ justify-content: center;
1127
+ gap: 15px;
1128
+ }
1129
+
1130
+ .generate-btn:hover {
1131
+ transform: translateY(-5px);
1132
+ box-shadow: 0 10px 25px rgba(0, 176, 155, 0.4);
1133
+ }
1134
+
1135
+ .generate-btn i {
1136
+ font-size: 2rem;
1137
+ }
1138
+ </style>
1139
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
1140
+ </head>
1141
+ <body>
1142
+ <header>
1143
+ <h1><i class="fas fa-magic"></i> Mini Constructeur de Site Web IA</h1>
1144
+ <p>Glissez-déposez des éléments, personnalisez et générez votre site web en quelques clics !</p>
1145
+ </header>
1146
+
1147
+ <div class="container">
1148
+ <div class="toolbox">
1149
+ <h2><i class="fas fa-tools"></i> Boîte à outils</h2>
1150
+ <button id="add-title"><i class="fas fa-heading"></i> Ajouter un titre</button>
1151
+ <button id="add-paragraph"><i class="fas fa-paragraph"></i> Ajouter un paragraphe</button>
1152
+ <button id="add-image"><i class="fas fa-image"></i> Ajouter une image</button>
1153
+ <button id="add-button"><i class="fas fa-square"></i> Ajouter un bouton</button>
1154
+ <button id="add-section"><i class="fas fa-layer-group"></i> Ajouter une section</button>
1155
+
1156
+ <h2 style="margin-top: 30px;"><i class="fas fa-palette"></i> Thèmes rapides</h2>
1157
+ <button id="theme-modern"><i class="fas fa-star"></i> Moderne</button>
1158
+ <button id="theme-classic"><i class="fas fa-landmark"></i> Classique</button>
1159
+ <button id="theme-dark"><i class="fas fa-moon"></i> Sombre</button>
1160
+ </div>
1161
+
1162
+ <div class="canvas" id="canvas">
1163
+ <h2><i class="fas fa-paint-brush"></i> Votre Canva</h2>
1164
+ <p style="color: #666; margin-bottom: 20px;">Glissez les éléments ici et personnalisez-les.</p>
1165
+ <!-- Les éléments ajoutés apparaîtront ici -->
1166
+ </div>
1167
+
1168
+ <div class="properties" id="properties-panel">
1169
+ <h2><i class="fas fa-sliders-h"></i> Propriétés</h2>
1170
+ <p style="color: #666;">Sélectionnez un élément pour le personnaliser.</p>
1171
+ <!-- Les contrôles de propriétés seront ajoutés dynamiquement -->
1172
+ </div>
1173
+ </div>
1174
+
1175
+ <div class="ai-panel">
1176
+ <h2><i class="fas fa-robot"></i> Assistant IA</h2>
1177
+ <p>Utilisez l'IA pour générer du contenu pour votre site. Entrez une description et choisissez le type de contenu.</p>
1178
+ <textarea id="ai-prompt" placeholder="Exemple : Un titre accrocheur pour un site de restaurant italien..."></textarea>
1179
+ <select id="ai-content-type">
1180
+ <option value="title">Titre</option>
1181
+ <option value="paragraph">Paragraphe</option>
1182
+ <option value="button">Texte de bouton</option>
1183
+ <option value="section">Section complète</option>
1184
+ </select>
1185
+ <button id="generate-ai-content"><i class="fas fa-bolt"></i> Générer avec l'IA</button>
1186
+ <small>Remarque : Vous devez configurer votre propre clé API OpenAI dans le code pour utiliser cette fonctionnalité.</small>
1187
+ </div>
1188
+
1189
+ <button class="generate-btn" id="generate-site">
1190
+ <i class="fas fa-rocket"></i> Générer et Télécharger le Site Web
1191
+ </button>
1192
+
1193
+ <footer>
1194
+ <p>Mini Constructeur de Site Web IA &copy; 2024 - Développé avec <i class="fas fa-heart" style="color: #ff4757;"></i> pour démontrer les capacités de génération de code</p>
1195
+ </footer>
1196
+
1197
+ <!-- Modal pour afficher le code généré -->
1198
+ <div class="modal" id="code-modal">
1199
+ <div class="modal-content">
1200
+ <span class="close-modal" id="close-modal">&times;</span>
1201
+ <h2><i class="fas fa-code"></i> Code généré</h2>
1202
+ <p>Voici le code HTML et CSS de votre site web. Copiez-le ou téléchargez-le.</p>
1203
+ <textarea id="generated-code" readonly></textarea>
1204
+ <button id="download-code"><i class="fas fa-download"></i> Télécharger le code</button>
1205
+ </div>
1206
+ </div>
1207
+
1208
+ <script>
1209
+ // État de l'application
1210
+ let elements = [];
1211
+ let selectedElementId = null;
1212
+ let elementCounter = 0;
1213
+
1214
+ // Références aux éléments DOM
1215
+ const canvas = document.getElementById('canvas');
1216
+ const propertiesPanel = document.getElementById('properties-panel');
1217
+ const generateSiteBtn = document.getElementById('generate-site');
1218
+ const codeModal = document.getElementById('code-modal');
1219
+ const generatedCodeTextarea = document.getElementById('generated-code');
1220
+ const closeModalBtn = document.getElementById('close-modal');
1221
+ const downloadCodeBtn = document.getElementById('download-code');
1222
+
1223
+ // Initialisation
1224
+ document.addEventListener('DOMContentLoaded', function() {
1225
+ // Ajouter les écouteurs d'événements pour les boutons d'ajout d'éléments
1226
+ document.getElementById('add-title').addEventListener('click', () => addElement('title'));
1227
+ document.getElementById('add-paragraph').addEventListener('click', () => addElement('paragraph'));
1228
+ document.getElementById('add-image').addEventListener('click', () => addElement('image'));
1229
+ document.getElementById('add-button').addEventListener('click', () => addElement('button'));
1230
+ document.getElementById('add-section').addEventListener('click', () => addElement('section'));
1231
+
1232
+ // Écouteurs pour les thèmes rapides
1233
+ document.getElementById('theme-modern').addEventListener('click', () => applyTheme('modern'));
1234
+ document.getElementById('theme-classic').addEventListener('click', () => applyTheme('classic'));
1235
+ document.getElementById('theme-dark').addEventListener('click', () => applyTheme('dark'));
1236
+
1237
+ // Écouteur pour générer le site
1238
+ generateSiteBtn.addEventListener('click', generateAndDownloadSite);
1239
+
1240
+ // Écouteurs pour la modal
1241
+ closeModalBtn.addEventListener('click', () => codeModal.style.display = 'none');
1242
+ downloadCodeBtn.addEventListener('click', downloadGeneratedCode);
1243
+
1244
+ // Écouteur pour fermer la modal en cliquant en dehors
1245
+ window.addEventListener('click', (event) => {
1246
+ if (event.target === codeModal) {
1247
+ codeModal.style.display = 'none';
1248
+ }
1249
+ });
1250
+
1251
+ // Écouteur pour l'IA (fonctionnalité basique)
1252
+ document.getElementById('generate-ai-content').addEventListener('click', generateAIContent);
1253
+
1254
+ // Afficher les propriétés par défaut
1255
+ updatePropertiesPanel();
1256
+ });
1257
+
1258
+ // Fonction pour ajouter un nouvel élément
1259
+ function addElement(type) {
1260
+ elementCounter++;
1261
+ const id = `element-${elementCounter}`;
1262
+ let content = '';
1263
+ let tag = 'div';
1264
+ let defaultStyles = {};
1265
+
1266
+ switch (type) {
1267
+ case 'title':
1268
+ content = 'Mon Titre Accrocheur';
1269
+ tag = 'h2';
1270
+ defaultStyles = {
1271
+ fontSize: '32px',
1272
+ fontWeight: 'bold',
1273
+ color: '#2c3e50',
1274
+ marginBottom: '20px'
1275
+ };
1276
+ break;
1277
+ case 'paragraph':
1278
+ content = 'Ceci est un paragraphe de texte. Vous pouvez le modifier en double-cliquant dessus ou via le panneau de propriétés.';
1279
+ tag = 'p';
1280
+ defaultStyles = {
1281
+ fontSize: '18px',
1282
+ lineHeight: '1.6',
1283
+ color: '#34495e',
1284
+ marginBottom: '20px'
1285
+ };
1286
+ break;
1287
+ case 'image':
1288
+ content = '<img src="https://via.placeholder.com/400x250/4b6cb7/ffffff?text=Image+Exemple" alt="Exemple" style="width:100%; border-radius:10px;">';
1289
+ tag = 'div';
1290
+ defaultStyles = {
1291
+ marginBottom: '20px'
1292
+ };
1293
+ break;
1294
+ case 'button':
1295
+ content = 'Cliquez ici';
1296
+ tag = 'button';
1297
+ defaultStyles = {
1298
+ backgroundColor: '#4b6cb7',
1299
+ color: 'white',
1300
+ padding: '15px 30px',
1301
+ border: 'none',
1302
+ borderRadius: '8px',
1303
+ fontSize: '18px',
1304
+ cursor: 'pointer',
1305
+ marginBottom: '20px'
1306
+ };
1307
+ break;
1308
+ case 'section':
1309
+ content = '<h3>Nouvelle Section</h3><p>Contenu de la section...</p>';
1310
+ tag = 'section';
1311
+ defaultStyles = {
1312
+ backgroundColor: '#f8f9fa',
1313
+ padding: '30px',
1314
+ borderRadius: '15px',
1315
+ marginBottom: '30px',
1316
+ borderLeft: '5px solid #4b6cb7'
1317
+ };
1318
+ break;
1319
+ }
1320
+
1321
+ const element = {
1322
+ id,
1323
+ type,
1324
+ tag,
1325
+ content,
1326
+ styles: defaultStyles,
1327
+ classes: []
1328
+ };
1329
+
1330
+ elements.push(element);
1331
+ renderElement(element);
1332
+ selectElement(id);
1333
+ }
1334
+
1335
+ // Fonction pour rendre un élément sur le canevas
1336
+ function renderElement(element) {
1337
+ // Créer l'élément DOM
1338
+ const el = document.createElement('div');
1339
+ el.id = element.id;
1340
+ el.className = 'element';
1341
+ el.innerHTML = `
1342
+ ${element.type === 'image' ? element.content : `<${element.tag}>${element.content}</${element.tag}>`}
1343
+ <button class="delete-btn" data-id="${element.id}"><i class="fas fa-trash"></i></button>
1344
+ <button class="edit-btn" data-id="${element.id}"><i class="fas fa-edit"></i></button>
1345
+ `;
1346
+
1347
+ // Appliquer les styles
1348
+ Object.keys(element.styles).forEach(style => {
1349
+ el.style[style] = element.styles[style];
1350
+ });
1351
+
1352
+ // Ajouter des écouteurs d'événements
1353
+ el.addEventListener('click', (e) => {
1354
+ if (!e.target.closest('.delete-btn') && !e.target.closest('.edit-btn')) {
1355
+ selectElement(element.id);
1356
+ }
1357
+ });
1358
+
1359
+ // Double-clic pour éditer le texte (si ce n'est pas une image)
1360
+ if (element.type !== 'image') {
1361
+ el.addEventListener('dblclick', () => {
1362
+ const currentText = el.querySelector(`${element.tag}`).innerText;
1363
+ const newText = prompt('Modifier le texte:', currentText);
1364
+ if (newText !== null) {
1365
+ element.content = newText;
1366
+ el.querySelector(`${element.tag}`).innerText = newText;
1367
+ updatePropertiesPanel();
1368
+ }
1369
+ });
1370
+ }
1371
+
1372
+ // Bouton supprimer
1373
+ el.querySelector('.delete-btn').addEventListener('click', (e) => {
1374
+ e.stopPropagation();
1375
+ deleteElement(element.id);
1376
+ });
1377
+
1378
+ // Bouton éditer (ouvre le panneau de propriétés)
1379
+ el.querySelector('.edit-btn').addEventListener('click', (e) => {
1380
+ e.stopPropagation();
1381
+ selectElement(element.id);
1382
+ });
1383
+
1384
+ // Rendre l'élément glissable
1385
+ el.draggable = true;
1386
+ el.addEventListener('dragstart', (e) => {
1387
+ e.dataTransfer.setData('text/plain', element.id);
1388
+ });
1389
+
1390
+ // Ajouter au canevas
1391
+ canvas.appendChild(el);
1392
+
1393
+ // Zone de dépôt pour le glisser-déposer
1394
+ canvas.addEventListener('dragover', (e) => e.preventDefault());
1395
+ canvas.addEventListener('drop', (e) => {
1396
+ e.preventDefault();
1397
+ const id = e.dataTransfer.getData('text/plain');
1398
+ const draggedEl = document.getElementById(id);
1399
+ if (draggedEl) {
1400
+ // On pourrait implémenter un repositionnement plus sophistiqué ici
1401
+ // Pour l'exemple, on ne change pas la position
1402
+ }
1403
+ });
1404
+ }
1405
+
1406
+ // Fonction pour supprimer un élément
1407
+ function deleteElement(id) {
1408
+ elements = elements.filter(el => el.id !== id);
1409
+ document.getElementById(id)?.remove();
1410
+ if (selectedElementId === id) {
1411
+ selectedElementId = null;
1412
+ updatePropertiesPanel();
1413
+ }
1414
+ }
1415
+
1416
+ // Fonction pour sélectionner un élément
1417
+ function selectElement(id) {
1418
+ // Désélectionner l'élément précédent
1419
+ if (selectedElementId) {
1420
+ const prevEl = document.getElementById(selectedElementId);
1421
+ if (prevEl) prevEl.classList.remove('selected');
1422
+ }
1423
+
1424
+ // Sélectionner le nouvel élément
1425
+ selectedElementId = id;
1426
+ const currentEl = document.getElementById(id);
1427
+ if (currentEl) {
1428
+ currentEl.classList.add('selected');
1429
+ }
1430
+
1431
+ updatePropertiesPanel();
1432
+ }
1433
+
1434
+ // Fonction pour mettre à jour le panneau de propriétés
1435
+ function updatePropertiesPanel() {
1436
+ propertiesPanel.innerHTML = '<h2><i class="fas fa-sliders-h"></i> Propriétés</h2>';
1437
+
1438
+ if (!selectedElementId) {
1439
+ propertiesPanel.innerHTML += '<p style="color:#666;">Sélectionnez un élément pour le personnaliser.</p>';
1440
+ return;
1441
+ }
1442
+
1443
+ const element = elements.find(el => el.id === selectedElementId);
1444
+ if (!element) return;
1445
+
1446
+ // Afficher les propriétés de l'élément sélectionné
1447
+ propertiesPanel.innerHTML += `
1448
+ <p><strong>Type:</strong> ${element.type}</p>
1449
+ <label for="edit-content">Contenu:</label>
1450
+ <textarea id="edit-content">${element.type === 'image' ? 'Image (non modifiable)' : element.content}</textarea>
1451
+ <label for="edit-font-size">Taille de police:</label>
1452
+ <input type="text" id="edit-font-size" value="${element.styles.fontSize || '16px'}">
1453
+ <label for="edit-color">Couleur:</label>
1454
+ <input type="color" id="edit-color" value="${element.styles.color || '#000000'}">
1455
+ <label for="edit-bg-color">Couleur de fond:</label>
1456
+ <input type="color" id="edit-bg-color" value="${element.styles.backgroundColor || '#ffffff'}">
1457
+ <label for="edit-padding">Padding:</label>
1458
+ <input type="text" id="edit-padding" value="${element.styles.padding || '0px'}">
1459
+ <label for="edit-margin">Margin:</label>
1460
+ <input type="text" id="edit-margin" value="${element.styles.margin || '0px'}">
1461
+ <button id="apply-properties"><i class="fas fa-check"></i> Appliquer les modifications</button>
1462
+ `;
1463
+
1464
+ // Écouteur pour appliquer les modifications
1465
+ document.getElementById('apply-properties').addEventListener('click', () => {
1466
+ applyProperties(element);
1467
+ });
1468
+ }
1469
+
1470
+ // Fonction pour appliquer les propriétés modifiées
1471
+ function applyProperties(element) {
1472
+ // Mettre à jour le contenu
1473
+ if (element.type !== 'image') {
1474
+ const newContent = document.getElementById('edit-content').value;
1475
+ element.content = newContent;
1476
+ }
1477
+
1478
+ // Mettre à jour les styles
1479
+ const styles = {
1480
+ fontSize: document.getElementById('edit-font-size').value,
1481
+ color: document.getElementById('edit-color').value,
1482
+ backgroundColor: document.getElementById('edit-bg-color').value,
1483
+ padding: document.getElementById('edit-padding').value,
1484
+ margin: document.getElementById('edit-margin').value
1485
+ };
1486
+
1487
+ // Appliquer les styles non vides
1488
+ Object.keys(styles).forEach(style => {
1489
+ if (styles[style]) {
1490
+ element.styles[style] = styles[style];
1491
+ }
1492
+ });
1493
+
1494
+ // Re-rendre l'élément
1495
+ const el = document.getElementById(element.id);
1496
+ if (el) {
1497
+ if (element.type !== 'image') {
1498
+ el.querySelector(element.tag).innerText = element.content;
1499
+ }
1500
+
1501
+ Object.keys(element.styles).forEach(style => {
1502
+ el.style[style] = element.styles[style];
1503
+ });
1504
+ }
1505
+ }
1506
+
1507
+ // Fonction pour appliquer un thème rapide
1508
+ function applyTheme(themeName) {
1509
+ const themes = {
1510
+ modern: {
1511
+ backgroundColor: '#ffffff',
1512
+ primaryColor: '#4b6cb7',
1513
+ secondaryColor: '#2575fc',
1514
+ fontFamily: "'Segoe UI', sans-serif"
1515
+ },
1516
+ classic: {
1517
+ backgroundColor: '#f8f4e9',
1518
+ primaryColor: '#8b4513',
1519
+ secondaryColor: '#d2691e',
1520
+ fontFamily: "'Times New Roman', serif"
1521
+ },
1522
+ dark: {
1523
+ backgroundColor: '#2c3e50',
1524
+ primaryColor: '#1abc9c',
1525
+ secondaryColor: '#3498db',
1526
+ fontFamily: "'Arial', sans-serif"
1527
+ }
1528
+ };
1529
+
1530
+ const theme = themes[themeName];
1531
+
1532
+ // Appliquer le thème au body
1533
+ document.body.style.backgroundColor = theme.backgroundColor;
1534
+ document.body.style.color = theme.primaryColor;
1535
+ document.body.style.fontFamily = theme.fontFamily;
1536
+
1537
+ // Appliquer le thème aux éléments existants
1538
+ elements.forEach(element => {
1539
+ if (element.type === 'title' || element.type === 'paragraph') {
1540
+ element.styles.color = theme.primaryColor;
1541
+ }
1542
+ if (element.type === 'button') {
1543
+ element.styles.backgroundColor = theme.secondaryColor;
1544
+ }
1545
+ if (element.type === 'section') {
1546
+ element.styles.backgroundColor = theme.backgroundColor;
1547
+ element.styles.borderLeftColor = theme.secondaryColor;
1548
+ }
1549
+
1550
+ // Re-rendre l'élément
1551
+ const el = document.getElementById(element.id);
1552
+ if (el) {
1553
+ Object.keys(element.styles).forEach(style => {
1554
+ el.style[style] = element.styles[style];
1555
+ });
1556
+ }
1557
+ });
1558
+ }
1559
+
1560
+ // Fonction pour générer et télécharger le site
1561
+ function generateAndDownloadSite() {
1562
+ // Générer le code HTML
1563
+ let html = `<!DOCTYPE html>
1564
+ <html lang="fr">
1565
+ <head>
1566
+ <meta charset="UTF-8">
1567
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1568
+ <title>Site Généré avec le Mini Constructeur</title>
1569
+ <style>
1570
+ * {
1571
+ margin: 0;
1572
+ padding: 0;
1573
+ box-sizing: border-box;
1574
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
1575
+ }
1576
+ body {
1577
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
1578
+ color: #333;
1579
+ line-height: 1.6;
1580
+ padding: 20px;
1581
+ }
1582
+ .container {
1583
+ max-width: 1200px;
1584
+ margin: 0 auto;
1585
+ padding: 20px;
1586
+ }
1587
+ ${generateCSS()}
1588
+ </style>
1589
+ </head>
1590
+ <body>
1591
+ <div class="container">
1592
+ `;
1593
+
1594
+ // Ajouter chaque élément
1595
+ elements.forEach(element => {
1596
+ html += ` <!-- Élément ${element.type} -->\n`;
1597
+ html += ` <div class="generated-element ${element.type}">\n`;
1598
+ if (element.type === 'image') {
1599
+ html += ` ${element.content}\n`;
1600
+ } else {
1601
+ html += ` <${element.tag}>${element.content}</${element.tag}>\n`;
1602
+ }
1603
+ html += ` </div>\n\n`;
1604
+ });
1605
+
1606
+ html += ` </div>
1607
+ </body>
1608
+ </html>`;
1609
+
1610
+ // Afficher le code dans la modal
1611
+ generatedCodeTextarea.value = html;
1612
+ codeModal.style.display = 'flex';
1613
+ }
1614
+
1615
+ // Fonction pour générer le CSS
1616
+ function generateCSS() {
1617
+ let css = '';
1618
+ elements.forEach(element => {
1619
+ css += `.${element.id} {\n`;
1620
+ Object.keys(element.styles).forEach(style => {
1621
+ const cssStyle = style.replace(/([A-Z])/g, '-$1').toLowerCase();
1622
+ css += ` ${cssStyle}: ${element.styles[style]};\n`;
1623
+ });
1624
+ css += '}\n\n';
1625
+ });
1626
+ return css;
1627
+ }
1628
+
1629
+ // Fonction pour télécharger le code généré
1630
+ function downloadGeneratedCode() {
1631
+ const code = generatedCodeTextarea.value;
1632
+ const blob = new Blob([code], { type: 'text/html' });
1633
+ const url = URL.createObjectURL(blob);
1634
+ const a = document.createElement('a');
1635
+ a.href = url;
1636
+ a.download = 'site-generé.html';
1637
+ a.click();
1638
+ URL.revokeObjectURL(url);
1639
+ }
1640
+
1641
+ // Fonction pour générer du contenu avec l'IA (version simulée car besoin d'une clé API)
1642
+ function generateAIContent() {
1643
+ const prompt = document.getElementById('ai-prompt').value;
1644
+ const contentType = document.getElementById('ai-content-type').value;
1645
+
1646
+ if (!prompt.trim()) {
1647
+ alert('Veuillez entrer une description pour l\'IA.');
1648
+ return;
1649
+ }
1650
+
1651
+ // Simulation de réponse IA (en production, il faudrait appeler l'API OpenAI)
1652
+ const responses = {
1653
+ title: [
1654
+ "Découvrez un Monde d'Innovation",
1655
+ "Votre Partenaire pour la Réussite Digitale",
1656
+ "Excellence et Créativité au Service de Vos Projets"
1657
+ ],
1658
+ paragraph: [
1659
+ "Nous sommes une équipe passionnée dédiée à la création de solutions web innovantes. Notre approche combine design élégant et technologie de pointe pour offrir des expériences utilisateur exceptionnelles.",
1660
+ "Avec des années d'expérience dans le développement web, nous accompagnons nos clients dans la réalisation de leurs projets digitaux, de la conception à la mise en production.",
1661
+ "Notre philosophie est simple : comprendre vos besoins, anticiper vos attentes et délivrer des solutions qui dépassent vos espérances."
1662
+ ],
1663
+ button: [
1664
+ "Commencer l'aventure",
1665
+ "En savoir plus",
1666
+ "Contactez-nous"
1667
+ ],
1668
+ section: `
1669
+ <section style="background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%); color: white; padding: 60px 20px; border-radius: 20px; text-align: center;">
1670
+ <h2 style="font-size: 2.5rem; margin-bottom: 20px;">Une Solution Sur Mesure</h2>
1671
+ <p style="font-size: 1.2rem; max-width: 800px; margin: 0 auto 30px;">Notre équipe d'experts crée des solutions personnalisées adaptées à vos besoins spécifiques pour maximiser votre impact digital.</p>
1672
+ <button style="background: white; color: #2575fc; border: none; padding: 15px 40px; font-size: 1.1rem; border-radius: 50px; cursor: pointer; font-weight: bold;">Découvrir nos réalisations</button>
1673
+ </section>
1674
+ `
1675
+ };
1676
+
1677
+ // Choisir une réponse aléatoire pour le type demandé
1678
+ let response;
1679
+ if (contentType === 'section') {
1680
+ response = responses[contentType];
1681
+ } else {
1682
+ const options = responses[contentType];
1683
+ response = options[Math.floor(Math.random() * options.length)];
1684
+ }
1685
+
1686
+ // Si un élément est sélectionné, mettre à jour son contenu
1687
+ if (selectedElementId) {
1688
+ const element = elements.find(el => el.id === selectedElementId);
1689
+ if (element) {
1690
+ element.content = response;
1691
+ const el = document.getElementById(element.id);
1692
+ if (el && element.type !== 'image') {
1693
+ el.querySelector(element.tag).innerHTML = response;
1694
+ updatePropertiesPanel();
1695
+ }
1696
+ }
1697
+ } else {
1698
+ // Sinon, ajouter un nouvel élément avec le contenu généré
1699
+ let type = contentType;
1700
+ if (contentType === 'section') type = 'section';
1701
+ addElement(type);
1702
+ // Le nouvel élément aura le contenu par défaut, donc on le met à jour
1703
+ const newElement = elements[elements.length - 1];
1704
+ newElement.content = response;
1705
+ const el = document.getElementById(newElement.id);
1706
+ if (el && newElement.type !== 'image') {
1707
+ el.querySelector(newElement.tag).innerHTML = response;
1708
+ }
1709
+ }
1710
+
1711
+ alert('Contenu généré avec l\'IA (simulation). En production, connectez-vous à l\'API OpenAI.');
1712
+ }
1713
+ </script>
1714
+ </body>
1715
+ </html>