Changeset 3453884
- Timestamp:
- 02/04/2026 03:01:35 PM (8 weeks ago)
- Location:
- ai-builder
- Files:
-
- 2 added
- 7 edited
- 50 copied
-
tags/2.4.7 (copied) (copied from ai-builder/trunk)
-
tags/2.4.7/admin/menu.php (copied) (copied from ai-builder/trunk/admin/menu.php)
-
tags/2.4.7/admin/pages/agent-chat.php (copied) (copied from ai-builder/trunk/admin/pages/agent-chat.php)
-
tags/2.4.7/admin/pages/credits.php (copied) (copied from ai-builder/trunk/admin/pages/credits.php)
-
tags/2.4.7/admin/pages/multi-page.php (copied) (copied from ai-builder/trunk/admin/pages/multi-page.php)
-
tags/2.4.7/admin/pages/settings.php (copied) (copied from ai-builder/trunk/admin/pages/settings.php) (2 diffs)
-
tags/2.4.7/admin/pages/translation-settings.php (copied) (copied from ai-builder/trunk/admin/pages/translation-settings.php)
-
tags/2.4.7/admin/pages/tuto.php (copied) (copied from ai-builder/trunk/admin/pages/tuto.php)
-
tags/2.4.7/aibui-builder.php (copied) (copied from ai-builder/trunk/aibui-builder.php) (4 diffs)
-
tags/2.4.7/assets/css/account.css (copied) (copied from ai-builder/trunk/assets/css/account.css)
-
tags/2.4.7/assets/css/credits.css (copied) (copied from ai-builder/trunk/assets/css/credits.css)
-
tags/2.4.7/assets/css/language-switcher.css (copied) (copied from ai-builder/trunk/assets/css/language-switcher.css)
-
tags/2.4.7/assets/css/multi-page.css (copied) (copied from ai-builder/trunk/assets/css/multi-page.css)
-
tags/2.4.7/assets/css/settings.css (modified) (3 diffs)
-
tags/2.4.7/assets/css/translation.css (copied) (copied from ai-builder/trunk/assets/css/translation.css)
-
tags/2.4.7/assets/js/account.js (copied) (copied from ai-builder/trunk/assets/js/account.js)
-
tags/2.4.7/assets/js/agent-chat.js (copied) (copied from ai-builder/trunk/assets/js/agent-chat.js)
-
tags/2.4.7/assets/js/build/index.asset.php (copied) (copied from ai-builder/trunk/assets/js/build/index.asset.php)
-
tags/2.4.7/assets/js/build/index.js (copied) (copied from ai-builder/trunk/assets/js/build/index.js)
-
tags/2.4.7/assets/js/chat-widget.js (copied) (copied from ai-builder/trunk/assets/js/chat-widget.js) (8 diffs)
-
tags/2.4.7/assets/js/credits.js (copied) (copied from ai-builder/trunk/assets/js/credits.js)
-
tags/2.4.7/assets/js/language-switcher-block.js (copied) (copied from ai-builder/trunk/assets/js/language-switcher-block.js)
-
tags/2.4.7/assets/js/multi-page-apply.js (copied) (copied from ai-builder/trunk/assets/js/multi-page-apply.js)
-
tags/2.4.7/assets/js/multi-page.js (copied) (copied from ai-builder/trunk/assets/js/multi-page.js)
-
tags/2.4.7/assets/js/pattern-translation.js (copied) (copied from ai-builder/trunk/assets/js/pattern-translation.js)
-
tags/2.4.7/assets/js/review-banner.js (added)
-
tags/2.4.7/assets/js/settings.js (copied) (copied from ai-builder/trunk/assets/js/settings.js) (2 diffs)
-
tags/2.4.7/assets/js/src/editor-blocks/ai-block/ai-block.js (copied) (copied from ai-builder/trunk/assets/js/src/editor-blocks/ai-block/ai-block.js)
-
tags/2.4.7/assets/js/src/editor-blocks/image-ai-blocks/image-ai-controls.js (copied) (copied from ai-builder/trunk/assets/js/src/editor-blocks/image-ai-blocks/image-ai-controls.js)
-
tags/2.4.7/assets/js/src/editor-blocks/text-ai-blocks/text-ai-controls.js (copied) (copied from ai-builder/trunk/assets/js/src/editor-blocks/text-ai-blocks/text-ai-controls.js)
-
tags/2.4.7/assets/js/translation.js (copied) (copied from ai-builder/trunk/assets/js/translation.js)
-
tags/2.4.7/composer.json (copied) (copied from ai-builder/trunk/composer.json)
-
tags/2.4.7/composer.lock (copied) (copied from ai-builder/trunk/composer.lock)
-
tags/2.4.7/config.js (copied) (copied from ai-builder/trunk/config.js)
-
tags/2.4.7/debug-language.log (copied) (copied from ai-builder/trunk/debug-language.log)
-
tags/2.4.7/debug-template-part.log (copied) (copied from ai-builder/trunk/debug-template-part.log)
-
tags/2.4.7/debug-unescape.log (copied) (copied from ai-builder/trunk/debug-unescape.log)
-
tags/2.4.7/includes/class-agent-chat-handler.php (copied) (copied from ai-builder/trunk/includes/class-agent-chat-handler.php)
-
tags/2.4.7/includes/class-agent-discovery-service.php (copied) (copied from ai-builder/trunk/includes/class-agent-discovery-service.php)
-
tags/2.4.7/includes/class-agent-execution-service.php (copied) (copied from ai-builder/trunk/includes/class-agent-execution-service.php)
-
tags/2.4.7/includes/class-agent-security-service.php (copied) (copied from ai-builder/trunk/includes/class-agent-security-service.php)
-
tags/2.4.7/includes/class-ajax-handler.php (copied) (copied from ai-builder/trunk/includes/class-ajax-handler.php)
-
tags/2.4.7/includes/class-css-handler.php (copied) (copied from ai-builder/trunk/includes/class-css-handler.php)
-
tags/2.4.7/includes/class-generations-storage.php (copied) (copied from ai-builder/trunk/includes/class-generations-storage.php)
-
tags/2.4.7/includes/class-js-handler.php (copied) (copied from ai-builder/trunk/includes/class-js-handler.php)
-
tags/2.4.7/includes/class-translation-handler.php (copied) (copied from ai-builder/trunk/includes/class-translation-handler.php)
-
tags/2.4.7/includes/class-translation-manager.php (copied) (copied from ai-builder/trunk/includes/class-translation-manager.php)
-
tags/2.4.7/includes/class-translation-settings.php (copied) (copied from ai-builder/trunk/includes/class-translation-settings.php)
-
tags/2.4.7/includes/class-translation-switcher.php (copied) (copied from ai-builder/trunk/includes/class-translation-switcher.php)
-
tags/2.4.7/package-lock.json (copied) (copied from ai-builder/trunk/package-lock.json)
-
tags/2.4.7/readme.txt (copied) (copied from ai-builder/trunk/readme.txt) (1 diff)
-
tags/2.4.7/templates (copied) (copied from ai-builder/trunk/templates)
-
trunk/admin/pages/settings.php (modified) (2 diffs)
-
trunk/aibui-builder.php (modified) (4 diffs)
-
trunk/assets/css/settings.css (modified) (3 diffs)
-
trunk/assets/js/chat-widget.js (modified) (8 diffs)
-
trunk/assets/js/review-banner.js (added)
-
trunk/assets/js/settings.js (modified) (2 diffs)
-
trunk/readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
ai-builder/tags/2.4.7/admin/pages/settings.php
r3408247 r3453884 46 46 <th scope="row"><label for="siteDescription">Site description & context</label></th> 47 47 <td> 48 <textarea name="siteDescription" id="siteDescription" class="large-text" rows="4" 48 <textarea name="siteDescription" id="siteDescription" class="large-text" rows="4" maxlength="500" 49 49 placeholder="Describe your site and add any additional context that will help AI generate better content"></textarea> 50 <p id="siteDescription-counter" class="description" style="margin-top:4px;margin-bottom:4px;">0/500</p> 50 51 <p class="description">Start with your site's description, then add any relevant information about your business, target audience, or specific requirements.</p> 51 52 </td> … … 111 112 </tbody> 112 113 </table> 114 <div id="aibui-settings-toast" style="display:none;"></div> 113 115 114 116 <p class="submit"> 115 <button type="submit" class="button button-primary ">Save Settings</button>117 <button type="submit" class="button button-primary button-center">Save Settings</button> 116 118 </p> 117 119 </form> 118 120 119 <div id="aibui-settings-toast" style="display:none;"></div>120 121 </div> -
ai-builder/tags/2.4.7/aibui-builder.php
r3443924 r3453884 4 4 * Plugin URI: https://website-ai-builder.com/ 5 5 * Description: This plugin is used to build your website with AI. 6 * Version: 2.4. 66 * Version: 2.4.7 7 7 * Author: enkic 8 8 * Author URI: https://enkicorbin.fr/ … … 18 18 19 19 // Définir la version du plugin 20 define('AIBUI_VERSION', '2.4. 6');20 define('AIBUI_VERSION', '2.4.7'); 21 21 22 22 /** … … 540 540 } 541 541 542 $current_screen = get_current_screen(); 542 543 // Charger les styles et scripts pour la page account du plugin AI Builder 543 $current_screen = get_current_screen();544 544 if ($current_screen && strpos($current_screen->id, 'aibui-assistant') !== false) { 545 545 wp_enqueue_style( … … 755 755 ) 756 756 ); 757 } 758 759 // Bandeau de review : uniquement sur les pages admin du plugin 760 if ($current_screen) { 761 $screen_id = $current_screen->id; 762 $is_plugin_screen = 763 strpos($screen_id, 'aibui-assistant') !== false || 764 strpos($screen_id, 'aibui-credits') !== false || 765 strpos($screen_id, 'aibui-tuto') !== false || 766 strpos($screen_id, 'aibui-multi-page') !== false || 767 strpos($screen_id, 'aibui-agent-chat') !== false || 768 strpos($screen_id, 'aibui-translation-settings') !== false || 769 strpos($screen_id, 'aibui-settings') !== false; 770 771 if ($is_plugin_screen) { 772 // S'assurer que config.js est chargé 773 wp_enqueue_script( 774 'ai-builder-config', 775 plugin_dir_url(__FILE__) . 'config.js', 776 [], 777 AIBUI_VERSION, 778 true 779 ); 780 wp_enqueue_script( 781 'ai-builder-review-banner', 782 plugin_dir_url(__FILE__) . 'assets/js/review-banner.js', 783 ['ai-builder-config'], 784 AIBUI_VERSION, 785 true 786 ); 787 wp_localize_script( 788 'ai-builder-review-banner', 789 'aiBuilderReviewVars', 790 array( 791 'ajaxurl' => admin_url('admin-ajax.php'), 792 'nonce' => wp_create_nonce('aibui_nonce'), 793 'reviewUrl' => 'https://wordpress.org/support/plugin/ai-builder/reviews/#new-post', 794 ) 795 ); 796 } 757 797 } 758 798 -
ai-builder/tags/2.4.7/assets/css/settings.css
r3397412 r3453884 15 15 } 16 16 17 .ai-builder-settings >p {17 .ai-builder-settings>p { 18 18 margin-top: 0; 19 19 margin-bottom: 28px; … … 113 113 } 114 114 115 .ai-builder-settings .submit { 116 margin-top: 32px; 117 text-align: center; 118 } 119 115 120 .ai-builder-settings .submit .button-primary:hover { 116 121 transform: translateY(-1px); … … 154 159 } 155 160 } 156 -
ai-builder/tags/2.4.7/assets/js/chat-widget.js
r3443924 r3453884 59 59 "beforeend", 60 60 ` 61 <div id="chat-toggle"> 🤖AI Builder</div>61 <div id="chat-toggle">AI Builder</div> 62 62 <div id="chat-box"> 63 63 <div id="chat-header"> … … 77 77 <div id="chat-messages"></div> 78 78 <div id="chat-input"> 79 <textarea placeholder="Create a modern pricing page with 3 plans and call-to-action buttons..." rows="2"></textarea> 79 <textarea placeholder="Create a modern pricing page with 3 plans and call-to-action buttons..." rows="2" maxlength="2000"></textarea> 80 <div id="chat-char-counter">0/2000</div> 80 81 <button>Generate</button> 81 82 <button id="chat-undo" style="display: none;">Undo</button> … … 131 132 const input = document.querySelector("#chat-input textarea"); 132 133 const sendBtn = document.querySelector("#chat-input button"); 134 const charCounter = document.getElementById("chat-char-counter"); 133 135 const undoBtn = document.getElementById("chat-undo"); 134 136 let chatHistory = []; 137 138 const MAX_CHAT_CHARS = 2000; 139 140 // Met à jour le compteur de caractères du chat 141 function updateChatCharCounter() { 142 if (!input || !charCounter) return; 143 const currentLength = input.value.length; 144 // Sécurité : tronquer si, pour une raison quelconque, on dépasse la limite 145 if (currentLength > MAX_CHAT_CHARS) { 146 input.value = input.value.slice(0, MAX_CHAT_CHARS); 147 } 148 charCounter.textContent = `${input.value.length}/${MAX_CHAT_CHARS}`; 149 } 150 151 if (input) { 152 input.addEventListener("input", updateChatCharCounter); 153 // Initialiser l'affichage du compteur 154 updateChatCharCounter(); 155 } 156 157 // Indicateur de saisie de l'IA (3 points animés) 158 function createTypingIndicator() { 159 if (!messages) return null; 160 let indicator = document.getElementById("chat-typing-indicator"); 161 if (!indicator) { 162 indicator = document.createElement("div"); 163 indicator.id = "chat-typing-indicator"; 164 indicator.innerHTML = ` 165 <span class="typing-dot"></span> 166 <span class="typing-dot"></span> 167 <span class="typing-dot"></span> 168 `; 169 } 170 return indicator; 171 } 172 173 function showTypingIndicator() { 174 if (!messages) return; 175 const indicator = createTypingIndicator(); 176 if (!indicator) return; 177 if (!messages.contains(indicator)) { 178 messages.appendChild(indicator); 179 } 180 } 181 182 function hideTypingIndicator() { 183 const indicator = document.getElementById("chat-typing-indicator"); 184 if (indicator && indicator.parentNode) { 185 indicator.parentNode.removeChild(indicator); 186 } 187 } 135 188 136 189 function getChatStorageKey() { … … 292 345 if (!messages) return; 293 346 347 // Si un indicateur de saisie est présent, le garder toujours en bas 348 const typingIndicator = document.getElementById("chat-typing-indicator"); 349 if (typingIndicator && typingIndicator.parentNode === messages) { 350 messages.removeChild(typingIndicator); 351 } 352 294 353 const messageDiv = document.createElement("div"); 295 354 messageDiv.className = type === "assistant" ? "ai-message" : "user-message"; 296 355 297 356 if (type === "assistant") { 298 messageDiv.innerHTML = ` <strong>🤖</strong>${message}`;357 messageDiv.innerHTML = `${message}`; 299 358 } else { 300 messageDiv.innerHTML = ` <strong>👤</strong>${message}`;359 messageDiv.innerHTML = `${message}`; 301 360 } 302 361 303 362 messages.appendChild(messageDiv); 363 364 // Ré‑ajouter l'indicateur de saisie en bas si nécessaire 365 if (typingIndicator) { 366 messages.appendChild(typingIndicator); 367 } 304 368 messages.scrollTop = messages.scrollHeight; 305 369 … … 1197 1261 // 🔒 Désactiver le bouton + animation loading 1198 1262 sendBtn.disabled = true; 1199 sendBtn.classList.add("loading");1263 // sendBtn.classList.add("loading"); 1200 1264 sendBtn.textContent = "Generating..."; 1201 1265 … … 1205 1269 } 1206 1270 1271 // 👀 Afficher l'indicateur de saisie de l'IA 1272 if (typeof showTypingIndicator === "function") { 1273 showTypingIndicator(); 1274 } 1275 1207 1276 // Ajouter le message utilisateur à l'historique 1208 1277 addMessage(finalQuestion, "user"); 1209 1278 input.value = ""; 1279 // Réinitialiser le compteur après envoi 1280 if (typeof updateChatCharCounter === "function") { 1281 updateChatCharCounter(); 1282 } 1210 1283 messages.scrollTop = messages.scrollHeight; 1211 1284 … … 1352 1425 toggleBtn.classList.remove("generating"); 1353 1426 } 1427 1428 // 👀 Masquer l'indicateur de saisie de l'IA 1429 if (typeof hideTypingIndicator === "function") { 1430 hideTypingIndicator(); 1431 } 1354 1432 } 1355 1433 } … … 1367 1445 const cssStyles = document.createElement("style"); 1368 1446 cssStyles.textContent = ` 1447 /* Zone de saisie du chat */ 1448 #chat-input { 1449 display: flex; 1450 flex-direction: column; 1451 gap: 6px; 1452 } 1453 1454 #chat-input textarea { 1455 width: 100%; 1456 resize: vertical; 1457 } 1458 1459 #chat-char-counter { 1460 align-self: flex-end; 1461 font-size: 11px; 1462 color: #888; 1463 } 1464 1465 /* Indicateur de saisie de l'IA */ 1466 #chat-typing-indicator { 1467 display: inline-flex; 1468 align-items: center; 1469 gap: 4px; 1470 padding: 6px 10px; 1471 border-radius: 12px; 1472 background-color: #f1f3f5; 1473 color: #555; 1474 font-size: 12px; 1475 max-width: 80%; 1476 margin-top: 4px; 1477 } 1478 1479 #chat-typing-indicator .typing-dot { 1480 width: 6px; 1481 height: 6px; 1482 border-radius: 50%; 1483 background-color: #888; 1484 display: inline-block; 1485 animation: ai-typing-bounce 1s infinite ease-in-out; 1486 } 1487 1488 #chat-typing-indicator .typing-dot:nth-child(2) { 1489 animation-delay: 0.15s; 1490 } 1491 1492 #chat-typing-indicator .typing-dot:nth-child(3) { 1493 animation-delay: 0.3s; 1494 } 1495 1496 @keyframes ai-typing-bounce { 1497 0%, 60%, 100% { 1498 transform: translateY(0); 1499 opacity: 0.4; 1500 } 1501 30% { 1502 transform: translateY(-4px); 1503 opacity: 1; 1504 } 1505 } 1506 1369 1507 /* Header du chat avec bouton CSS intégré */ 1370 1508 #chat-header { -
ai-builder/tags/2.4.7/assets/js/settings.js
r3408247 r3453884 41 41 toast.style.display = "none"; 42 42 }, 4000); 43 } 44 45 // Limite et compteur pour "Site description & context" 46 const SITE_DESCRIPTION_MAX = 500; 47 const siteDescriptionTextarea = document.getElementById("siteDescription"); 48 const siteDescriptionCounter = document.getElementById("siteDescription-counter"); 49 50 function updateSiteDescriptionCounter() { 51 if (!siteDescriptionTextarea || !siteDescriptionCounter) return; 52 let value = siteDescriptionTextarea.value || ""; 53 if (value.length > SITE_DESCRIPTION_MAX) { 54 value = value.slice(0, SITE_DESCRIPTION_MAX); 55 siteDescriptionTextarea.value = value; 56 } 57 siteDescriptionCounter.textContent = `${value.length}/${SITE_DESCRIPTION_MAX}`; 58 } 59 60 if (siteDescriptionTextarea && siteDescriptionCounter) { 61 siteDescriptionTextarea.addEventListener("input", updateSiteDescriptionCounter); 62 // Initialiser l'affichage au chargement 63 updateSiteDescriptionCounter(); 43 64 } 44 65 … … 94 115 document.getElementById("secondaryColor").value = secondaryColor; 95 116 document.getElementById("siteName").value = siteName; 96 document.getElementById("siteDescription").value = siteDescription; 117 const siteDescriptionEl = document.getElementById("siteDescription"); 118 if (siteDescriptionEl) { 119 siteDescriptionEl.value = siteDescription; 120 // Mettre à jour le compteur si déjà chargé 121 if (typeof updateSiteDescriptionCounter === "function") { 122 updateSiteDescriptionCounter(); 123 } 124 } 97 125 98 126 if (designStyle) { -
ai-builder/tags/2.4.7/readme.txt
r3443924 r3453884 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 2.4. 67 Stable tag: 2.4.7 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html -
ai-builder/trunk/admin/pages/settings.php
r3408247 r3453884 46 46 <th scope="row"><label for="siteDescription">Site description & context</label></th> 47 47 <td> 48 <textarea name="siteDescription" id="siteDescription" class="large-text" rows="4" 48 <textarea name="siteDescription" id="siteDescription" class="large-text" rows="4" maxlength="500" 49 49 placeholder="Describe your site and add any additional context that will help AI generate better content"></textarea> 50 <p id="siteDescription-counter" class="description" style="margin-top:4px;margin-bottom:4px;">0/500</p> 50 51 <p class="description">Start with your site's description, then add any relevant information about your business, target audience, or specific requirements.</p> 51 52 </td> … … 111 112 </tbody> 112 113 </table> 114 <div id="aibui-settings-toast" style="display:none;"></div> 113 115 114 116 <p class="submit"> 115 <button type="submit" class="button button-primary ">Save Settings</button>117 <button type="submit" class="button button-primary button-center">Save Settings</button> 116 118 </p> 117 119 </form> 118 120 119 <div id="aibui-settings-toast" style="display:none;"></div>120 121 </div> -
ai-builder/trunk/aibui-builder.php
r3443924 r3453884 4 4 * Plugin URI: https://website-ai-builder.com/ 5 5 * Description: This plugin is used to build your website with AI. 6 * Version: 2.4. 66 * Version: 2.4.7 7 7 * Author: enkic 8 8 * Author URI: https://enkicorbin.fr/ … … 18 18 19 19 // Définir la version du plugin 20 define('AIBUI_VERSION', '2.4. 6');20 define('AIBUI_VERSION', '2.4.7'); 21 21 22 22 /** … … 540 540 } 541 541 542 $current_screen = get_current_screen(); 542 543 // Charger les styles et scripts pour la page account du plugin AI Builder 543 $current_screen = get_current_screen();544 544 if ($current_screen && strpos($current_screen->id, 'aibui-assistant') !== false) { 545 545 wp_enqueue_style( … … 755 755 ) 756 756 ); 757 } 758 759 // Bandeau de review : uniquement sur les pages admin du plugin 760 if ($current_screen) { 761 $screen_id = $current_screen->id; 762 $is_plugin_screen = 763 strpos($screen_id, 'aibui-assistant') !== false || 764 strpos($screen_id, 'aibui-credits') !== false || 765 strpos($screen_id, 'aibui-tuto') !== false || 766 strpos($screen_id, 'aibui-multi-page') !== false || 767 strpos($screen_id, 'aibui-agent-chat') !== false || 768 strpos($screen_id, 'aibui-translation-settings') !== false || 769 strpos($screen_id, 'aibui-settings') !== false; 770 771 if ($is_plugin_screen) { 772 // S'assurer que config.js est chargé 773 wp_enqueue_script( 774 'ai-builder-config', 775 plugin_dir_url(__FILE__) . 'config.js', 776 [], 777 AIBUI_VERSION, 778 true 779 ); 780 wp_enqueue_script( 781 'ai-builder-review-banner', 782 plugin_dir_url(__FILE__) . 'assets/js/review-banner.js', 783 ['ai-builder-config'], 784 AIBUI_VERSION, 785 true 786 ); 787 wp_localize_script( 788 'ai-builder-review-banner', 789 'aiBuilderReviewVars', 790 array( 791 'ajaxurl' => admin_url('admin-ajax.php'), 792 'nonce' => wp_create_nonce('aibui_nonce'), 793 'reviewUrl' => 'https://wordpress.org/support/plugin/ai-builder/reviews/#new-post', 794 ) 795 ); 796 } 757 797 } 758 798 -
ai-builder/trunk/assets/css/settings.css
r3397412 r3453884 15 15 } 16 16 17 .ai-builder-settings >p {17 .ai-builder-settings>p { 18 18 margin-top: 0; 19 19 margin-bottom: 28px; … … 113 113 } 114 114 115 .ai-builder-settings .submit { 116 margin-top: 32px; 117 text-align: center; 118 } 119 115 120 .ai-builder-settings .submit .button-primary:hover { 116 121 transform: translateY(-1px); … … 154 159 } 155 160 } 156 -
ai-builder/trunk/assets/js/chat-widget.js
r3443924 r3453884 59 59 "beforeend", 60 60 ` 61 <div id="chat-toggle"> 🤖AI Builder</div>61 <div id="chat-toggle">AI Builder</div> 62 62 <div id="chat-box"> 63 63 <div id="chat-header"> … … 77 77 <div id="chat-messages"></div> 78 78 <div id="chat-input"> 79 <textarea placeholder="Create a modern pricing page with 3 plans and call-to-action buttons..." rows="2"></textarea> 79 <textarea placeholder="Create a modern pricing page with 3 plans and call-to-action buttons..." rows="2" maxlength="2000"></textarea> 80 <div id="chat-char-counter">0/2000</div> 80 81 <button>Generate</button> 81 82 <button id="chat-undo" style="display: none;">Undo</button> … … 131 132 const input = document.querySelector("#chat-input textarea"); 132 133 const sendBtn = document.querySelector("#chat-input button"); 134 const charCounter = document.getElementById("chat-char-counter"); 133 135 const undoBtn = document.getElementById("chat-undo"); 134 136 let chatHistory = []; 137 138 const MAX_CHAT_CHARS = 2000; 139 140 // Met à jour le compteur de caractères du chat 141 function updateChatCharCounter() { 142 if (!input || !charCounter) return; 143 const currentLength = input.value.length; 144 // Sécurité : tronquer si, pour une raison quelconque, on dépasse la limite 145 if (currentLength > MAX_CHAT_CHARS) { 146 input.value = input.value.slice(0, MAX_CHAT_CHARS); 147 } 148 charCounter.textContent = `${input.value.length}/${MAX_CHAT_CHARS}`; 149 } 150 151 if (input) { 152 input.addEventListener("input", updateChatCharCounter); 153 // Initialiser l'affichage du compteur 154 updateChatCharCounter(); 155 } 156 157 // Indicateur de saisie de l'IA (3 points animés) 158 function createTypingIndicator() { 159 if (!messages) return null; 160 let indicator = document.getElementById("chat-typing-indicator"); 161 if (!indicator) { 162 indicator = document.createElement("div"); 163 indicator.id = "chat-typing-indicator"; 164 indicator.innerHTML = ` 165 <span class="typing-dot"></span> 166 <span class="typing-dot"></span> 167 <span class="typing-dot"></span> 168 `; 169 } 170 return indicator; 171 } 172 173 function showTypingIndicator() { 174 if (!messages) return; 175 const indicator = createTypingIndicator(); 176 if (!indicator) return; 177 if (!messages.contains(indicator)) { 178 messages.appendChild(indicator); 179 } 180 } 181 182 function hideTypingIndicator() { 183 const indicator = document.getElementById("chat-typing-indicator"); 184 if (indicator && indicator.parentNode) { 185 indicator.parentNode.removeChild(indicator); 186 } 187 } 135 188 136 189 function getChatStorageKey() { … … 292 345 if (!messages) return; 293 346 347 // Si un indicateur de saisie est présent, le garder toujours en bas 348 const typingIndicator = document.getElementById("chat-typing-indicator"); 349 if (typingIndicator && typingIndicator.parentNode === messages) { 350 messages.removeChild(typingIndicator); 351 } 352 294 353 const messageDiv = document.createElement("div"); 295 354 messageDiv.className = type === "assistant" ? "ai-message" : "user-message"; 296 355 297 356 if (type === "assistant") { 298 messageDiv.innerHTML = ` <strong>🤖</strong>${message}`;357 messageDiv.innerHTML = `${message}`; 299 358 } else { 300 messageDiv.innerHTML = ` <strong>👤</strong>${message}`;359 messageDiv.innerHTML = `${message}`; 301 360 } 302 361 303 362 messages.appendChild(messageDiv); 363 364 // Ré‑ajouter l'indicateur de saisie en bas si nécessaire 365 if (typingIndicator) { 366 messages.appendChild(typingIndicator); 367 } 304 368 messages.scrollTop = messages.scrollHeight; 305 369 … … 1197 1261 // 🔒 Désactiver le bouton + animation loading 1198 1262 sendBtn.disabled = true; 1199 sendBtn.classList.add("loading");1263 // sendBtn.classList.add("loading"); 1200 1264 sendBtn.textContent = "Generating..."; 1201 1265 … … 1205 1269 } 1206 1270 1271 // 👀 Afficher l'indicateur de saisie de l'IA 1272 if (typeof showTypingIndicator === "function") { 1273 showTypingIndicator(); 1274 } 1275 1207 1276 // Ajouter le message utilisateur à l'historique 1208 1277 addMessage(finalQuestion, "user"); 1209 1278 input.value = ""; 1279 // Réinitialiser le compteur après envoi 1280 if (typeof updateChatCharCounter === "function") { 1281 updateChatCharCounter(); 1282 } 1210 1283 messages.scrollTop = messages.scrollHeight; 1211 1284 … … 1352 1425 toggleBtn.classList.remove("generating"); 1353 1426 } 1427 1428 // 👀 Masquer l'indicateur de saisie de l'IA 1429 if (typeof hideTypingIndicator === "function") { 1430 hideTypingIndicator(); 1431 } 1354 1432 } 1355 1433 } … … 1367 1445 const cssStyles = document.createElement("style"); 1368 1446 cssStyles.textContent = ` 1447 /* Zone de saisie du chat */ 1448 #chat-input { 1449 display: flex; 1450 flex-direction: column; 1451 gap: 6px; 1452 } 1453 1454 #chat-input textarea { 1455 width: 100%; 1456 resize: vertical; 1457 } 1458 1459 #chat-char-counter { 1460 align-self: flex-end; 1461 font-size: 11px; 1462 color: #888; 1463 } 1464 1465 /* Indicateur de saisie de l'IA */ 1466 #chat-typing-indicator { 1467 display: inline-flex; 1468 align-items: center; 1469 gap: 4px; 1470 padding: 6px 10px; 1471 border-radius: 12px; 1472 background-color: #f1f3f5; 1473 color: #555; 1474 font-size: 12px; 1475 max-width: 80%; 1476 margin-top: 4px; 1477 } 1478 1479 #chat-typing-indicator .typing-dot { 1480 width: 6px; 1481 height: 6px; 1482 border-radius: 50%; 1483 background-color: #888; 1484 display: inline-block; 1485 animation: ai-typing-bounce 1s infinite ease-in-out; 1486 } 1487 1488 #chat-typing-indicator .typing-dot:nth-child(2) { 1489 animation-delay: 0.15s; 1490 } 1491 1492 #chat-typing-indicator .typing-dot:nth-child(3) { 1493 animation-delay: 0.3s; 1494 } 1495 1496 @keyframes ai-typing-bounce { 1497 0%, 60%, 100% { 1498 transform: translateY(0); 1499 opacity: 0.4; 1500 } 1501 30% { 1502 transform: translateY(-4px); 1503 opacity: 1; 1504 } 1505 } 1506 1369 1507 /* Header du chat avec bouton CSS intégré */ 1370 1508 #chat-header { -
ai-builder/trunk/assets/js/settings.js
r3408247 r3453884 41 41 toast.style.display = "none"; 42 42 }, 4000); 43 } 44 45 // Limite et compteur pour "Site description & context" 46 const SITE_DESCRIPTION_MAX = 500; 47 const siteDescriptionTextarea = document.getElementById("siteDescription"); 48 const siteDescriptionCounter = document.getElementById("siteDescription-counter"); 49 50 function updateSiteDescriptionCounter() { 51 if (!siteDescriptionTextarea || !siteDescriptionCounter) return; 52 let value = siteDescriptionTextarea.value || ""; 53 if (value.length > SITE_DESCRIPTION_MAX) { 54 value = value.slice(0, SITE_DESCRIPTION_MAX); 55 siteDescriptionTextarea.value = value; 56 } 57 siteDescriptionCounter.textContent = `${value.length}/${SITE_DESCRIPTION_MAX}`; 58 } 59 60 if (siteDescriptionTextarea && siteDescriptionCounter) { 61 siteDescriptionTextarea.addEventListener("input", updateSiteDescriptionCounter); 62 // Initialiser l'affichage au chargement 63 updateSiteDescriptionCounter(); 43 64 } 44 65 … … 94 115 document.getElementById("secondaryColor").value = secondaryColor; 95 116 document.getElementById("siteName").value = siteName; 96 document.getElementById("siteDescription").value = siteDescription; 117 const siteDescriptionEl = document.getElementById("siteDescription"); 118 if (siteDescriptionEl) { 119 siteDescriptionEl.value = siteDescription; 120 // Mettre à jour le compteur si déjà chargé 121 if (typeof updateSiteDescriptionCounter === "function") { 122 updateSiteDescriptionCounter(); 123 } 124 } 97 125 98 126 if (designStyle) { -
ai-builder/trunk/readme.txt
r3443924 r3453884 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 2.4. 67 Stable tag: 2.4.7 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html
Note: See TracChangeset
for help on using the changeset viewer.