WhatsApp Web - Bootstrap 5

🏷️ Extraits de code HTML 📅 10/04/2026 22:00:00 👤 Mezgani said
Bootstrap Bootstrap5 Whatsapp Chat Messagerie Html

Template Bootstrap 5 de messagerie type WhatsApp Web avec panneau de contacts et conversation principale.

<!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>Template Whatsapp Bootstrap 5 01 | AngularForAll</title>
<!-- Bootstrap 5 CSS -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
  <!-- Bootstrap Icons -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
  
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: 'Segoe UI', 'Helvetica Neue', sans-serif;
      background: #0b141a;
      height: 100vh;
      overflow: hidden;
    }

    /* Structure principale */
    .app-container {
      display: flex;
      height: 100vh;
      background: #0b141a;
    }

    /* ===== SIDEBAR GAUCHE ===== */
    .sidebar {
      width: 380px;
      background: #111b21;
      border-right: 1px solid #222d34;
      display: flex;
      flex-direction: column;
    }

    /* Header sidebar */
    .sidebar-header {
      background: #202c33;
      padding: 10px 16px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      height: 59px;
    }

    .user-avatar {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      background: #6b7c85;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-weight: 500;
      cursor: pointer;
      transition: 0.2s;
    }

    .user-avatar:hover {
      opacity: 0.8;
    }

    .header-icons {
      display: flex;
      gap: 20px;
    }

    .header-icons i {
      color: #aebac1;
      font-size: 1.3rem;
      cursor: pointer;
      transition: 0.2s;
    }

    .header-icons i:hover {
      color: #e9edef;
    }

    /* Barre de recherche */
    .search-container {
      padding: 8px 12px;
      background: #111b21;
    }

    .search-box {
      background: #202c33;
      border-radius: 8px;
      padding: 8px 16px;
      display: flex;
      align-items: center;
      gap: 15px;
    }

    .search-box i {
      color: #8696a0;
      font-size: 0.9rem;
    }

    .search-box input {
      background: transparent;
      border: none;
      color: #e9edef;
      outline: none;
      width: 100%;
      font-size: 0.9rem;
    }

    .search-box input::placeholder {
      color: #8696a0;
    }

    /* Liste des conversations */
    .chat-list {
      flex: 1;
      overflow-y: auto;
      background: #111b21;
    }

    .chat-item {
      display: flex;
      align-items: center;
      padding: 12px 16px;
      cursor: pointer;
      border-bottom: 1px solid #222d34;
      transition: background 0.2s;
    }

    .chat-item:hover {
      background: #202c33;
    }

    .chat-item.active {
      background: #2a3942;
    }

    .chat-avatar {
      width: 49px;
      height: 49px;
      border-radius: 50%;
      background: #6b7c85;
      margin-right: 15px;
      flex-shrink: 0;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-weight: 500;
    }

    .chat-info {
      flex: 1;
      min-width: 0;
    }

    .chat-header {
      display: flex;
      justify-content: space-between;
      margin-bottom: 4px;
    }

    .chat-name {
      color: #e9edef;
      font-weight: 500;
      font-size: 1rem;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .chat-time {
      color: #8696a0;
      font-size: 0.75rem;
    }

    .chat-last-message {
      display: flex;
      justify-content: space-between;
    }

    .last-message {
      color: #8696a0;
      font-size: 0.85rem;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      max-width: 200px;
    }

    .unread-badge {
      background: #00a884;
      color: white;
      border-radius: 50%;
      padding: 2px 6px;
      font-size: 0.7rem;
      font-weight: 600;
      min-width: 20px;
      text-align: center;
    }

    /* ===== ZONE PRINCIPALE (CHAT) ===== */
    .chat-area {
      flex: 1;
      display: flex;
      flex-direction: column;
      background: #0b141a;
      position: relative;
    }

    /* Fond WhatsApp par défaut */
    .chat-background {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect width="100" height="100" fill="%230b141a"/><path d="M0 50 L100 50" stroke="%231b2a33" stroke-width="0.5"/><path d="M50 0 L50 100" stroke="%231b2a33" stroke-width="0.5"/></svg>');
      opacity: 0.3;
      z-index: 0;
    }

    /* Header du chat */
    .chat-header-bar {
      background: #202c33;
      padding: 10px 16px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      height: 59px;
      border-left: 1px solid #222d34;
      position: relative;
      z-index: 1;
    }

    .chat-contact-info {
      display: flex;
      align-items: center;
      gap: 15px;
    }

    .contact-avatar {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      background: #6b7c85;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-weight: 500;
    }

    .contact-details h6 {
      color: #e9edef;
      margin: 0;
      font-size: 1rem;
    }

    .contact-details small {
      color: #8696a0;
      font-size: 0.8rem;
    }

    .chat-actions {
      display: flex;
      gap: 25px;
    }

    .chat-actions i {
      color: #aebac1;
      font-size: 1.3rem;
      cursor: pointer;
      transition: 0.2s;
    }

    .chat-actions i:hover {
      color: #e9edef;
    }

    /* Zone des messages */
    .messages-container {
      flex: 1;
      overflow-y: auto;
      padding: 20px 60px;
      position: relative;
      z-index: 1;
      display: flex;
      flex-direction: column;
    }

    .message {
      max-width: 65%;
      margin-bottom: 8px;
      display: flex;
    }

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

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

    .message-bubble {
      padding: 8px 12px;
      border-radius: 8px;
      position: relative;
      word-wrap: break-word;
    }

    .message.sent .message-bubble {
      background: #005c4b;
      color: #e9edef;
      border-top-right-radius: 0;
    }

    .message.received .message-bubble {
      background: #202c33;
      color: #e9edef;
      border-top-left-radius: 0;
    }

    .message-time {
      font-size: 0.7rem;
      color: #8696a0;
      margin-top: 4px;
      text-align: right;
      display: flex;
      align-items: center;
      justify-content: flex-end;
      gap: 4px;
    }

    .message-status {
      color: #53bdeb;
      font-size: 0.9rem;
    }

    /* Zone de saisie */
    .message-input-container {
      background: #202c33;
      padding: 10px 16px;
      display: flex;
      align-items: center;
      gap: 15px;
      position: relative;
      z-index: 1;
    }

    .input-actions-left {
      display: flex;
      gap: 15px;
    }

    .input-actions-left i {
      color: #aebac1;
      font-size: 1.5rem;
      cursor: pointer;
      transition: 0.2s;
    }

    .input-actions-left i:hover {
      color: #e9edef;
    }

    .message-input {
      flex: 1;
      background: #2a3942;
      border: none;
      border-radius: 8px;
      padding: 12px 16px;
      color: #e9edef;
      outline: none;
      font-size: 0.95rem;
    }

    .message-input::placeholder {
      color: #8696a0;
    }

    .input-actions-right {
      display: flex;
      gap: 15px;
    }

    .input-actions-right i {
      color: #aebac1;
      font-size: 1.5rem;
      cursor: pointer;
      transition: 0.2s;
    }

    .input-actions-right i:hover {
      color: #e9edef;
    }

    /* Écran de bienvenue */
    .welcome-screen {
      flex: 1;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      position: relative;
      z-index: 1;
      background: #0b141a;
    }

    .welcome-logo {
      width: 320px;
      margin-bottom: 30px;
    }

    .welcome-screen h2 {
      color: #e9edef;
      font-weight: 300;
      margin-bottom: 15px;
    }

    .welcome-screen p {
      color: #8696a0;
      text-align: center;
      max-width: 500px;
      font-size: 0.9rem;
    }

    .encryption-info {
      position: absolute;
      bottom: 30px;
      color: #667781;
      font-size: 0.85rem;
      display: flex;
      align-items: center;
      gap: 8px;
    }

    /* Scrollbar personnalisée */
    ::-webkit-scrollbar {
      width: 6px;
    }

    ::-webkit-scrollbar-track {
      background: #111b21;
    }

    ::-webkit-scrollbar-thumb {
      background: #374248;
      border-radius: 3px;
    }

    /* Responsive */
    @media (max-width: 768px) {
      .sidebar {
        width: 100%;
      }
      .chat-area {
        display: none;
      }
      .chat-area.active {
        display: flex;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 10;
      }
    }
  </style>
</head>
<body>

<div class="app-container">
  
  <!-- ===== SIDEBAR (Liste des conversations) ===== -->
  <div class="sidebar">
    <!-- Header -->
    <div class="sidebar-header">
      <div class="user-avatar" onclick="showUserProfile()">
        <i class="bi bi-person-fill"></i>
      </div>
      <div class="header-icons">
        <i class="bi bi-people-fill" title="Communautés"></i>
        <i class="bi bi-chat-left-text-fill" title="Statut"></i>
        <i class="bi bi-three-dots-vertical" title="Menu"></i>
      </div>
    </div>

    <!-- Barre de recherche -->
    <div class="search-container">
      <div class="search-box">
        <i class="bi bi-search"></i>
        <input type="text" placeholder="Rechercher ou démarrer une nouvelle discussion" id="searchInput">
      </div>
    </div>

    <!-- Liste des conversations -->
    <div class="chat-list" id="chatList">
      <!-- Les conversations seront injectées ici par JS -->
    </div>
  </div>

  <!-- ===== ZONE PRINCIPALE (Chat) ===== -->
  <div class="chat-area" id="chatArea">
    <div class="chat-background"></div>
    
    <!-- Écran de bienvenue (par défaut) -->
    <div class="welcome-screen" id="welcomeScreen">
      <div class="welcome-logo">
        <img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='45' fill='%2300a884'/%3E%3Cpath d='M35 40 L65 40 L50 60 Z' fill='white'/%3E%3C/svg%3E" alt="WhatsApp" style="width: 100%;">
      </div>
      <h2>WhatsApp Web</h2>
      <p>Envoyez et recevez des messages sans avoir à garder votre téléphone connecté.<br>Utilisez WhatsApp sur jusqu'à 4 appareils liés et 1 téléphone simultanément.</p>
      <div class="encryption-info">
        <i class="bi bi-lock-fill"></i>
        <span>Chiffrement de bout en bout</span>
      </div>
    </div>

    <!-- Zone de chat active (cachée par défaut) -->
    <div id="activeChat" style="display: none; flex: 1; flex-direction: column;">
      <!-- Header du chat -->
      <div class="chat-header-bar">
        <div class="chat-contact-info">
          <div class="contact-avatar" id="contactAvatar">
            <i class="bi bi-person-fill"></i>
          </div>
          <div class="contact-details">
            <h6 id="contactName">Contact</h6>
            <small id="contactStatus">en ligne</small>
          </div>
        </div>
        <div class="chat-actions">
          <i class="bi bi-search"></i>
          <i class="bi bi-three-dots-vertical"></i>
        </div>
      </div>

      <!-- Messages -->
      <div class="messages-container" id="messagesContainer">
        <!-- Messages injectés ici -->
      </div>

      <!-- Zone de saisie -->
      <div class="message-input-container">
        <div class="input-actions-left">
          <i class="bi bi-emoji-smile"></i>
          <i class="bi bi-paperclip"></i>
        </div>
        <input type="text" class="message-input" id="messageInput" placeholder="Écrivez un message">
        <div class="input-actions-right">
          <i class="bi bi-mic"></i>
          <i class="bi bi-send-fill" id="sendMessageBtn" style="cursor: pointer;"></i>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>

<script>
  // ===== DONNÉES DES CONVERSATIONS =====
  const conversations = [
    {
      id: 1,
      name: 'Marie Lambert',
      avatar: 'ML',
      lastMessage: 'Salut ! On se voit demain ?',
      time: '12:45',
      unread: 2,
      status: 'en ligne',
      messages: [
        { id: 1, text: 'Salut ! Comment vas-tu ?', sent: false, time: '12:30' },
        { id: 2, text: 'Très bien, merci ! Et toi ?', sent: true, time: '12:32', status: 'read' },
        { id: 3, text: 'Salut ! On se voit demain ?', sent: false, time: '12:45' }
      ]
    },
    {
      id: 2,
      name: 'Thomas Martin',
      avatar: 'TM',
      lastMessage: 'Le projet est presque terminé',
      time: '11:20',
      unread: 0,
      status: 'en ligne',
      messages: [
        { id: 1, text: 'Tu as avancé sur le rapport ?', sent: true, time: '10:00', status: 'read' },
        { id: 2, text: 'Oui, je te l\'envoie dans 10 minutes', sent: false, time: '10:15' },
        { id: 3, text: 'Le projet est presque terminé', sent: false, time: '11:20' }
      ]
    },
    {
      id: 3,
      name: 'Sophie Dubois',
      avatar: 'SD',
      lastMessage: 'Merci pour ton aide ! 😊',
      time: 'Hier',
      unread: 1,
      status: 'vu à 18:30',
      messages: [
        { id: 1, text: 'Tu peux m\'aider avec l\'exercice ?', sent: false, time: '17:00' },
        { id: 2, text: 'Bien sûr ! Quel exercice ?', sent: true, time: '17:15', status: 'read' },
        { id: 3, text: 'Merci pour ton aide ! 😊', sent: false, time: '18:30' }
      ]
    },
    {
      id: 4,
      name: 'Lucas Bernard',
      avatar: 'LB',
      lastMessage: 'On se rejoint où ?',
      time: 'Hier',
      unread: 0,
      status: 'hors ligne',
      messages: [
        { id: 1, text: 'Salut Lucas ! Dispo ce soir ?', sent: true, time: '19:00', status: 'read' },
        { id: 2, text: 'Oui, vers 20h ?', sent: false, time: '19:10' },
        { id: 3, text: 'On se rejoint où ?', sent: false, time: '19:30' }
      ]
    },
    {
      id: 5,
      name: 'Emma Petit',
      avatar: 'EP',
      lastMessage: 'Photo',
      time: 'Lun',
      unread: 3,
      status: 'en ligne',
      messages: [
        { id: 1, text: 'Coucou !', sent: false, time: '09:00' },
        { id: 2, text: 'Regarde cette photo', sent: false, time: '09:01' },
        { id: 3, text: 'Photo', sent: false, time: '09:02' }
      ]
    }
  ];

  let currentChatId = null;

  // ===== INITIALISATION =====
  function init() {
    renderChatList();
    setupEventListeners();
  }

  // ===== RENDU DE LA LISTE DES CONVERSATIONS =====
  function renderChatList() {
    const chatList = document.getElementById('chatList');
    chatList.innerHTML = '';
    
    const searchTerm = document.getElementById('searchInput').value.toLowerCase();
    
    const filteredConversations = conversations.filter(conv => 
      conv.name.toLowerCase().includes(searchTerm) || 
      conv.lastMessage.toLowerCase().includes(searchTerm)
    );
    
    filteredConversations.forEach(conv => {
      const chatItem = document.createElement('div');
      chatItem.className = `chat-item ${currentChatId === conv.id ? 'active' : ''}`;
      chatItem.setAttribute('data-id', conv.id);
      
      chatItem.innerHTML = `
        <div class="chat-avatar">${conv.avatar}</div>
        <div class="chat-info">
          <div class="chat-header">
            <span class="chat-name">${conv.name}</span>
            <span class="chat-time">${conv.time}</span>
          </div>
          <div class="chat-last-message">
            <span class="last-message">${conv.lastMessage}</span>
            ${conv.unread > 0 ? `<span class="unread-badge">${conv.unread}</span>` : ''}
          </div>
        </div>
      `;
      
      chatItem.addEventListener('click', () => openChat(conv.id));
      chatList.appendChild(chatItem);
    });
  }

  // ===== OUVERTURE D'UNE CONVERSATION =====
  function openChat(chatId) {
    currentChatId = chatId;
    const conversation = conversations.find(c => c.id === chatId);
    
    if (!conversation) return;
    
    // Mise à jour de l'UI
    document.getElementById('welcomeScreen').style.display = 'none';
    document.getElementById('activeChat').style.display = 'flex';
    
    // Mise à jour du header
    document.getElementById('contactName').textContent = conversation.name;
    document.getElementById('contactStatus').textContent = conversation.status;
    document.getElementById('contactAvatar').innerHTML = conversation.avatar;
    
    // Rendu des messages
    renderMessages(conversation.messages);
    
    // Mise à jour de la liste (pour l'état actif)
    renderChatList();
    
    // Scroll en bas des messages
    const messagesContainer = document.getElementById('messagesContainer');
    setTimeout(() => {
      messagesContainer.scrollTop = messagesContainer.scrollHeight;
    }, 100);
    
    // Sur mobile, afficher la zone de chat
    if (window.innerWidth <= 768) {
      document.getElementById('chatArea').classList.add('active');
    }
  }

  // ===== RENDU DES MESSAGES =====
  function renderMessages(messages) {
    const container = document.getElementById('messagesContainer');
    container.innerHTML = '';
    
    messages.forEach(msg => {
      const messageDiv = document.createElement('div');
      messageDiv.className = `message ${msg.sent ? 'sent' : 'received'}`;
      
      const statusIcon = msg.sent ? 
        (msg.status === 'read' ? '<i class="bi bi-check-all message-status"></i>' : 
         '<i class="bi bi-check message-status"></i>') : '';
      
      messageDiv.innerHTML = `
        <div class="message-bubble">
          ${msg.text}
          <div class="message-time">
            ${msg.time}
            ${statusIcon}
          </div>
        </div>
      `;
      
      container.appendChild(messageDiv);
    });
  }

  // ===== ENVOI D'UN MESSAGE =====
  function sendMessage() {
    const input = document.getElementById('messageInput');
    const text = input.value.trim();
    
    if (!text || !currentChatId) return;
    
    const conversation = conversations.find(c => c.id === currentChatId);
    if (!conversation) return;
    
    // Ajouter le message
    const newMessage = {
      id: Date.now(),
      text: text,
      sent: true,
      time: new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }),
      status: 'sent'
    };
    
    conversation.messages.push(newMessage);
    conversation.lastMessage = text;
    conversation.time = newMessage.time;
    
    // Mise à jour de l'UI
    renderMessages(conversation.messages);
    renderChatList();
    
    // Vider l'input
    input.value = '';
    
    // Scroll en bas
    const messagesContainer = document.getElementById('messagesContainer');
    setTimeout(() => {
      messagesContainer.scrollTop = messagesContainer.scrollHeight;
    }, 100);
    
    // Simuler une réponse après 1-2 secondes
    setTimeout(() => {
      simulateResponse(conversation);
    }, Math.random() * 1000 + 1000);
  }

  // ===== SIMULATION DE RÉPONSE =====
  function simulateResponse(conversation) {
    const responses = [
      "D'accord, je vois !",
      "Super, merci pour l'info !",
      "Tu as raison 👍",
      "Je te réponds plus tard",
      "Parfait !",
      "😂😂😂",
      "Ok, à plus tard !",
      "Bien reçu !"
    ];
    
    const randomResponse = responses[Math.floor(Math.random() * responses.length)];
    
    const responseMessage = {
      id: Date.now(),
      text: randomResponse,
      sent: false,
      time: new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })
    };
    
    conversation.messages.push(responseMessage);
    conversation.lastMessage = randomResponse;
    conversation.time = responseMessage.time;
    
    // Marquer le dernier message envoyé comme "lu"
    const lastSentMessage = [...conversation.messages].reverse().find(m => m.sent);
    if (lastSentMessage) {
      lastSentMessage.status = 'read';
    }
    
    // Incrémenter les messages non lus si la conversation n'est pas active
    if (currentChatId !== conversation.id) {
      conversation.unread++;
    }
    
    // Mise à jour de l'UI
    if (currentChatId === conversation.id) {
      renderMessages(conversation.messages);
      const messagesContainer = document.getElementById('messagesContainer');
      setTimeout(() => {
        messagesContainer.scrollTop = messagesContainer.scrollHeight;
      }, 100);
    }
    
    renderChatList();
  }

  // ===== CONFIGURATION DES ÉCOUTEURS D'ÉVÉNEMENTS =====
  function setupEventListeners() {
    // Recherche
    document.getElementById('searchInput').addEventListener('input', renderChatList);
    
    // Envoi de message
    document.getElementById('sendMessageBtn').addEventListener('click', sendMessage);
    
    // Envoi avec Entrée
    document.getElementById('messageInput').addEventListener('keypress', (e) => {
      if (e.key === 'Enter') {
        sendMessage();
      }
    });
  }

  // ===== AFFICHAGE DU PROFIL UTILISATEUR =====
  function showUserProfile() {
    alert('👤 Profil utilisateur\n\nUtilisateur: Moi\nStatut: Disponible\n\n(Fonctionnalité de démonstration)');
  }

  // ===== GESTION DU RETOUR SUR MOBILE =====
  window.addEventListener('resize', () => {
    if (window.innerWidth > 768) {
      document.getElementById('chatArea').classList.remove('active');
    }
  });

  // Ajouter un bouton de retour pour mobile
  document.addEventListener('DOMContentLoaded', () => {
    const chatHeader = document.querySelector('.chat-header-bar');
    if (chatHeader && window.innerWidth <= 768) {
      const backButton = document.createElement('i');
      backButton.className = 'bi bi-arrow-left d-md-none';
      backButton.style.cssText = 'color: #aebac1; font-size: 1.3rem; cursor: pointer; margin-right: 15px;';
      backButton.addEventListener('click', () => {
        document.getElementById('chatArea').classList.remove('active');
        currentChatId = null;
        renderChatList();
      });
      chatHeader.querySelector('.chat-contact-info').prepend(backButton);
    }
  });

  // ===== DÉMARRAGE =====
  init();

  console.log('✅ WhatsApp Web Clone - Bootstrap 5 - Prêt !');
</script>

</body>
</html>

Ouvrir cet aperçu dans un nouvel onglet du navigateur

🔗 Ouvrir dans le navigateur