Chatbot Material

🏷️ Extraits & Composants HTML 📅 07/04/2026 16:00:00 👤 Mezgani Said
Material Chatbot List Material Design Template Html Integration List Ai

Chatbot Material optimisées pour la visualisation et l'interaction. Composants modernes et responsive.

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8" />
  <meta name="copyright" content="MEZGANI Said" />
  <meta name="author" content="AngularForAll" />
  <meta name="robots" content="noindex, nofollow" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Snippet Chatboot Material 2026 23040040 | AngularForAll</title>
<!-- Material Design 3 Web Components -->
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" rel="stylesheet" />
  <link rel="stylesheet" href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css">
  
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      font-family: 'Roboto', sans-serif;
      background: #f5f5f5;
      min-height: 100vh;
      margin: 0;
      padding: 0;
    }

    /* Variables Material Design 3 */
    :root {
      --md-sys-color-primary: #6750A4;
      --md-sys-color-on-primary: #FFFFFF;
      --md-sys-color-primary-container: #EADDFF;
      --md-sys-color-on-primary-container: #21005D;
      --md-sys-color-surface: #FEF7FF;
      --md-sys-color-surface-variant: #E7E0EC;
      --md-sys-color-on-surface: #1D1B20;
      --md-sys-color-on-surface-variant: #49454F;
      --md-sys-color-outline: #79747E;
      --md-sys-color-secondary-container: #E8DEF8;
      --md-sys-color-on-secondary-container: #1D192B;
      --md-elevation-2: 0px 3px 3px -2px rgba(0,0,0,0.2), 0px 3px 4px 0px rgba(0,0,0,0.14), 0px 1px 8px 0px rgba(0,0,0,0.12);
      --md-elevation-3: 0px 3px 5px -1px rgba(0,0,0,0.2), 0px 6px 10px 0px rgba(0,0,0,0.14), 0px 1px 18px 0px rgba(0,0,0,0.12);
      --md-elevation-4: 0px 5px 5px -3px rgba(0,0,0,0.2), 0px 8px 10px 1px rgba(0,0,0,0.14), 0px 3px 14px 2px rgba(0,0,0,0.12);
    }

    /* Container du widget */
    .chatbot-widget {
      position: fixed;
      bottom: 24px;
      right: 24px;
      z-index: 1000;
      display: flex;
      flex-direction: column;
      align-items: flex-end;
    }

    /* Fenêtre de chat */
    .chat-window {
      width: 360px;
      max-width: calc(100vw - 32px);
      background: var(--md-sys-color-surface);
      border-radius: 28px;
      box-shadow: var(--md-elevation-3);
      margin-bottom: 16px;
      overflow: hidden;
      display: none;
      flex-direction: column;
      border: 1px solid var(--md-sys-color-outline);
      animation: slideIn 0.3s cubic-bezier(0.2, 0, 0, 1);
    }

    .chat-window.active {
      display: flex;
    }

    @keyframes slideIn {
      from {
        opacity: 0;
        transform: translateY(20px) scale(0.95);
      }
      to {
        opacity: 1;
        transform: translateY(0) scale(1);
      }
    }

    /* Header Material */
    .chat-header {
      background: var(--md-sys-color-primary);
      color: var(--md-sys-color-on-primary);
      padding: 16px 20px;
      display: flex;
      align-items: center;
      justify-content: space-between;
    }

    .chat-header-left {
      display: flex;
      align-items: center;
      gap: 12px;
    }

    .chat-avatar {
      width: 40px;
      height: 40px;
      background: var(--md-sys-color-primary-container);
      border-radius: 20px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: var(--md-sys-color-on-primary-container);
    }

    .chat-avatar .material-symbols-outlined {
      font-size: 24px;
      font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
    }

    .chat-title h3 {
      font-size: 16px;
      font-weight: 500;
      margin: 0 0 2px 0;
      letter-spacing: 0.15px;
    }

    .chat-title .status {
      font-size: 12px;
      opacity: 0.9;
      display: flex;
      align-items: center;
      gap: 4px;
    }

    .status-dot {
      width: 8px;
      height: 8px;
      background: #4CAF50;
      border-radius: 4px;
      display: inline-block;
    }

    .close-btn {
      width: 40px;
      height: 40px;
      border-radius: 20px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      transition: background 0.2s;
      border: none;
      background: transparent;
      color: var(--md-sys-color-on-primary);
    }

    .close-btn:hover {
      background: rgba(255, 255, 255, 0.08);
    }

    .close-btn .material-symbols-outlined {
      font-size: 20px;
      font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
    }

    /* Body des messages */
    .chat-body {
      height: 380px;
      overflow-y: auto;
      padding: 16px;
      background: var(--md-sys-color-surface);
      display: flex;
      flex-direction: column;
      gap: 12px;
    }

    .chat-body::-webkit-scrollbar {
      width: 4px;
    }

    .chat-body::-webkit-scrollbar-track {
      background: transparent;
    }

    .chat-body::-webkit-scrollbar-thumb {
      background: var(--md-sys-color-outline);
      border-radius: 4px;
    }

    /* Messages */
    .message {
      display: flex;
      max-width: 85%;
      animation: messageAppear 0.3s cubic-bezier(0.2, 0, 0, 1);
    }

    @keyframes messageAppear {
      from {
        opacity: 0;
        transform: translateY(8px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    .message.bot {
      align-self: flex-start;
    }

    .message.user {
      align-self: flex-end;
    }

    .message-content {
      padding: 12px 16px;
      border-radius: 20px;
      font-size: 14px;
      line-height: 1.5;
      letter-spacing: 0.25px;
      word-break: break-word;
    }

    .bot .message-content {
      background: var(--md-sys-color-surface-variant);
      color: var(--md-sys-color-on-surface-variant);
      border-bottom-left-radius: 4px;
    }

    .user .message-content {
      background: var(--md-sys-color-primary);
      color: var(--md-sys-color-on-primary);
      border-bottom-right-radius: 4px;
    }

    /* Indicateur de frappe */
    .typing-indicator {
      display: flex;
      gap: 4px;
      padding: 12px 16px;
      background: var(--md-sys-color-surface-variant);
      border-radius: 20px;
      border-bottom-left-radius: 4px;
      width: fit-content;
    }

    .typing-dot {
      width: 8px;
      height: 8px;
      background: var(--md-sys-color-on-surface-variant);
      border-radius: 4px;
      animation: typingBounce 1.4s infinite ease-in-out;
      opacity: 0.6;
    }

    .typing-dot:nth-child(2) { animation-delay: 0.2s; }
    .typing-dot:nth-child(3) { animation-delay: 0.4s; }

    @keyframes typingBounce {
      0%, 60%, 100% { transform: translateY(0); }
      30% { transform: translateY(-6px); }
    }

    /* Footer avec input */
    .chat-footer {
      padding: 12px 16px;
      background: var(--md-sys-color-surface);
      border-top: 1px solid var(--md-sys-color-outline);
      display: flex;
      align-items: center;
      gap: 12px;
    }

    .chat-input-wrapper {
      flex: 1;
      position: relative;
    }

    .chat-input {
      width: 100%;
      padding: 12px 16px;
      border: 1px solid var(--md-sys-color-outline);
      border-radius: 24px;
      font-size: 14px;
      font-family: 'Roboto', sans-serif;
      background: var(--md-sys-color-surface);
      color: var(--md-sys-color-on-surface);
      outline: none;
      transition: border-color 0.2s, box-shadow 0.2s;
    }

    .chat-input:focus {
      border-color: var(--md-sys-color-primary);
      box-shadow: 0 0 0 2px rgba(103, 80, 164, 0.1);
    }

    .chat-input::placeholder {
      color: var(--md-sys-color-on-surface-variant);
      opacity: 0.6;
    }

    .send-btn {
      width: 48px;
      height: 48px;
      border-radius: 24px;
      background: var(--md-sys-color-primary-container);
      border: none;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      transition: all 0.2s cubic-bezier(0.2, 0, 0, 1);
      color: var(--md-sys-color-on-primary-container);
    }

    .send-btn:hover {
      background: var(--md-sys-color-primary);
      color: var(--md-sys-color-on-primary);
      box-shadow: var(--md-elevation-2);
    }

    .send-btn .material-symbols-outlined {
      font-size: 20px;
      font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
    }

    /* FAB - Floating Action Button */
    .fab {
      width: 56px;
      height: 56px;
      border-radius: 16px;
      background: var(--md-sys-color-primary-container);
      border: none;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      box-shadow: var(--md-elevation-3);
      transition: all 0.2s cubic-bezier(0.2, 0, 0, 1);
      color: var(--md-sys-color-on-primary-container);
      position: relative;
    }

    .fab:hover {
      box-shadow: var(--md-elevation-4);
      background: var(--md-sys-color-primary);
      color: var(--md-sys-color-on-primary);
    }

    .fab .material-symbols-outlined {
      font-size: 24px;
      font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
      transition: transform 0.2s;
    }

    /* Badge non lu */
    .unread-badge {
      position: absolute;
      top: -4px;
      right: -4px;
      background: #B3261E;
      color: white;
      border-radius: 12px;
      padding: 2px 6px;
      font-size: 11px;
      font-weight: 500;
      border: 2px solid var(--md-sys-color-surface);
      min-width: 18px;
      text-align: center;
    }

    /* Responsive */
    @media (max-width: 480px) {
      .chat-window {
        width: calc(100vw - 32px);
      }
      
      .chatbot-widget {
        bottom: 16px;
        right: 16px;
      }
    }

    /* Contenu démo */
    .demo-content {
      max-width: 800px;
      margin: 60px auto;
      padding: 40px 20px;
      text-align: center;
    }

    .demo-content h1 {
      font-size: 48px;
      font-weight: 400;
      color: var(--md-sys-color-on-surface);
      margin-bottom: 16px;
    }

    .demo-content p {
      font-size: 18px;
      color: var(--md-sys-color-on-surface-variant);
      margin-bottom: 40px;
    }

    .material-card {
      background: var(--md-sys-color-surface);
      border-radius: 28px;
      padding: 40px;
      box-shadow: var(--md-elevation-2);
      border: 1px solid var(--md-sys-color-outline);
    }

    .material-card .material-symbols-outlined {
      font-size: 64px;
      color: var(--md-sys-color-primary);
      font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 48;
      margin-bottom: 16px;
    }
  </style>
</head>
<body>

<!-- Contenu de démonstration -->
<div class="demo-content">
  <h1>Assistant Virtuel</h1>
  <p>Cliquez sur le FAB en bas à droite pour discuter avec notre assistant</p>
  
  <div class="material-card">
    <span class="material-symbols-outlined">chat</span>
    <h2 style="font-weight: 400; margin-bottom: 12px; color: var(--md-sys-color-on-surface);">Support Material Design</h2>
    <p style="color: var(--md-sys-color-on-surface-variant);">Posez une question sur nos services, les tarifs ou le support.</p>
  </div>
</div>

<!-- ========== WIDGET CHATBOT MATERIAL DESIGN ========== -->
<div class="chatbot-widget">
  
  <!-- Fenêtre de chat -->
  <div class="chat-window" id="chatWindow">
    <!-- Header -->
    <div class="chat-header">
      <div class="chat-header-left">
        <div class="chat-avatar">
          <span class="material-symbols-outlined">smart_toy</span>
        </div>
        <div class="chat-title">
          <h3>Assistant Material</h3>
          <div class="status">
            <span class="status-dot"></span>
            <span>En ligne</span>
          </div>
        </div>
      </div>
      <button class="close-btn" id="closeChatBtn">
        <span class="material-symbols-outlined">close</span>
      </button>
    </div>

    <!-- Body (messages) -->
    <div class="chat-body" id="chatBody">
      <div class="message bot">
        <div class="message-content">
          👋 Bonjour ! Je suis l'assistant Material. Comment puis-je vous aider aujourd'hui ?
        </div>
      </div>
    </div>

    <!-- Footer avec input -->
    <div class="chat-footer">
      <div class="chat-input-wrapper">
        <input type="text" class="chat-input" id="chatInput" placeholder="Votre message..." autocomplete="off">
      </div>
      <button class="send-btn" id="sendMessageBtn">
        <span class="material-symbols-outlined">send</span>
      </button>
    </div>
  </div>

  <!-- FAB Toggle -->
  <button class="fab" id="toggleChatBtn">
    <span class="material-symbols-outlined" id="fabIcon">chat</span>
  </button>
</div>

<script>
  (function() {
    'use strict';

    // Éléments DOM
    const chatWindow = document.getElementById('chatWindow');
    const toggleBtn = document.getElementById('toggleChatBtn');
    const closeBtn = document.getElementById('closeChatBtn');
    const chatBody = document.getElementById('chatBody');
    const chatInput = document.getElementById('chatInput');
    const sendBtn = document.getElementById('sendMessageBtn');
    const fabIcon = document.getElementById('fabIcon');

    // Fonctions utilitaires
    function openChat() {
      chatWindow.classList.add('active');
      fabIcon.textContent = 'close';
      setTimeout(() => chatInput.focus(), 100);
    }

    function closeChat() {
      chatWindow.classList.remove('active');
      fabIcon.textContent = 'chat';
    }

    function toggleChat() {
      chatWindow.classList.contains('active') ? closeChat() : openChat();
    }

    function scrollToBottom() {
      chatBody.scrollTop = chatBody.scrollHeight;
    }

    function escapeHtml(text) {
      const div = document.createElement('div');
      div.textContent = text;
      return div.innerHTML;
    }

    // Ajouter message utilisateur
    function addUserMessage(text) {
      const msgDiv = document.createElement('div');
      msgDiv.className = 'message user';
      msgDiv.innerHTML = `<div class="message-content">${escapeHtml(text)}</div>`;
      chatBody.appendChild(msgDiv);
      scrollToBottom();
    }

    // Ajouter message bot
    function addBotMessage(text) {
      const msgDiv = document.createElement('div');
      msgDiv.className = 'message bot';
      msgDiv.innerHTML = `<div class="message-content">${escapeHtml(text)}</div>`;
      chatBody.appendChild(msgDiv);
      scrollToBottom();
    }

    // Indicateur de frappe
    function addTypingIndicator() {
      const typingDiv = document.createElement('div');
      typingDiv.className = 'message bot';
      typingDiv.id = 'typingIndicator';
      typingDiv.innerHTML = `
        <div class="typing-indicator">
          <span class="typing-dot"></span>
          <span class="typing-dot"></span>
          <span class="typing-dot"></span>
        </div>
      `;
      chatBody.appendChild(typingDiv);
      scrollToBottom();
      return typingDiv;
    }

    function removeTypingIndicator() {
      const el = document.getElementById('typingIndicator');
      if (el) el.remove();
    }

    // Logique de réponse du bot
    function getBotResponse(userMsg) {
      const msg = userMsg.toLowerCase().trim();
      
      if (msg.includes('bonjour') || msg.includes('salut') || msg.includes('hello')) 
        return "Bonjour ! 😊 Comment puis-je vous aider aujourd'hui ?";
      
      if (msg.includes('prix') || msg.includes('tarif') || msg.includes('coût')) 
        return "Nos tarifs sont compétitifs. Le forfait de base commence à 29€/mois. Souhaitez-vous plus d'informations ?";
      
      if (msg.includes('horaire') || msg.includes('ouverture')) 
        return "Notre équipe est disponible du lundi au vendredi, de 9h à 18h. Le support par chat est ouvert 24/7.";
      
      if (msg.includes('contact') || msg.includes('téléphone') || msg.includes('email')) 
        return "📞 Contactez-nous au +33 1 23 45 67 89 ou par email à support@material-assistant.fr";
      
      if (msg.includes('merci')) 
        return "Avec plaisir ! 🌟 N'hésitez pas si vous avez d'autres questions.";
      
      if (msg.includes('aide') || msg.includes('help')) 
        return "Je peux vous aider sur : tarifs, horaires, contact, ou support technique. Que souhaitez-vous savoir ?";
      
      if (msg.includes('tech') || msg.includes('bug') || msg.includes('problème')) 
        return "Je comprends votre problème technique. Pouvez-vous me donner plus de détails pour que je puisse vous aider efficacement ?";
      
      if (msg.includes('material') || msg.includes('design')) 
        return "Material Design est un système de design créé par Google. Notre interface suit les principes Material 3 !";
      
      return "Je suis là pour vous aider ! Vous pouvez me parler de tarifs, horaires, support technique ou contact. Que voulez-vous savoir ? 😊";
    }

    function simulateBotReply(userText) {
      const typingEl = addTypingIndicator();
      const delay = Math.floor(Math.random() * 900) + 800;
      
      setTimeout(() => {
        removeTypingIndicator();
        addBotMessage(getBotResponse(userText));
      }, delay);
    }

    function handleSendMessage() {
      const text = chatInput.value.trim();
      if (!text) return;
      
      addUserMessage(text);
      chatInput.value = '';
      simulateBotReply(text);
    }

    // Événements
    toggleBtn.addEventListener('click', toggleChat);
    closeBtn.addEventListener('click', closeChat);
    
    sendBtn.addEventListener('click', handleSendMessage);
    
    chatInput.addEventListener('keypress', (e) => {
      if (e.key === 'Enter') {
        e.preventDefault();
        handleSendMessage();
      }
    });

    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && chatWindow.classList.contains('active')) {
        closeChat();
      }
    });

    // Ripple effect Material Design sur les boutons
    function createRipple(event) {
      const button = event.currentTarget;
      const ripple = document.createElement('span');
      const diameter = Math.max(button.clientWidth, button.clientHeight);
      const radius = diameter / 2;
      
      ripple.style.width = ripple.style.height = `${diameter}px`;
      ripple.style.left = `${event.clientX - button.offsetLeft - radius}px`;
      ripple.style.top = `${event.clientY - button.offsetTop - radius}px`;
      ripple.classList.add('ripple');
      
      const existingRipple = button.querySelector('.ripple');
      if (existingRipple) existingRipple.remove();
      
      button.appendChild(ripple);
    }

    // Style pour l'effet ripple
    const style = document.createElement('style');
    style.textContent = `
      .fab, .close-btn, .send-btn {
        position: relative;
        overflow: hidden;
      }
      .ripple {
        position: absolute;
        border-radius: 50%;
        background: rgba(255, 255, 255, 0.3);
        transform: scale(0);
        animation: ripple-animation 0.6s ease-out;
        pointer-events: none;
      }
      @keyframes ripple-animation {
        to {
          transform: scale(4);
          opacity: 0;
        }
      }
    `;
    document.head.appendChild(style);

    // Ajouter l'effet ripple
    [toggleBtn, closeBtn, sendBtn].forEach(btn => {
      btn.addEventListener('click', createRipple);
    });

  })();
</script>

</body>
</html>

Ouvrir cet aperçu dans un nouvel onglet du navigateur

🔗 Ouvrir dans le navigateur