Telegram Web - Bootstrap 5

🏷️ Extraits de code HTML 📅 08/04/2026 14:00:00 👤 Mezgani said
Bootstrap Bootstrap5 Telegram Chat Messagerie Html

Template Bootstrap 5 de messagerie type Telegram Web avec liste de conversations et panneau de discussion.

<!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 Telegrame 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: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', sans-serif;
      background: var(--tg-theme-bg-color, #17212b);
      height: 100vh;
      overflow: hidden;
    }

    /* Variables Telegram */
    :root {
      --tg-bg: #17212b;
      --tg-sidebar: #17212b;
      --tg-header: #242f3d;
      --tg-chat-bg: #0e1621;
      --tg-message-out: #2b5278;
      --tg-message-in: #242f3d;
      --tg-text-primary: #ffffff;
      --tg-text-secondary: #7c8b9a;
      --tg-accent: #2fa9e4;
      --tg-accent-hover: #3fb9f4;
      --tg-border: #1f2c38;
      --tg-scrollbar: #3a4a5a;
      --tg-avatar-gradient-1: linear-gradient(135deg, #6ab0f2, #3a82c4);
      --tg-avatar-gradient-2: linear-gradient(135deg, #f29b6a, #c47a3a);
      --tg-avatar-gradient-3: linear-gradient(135deg, #6af29b, #3ac47a);
      --tg-avatar-gradient-4: linear-gradient(135deg, #f26a9b, #c43a6a);
      --tg-avatar-gradient-5: linear-gradient(135deg, #c46af2, #8a3ac4);
    }

    /* Structure principale */
    .app-container {
      display: flex;
      height: 100vh;
      background: var(--tg-bg);
    }

    /* ===== SIDEBAR GAUCHE ===== */
    .sidebar {
      width: 320px;
      background: var(--tg-sidebar);
      border-right: 1px solid var(--tg-border);
      display: flex;
      flex-direction: column;
    }

    /* Header sidebar avec menu hamburger */
    .sidebar-header {
      background: var(--tg-header);
      padding: 12px 16px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      min-height: 60px;
    }

    .menu-btn {
      color: var(--tg-text-secondary);
      font-size: 1.4rem;
      cursor: pointer;
      transition: color 0.2s;
      width: 36px;
      height: 36px;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 50%;
    }

    .menu-btn:hover {
      color: var(--tg-text-primary);
      background: rgba(255, 255, 255, 0.05);
    }

    .sidebar-title {
      color: var(--tg-text-primary);
      font-weight: 600;
      font-size: 1.2rem;
      margin: 0;
    }

    .search-container {
      padding: 8px 12px;
      background: var(--tg-sidebar);
    }

    .search-box {
      background: var(--tg-header);
      border-radius: 22px;
      padding: 8px 16px;
      display: flex;
      align-items: center;
      gap: 12px;
      border: 1px solid transparent;
      transition: border-color 0.2s, background 0.2s;
    }

    .search-box:focus-within {
      border-color: var(--tg-accent);
      background: var(--tg-chat-bg);
    }

    .search-box i {
      color: var(--tg-text-secondary);
      font-size: 1rem;
    }

    .search-box input {
      background: transparent;
      border: none;
      color: var(--tg-text-primary);
      outline: none;
      width: 100%;
      font-size: 0.95rem;
    }

    .search-box input::placeholder {
      color: var(--tg-text-secondary);
    }

    /* Liste des conversations */
    .chat-list {
      flex: 1;
      overflow-y: auto;
      background: var(--tg-sidebar);
    }

    .chat-item {
      display: flex;
      align-items: center;
      padding: 10px 12px;
      cursor: pointer;
      transition: background 0.15s;
      border-radius: 10px;
      margin: 2px 6px;
    }

    .chat-item:hover {
      background: rgba(255, 255, 255, 0.05);
    }

    .chat-item.active {
      background: var(--tg-accent);
    }

    .chat-item.active .chat-name,
    .chat-item.active .last-message,
    .chat-item.active .chat-time {
      color: white;
    }

    .chat-avatar {
      width: 48px;
      height: 48px;
      border-radius: 50%;
      margin-right: 12px;
      flex-shrink: 0;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-weight: 500;
      font-size: 1.1rem;
      text-transform: uppercase;
    }

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

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

    .chat-name {
      color: var(--tg-text-primary);
      font-weight: 500;
      font-size: 1rem;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .chat-time {
      color: var(--tg-text-secondary);
      font-size: 0.75rem;
    }

    .chat-last-message {
      display: flex;
      align-items: center;
      gap: 4px;
    }

    .last-message {
      color: var(--tg-text-secondary);
      font-size: 0.85rem;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      flex: 1;
    }

    .message-status {
      color: var(--tg-accent);
      font-size: 1rem;
    }

    .unread-badge {
      background: var(--tg-accent);
      color: white;
      border-radius: 12px;
      padding: 2px 8px;
      font-size: 0.75rem;
      font-weight: 600;
      min-width: 20px;
      text-align: center;
      margin-left: 6px;
    }

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

    /* Fond Telegram avec motif */
    .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="%230e1621"/><circle cx="20" cy="20" r="15" fill="%23111b26" opacity="0.5"/><circle cx="80" cy="80" r="15" fill="%23111b26" opacity="0.5"/></svg>');
      background-size: 200px 200px;
      opacity: 0.4;
      z-index: 0;
    }

    /* Header du chat */
    .chat-header-bar {
      background: var(--tg-header);
      padding: 10px 20px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      min-height: 60px;
      border-bottom: 1px solid var(--tg-border);
      position: relative;
      z-index: 1;
    }

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

    .contact-avatar {
      width: 42px;
      height: 42px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-weight: 500;
      font-size: 1rem;
    }

    .contact-details h6 {
      color: var(--tg-text-primary);
      margin: 0;
      font-size: 1rem;
      font-weight: 600;
    }

    .contact-details small {
      color: var(--tg-text-secondary);
      font-size: 0.8rem;
    }

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

    .chat-actions i {
      color: var(--tg-text-secondary);
      font-size: 1.3rem;
      cursor: pointer;
      transition: color 0.2s;
      width: 36px;
      height: 36px;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 50%;
    }

    .chat-actions i:hover {
      color: var(--tg-text-primary);
      background: rgba(255, 255, 255, 0.05);
    }

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

    .message-group {
      margin-bottom: 16px;
    }

    .message {
      display: flex;
      margin-bottom: 4px;
    }

    .message.sent {
      justify-content: flex-end;
    }

    .message.received {
      justify-content: flex-start;
    }

    .message-bubble-wrapper {
      display: flex;
      align-items: flex-end;
      gap: 6px;
      max-width: 70%;
    }

    .message.sent .message-bubble-wrapper {
      flex-direction: row-reverse;
    }

    .message-avatar {
      width: 32px;
      height: 32px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-size: 0.8rem;
      font-weight: 500;
      flex-shrink: 0;
    }

    .message.received .message-avatar {
      display: flex;
    }

    .message.sent .message-avatar {
      display: none;
    }

    .message-bubble {
      padding: 10px 14px;
      border-radius: 18px;
      position: relative;
      word-wrap: break-word;
      box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
    }

    .message.sent .message-bubble {
      background: var(--tg-message-out);
      color: var(--tg-text-primary);
      border-bottom-right-radius: 4px;
    }

    .message.received .message-bubble {
      background: var(--tg-message-in);
      color: var(--tg-text-primary);
      border-bottom-left-radius: 4px;
    }

    .message-meta {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      gap: 4px;
      margin-top: 4px;
      font-size: 0.7rem;
      color: var(--tg-text-secondary);
    }

    .message.sent .message-meta {
      color: rgba(255, 255, 255, 0.6);
    }

    .message-status i {
      font-size: 0.9rem;
      color: var(--tg-accent);
    }

    /* Zone de saisie */
    .message-input-container {
      background: var(--tg-header);
      padding: 12px 20px;
      display: flex;
      align-items: center;
      gap: 12px;
      position: relative;
      z-index: 1;
      border-top: 1px solid var(--tg-border);
    }

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

    .input-actions-left i {
      color: var(--tg-text-secondary);
      font-size: 1.4rem;
      cursor: pointer;
      transition: color 0.2s;
      width: 40px;
      height: 40px;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 50%;
    }

    .input-actions-left i:hover {
      color: var(--tg-text-primary);
      background: rgba(255, 255, 255, 0.05);
    }

    .message-input {
      flex: 1;
      background: var(--tg-chat-bg);
      border: none;
      border-radius: 24px;
      padding: 10px 18px;
      color: var(--tg-text-primary);
      outline: none;
      font-size: 0.95rem;
      border: 1px solid transparent;
      transition: border-color 0.2s;
    }

    .message-input:focus {
      border-color: var(--tg-accent);
    }

    .message-input::placeholder {
      color: var(--tg-text-secondary);
    }

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

    .input-actions-right i {
      color: var(--tg-text-secondary);
      font-size: 1.4rem;
      cursor: pointer;
      transition: all 0.2s;
      width: 40px;
      height: 40px;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 50%;
    }

    .input-actions-right i:hover {
      color: var(--tg-text-primary);
      background: rgba(255, 255, 255, 0.05);
    }

    #sendMessageBtn {
      color: var(--tg-accent);
    }

    #sendMessageBtn:hover {
      background: rgba(47, 169, 228, 0.1);
    }

    /* Écran de bienvenue */
    .welcome-screen {
      flex: 1;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      position: relative;
      z-index: 1;
      background: var(--tg-chat-bg);
    }

    .welcome-logo {
      width: 160px;
      height: 160px;
      background: var(--tg-accent);
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-bottom: 30px;
      box-shadow: 0 10px 30px rgba(47, 169, 228, 0.3);
    }

    .welcome-logo i {
      font-size: 5rem;
      color: white;
    }

    .welcome-screen h2 {
      color: var(--tg-text-primary);
      font-weight: 400;
      margin-bottom: 15px;
    }

    .welcome-screen p {
      color: var(--tg-text-secondary);
      text-align: center;
      max-width: 400px;
      font-size: 0.95rem;
    }

    /* Scrollbar personnalisée style Telegram */
    ::-webkit-scrollbar {
      width: 5px;
    }

    ::-webkit-scrollbar-track {
      background: transparent;
    }

    ::-webkit-scrollbar-thumb {
      background: var(--tg-scrollbar);
      border-radius: 3px;
    }

    ::-webkit-scrollbar-thumb:hover {
      background: #4a5a6a;
    }

    /* 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;
      }
      .back-btn-mobile {
        display: block !important;
      }
    }

    .back-btn-mobile {
      display: none;
    }
  </style>
</head>
<body>

<div class="app-container">
  
  <!-- ===== SIDEBAR (Liste des conversations) ===== -->
  <div class="sidebar">
    <!-- Header -->
    <div class="sidebar-header">
      <div class="menu-btn">
        <i class="bi bi-list"></i>
      </div>
      <span class="sidebar-title">Telegram</span>
      <div class="menu-btn">
        <i class="bi bi-pencil-square"></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" 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">
        <i class="bi bi-send-fill"></i>
      </div>
      <h2>Telegram Web</h2>
      <p>Sélectionnez une conversation pour commencer à discuter.<br>Vos messages sont synchronisés sur tous vos appareils.</p>
    </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">
          <i class="bi bi-arrow-left back-btn-mobile" style="color: var(--tg-text-secondary); font-size: 1.3rem; cursor: pointer; margin-right: 10px;" onclick="goBack()"></i>
          <div class="contact-avatar" id="contactAvatar"></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-telephone"></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="Écrire un message...">
        <div class="input-actions-right">
          <i class="bi bi-mic"></i>
          <i class="bi bi-send-fill" id="sendMessageBtn"></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',
      avatarColor: '--tg-avatar-gradient-1',
      lastMessage: 'On se voit demain pour le café ? ☕',
      time: '12:45',
      unread: 2,
      status: 'en ligne',
      messages: [
        { id: 1, text: 'Salut ! Comment vas-tu ?', sent: false, time: '12:30', status: 'read' },
        { id: 2, text: 'Très bien ! Et toi ? 😊', sent: true, time: '12:32', status: 'read' },
        { id: 3, text: 'Super ! Dis-moi, tu es libre demain ?', sent: false, time: '12:40', status: 'read' },
        { id: 4, text: 'Oui, pourquoi pas !', sent: true, time: '12:42', status: 'read' },
        { id: 5, text: 'On se voit demain pour le café ? ☕', sent: false, time: '12:45', status: 'read' }
      ]
    },
    {
      id: 2,
      name: 'Thomas Martin',
      avatar: 'TM',
      avatarColor: '--tg-avatar-gradient-2',
      lastMessage: 'Le rapport est prêt, je te l\'envoie',
      time: '11:20',
      unread: 0,
      status: 'en ligne',
      messages: [
        { id: 1, text: 'Tu as avancé sur le projet ?', sent: true, time: '10:00', status: 'read' },
        { id: 2, text: 'Oui, presque terminé !', sent: false, time: '10:15', status: 'read' },
        { id: 3, text: 'Parfait, tu peux me l\'envoyer ?', sent: true, time: '11:10', status: 'read' },
        { id: 4, text: 'Le rapport est prêt, je te l\'envoie', sent: false, time: '11:20', status: 'read' }
      ]
    },
    {
      id: 3,
      name: 'Sophie Dubois',
      avatar: 'SD',
      avatarColor: '--tg-avatar-gradient-3',
      lastMessage: 'Merci beaucoup ! 🙏',
      time: 'Hier',
      unread: 1,
      status: 'vu à 18:30',
      messages: [
        { id: 1, text: 'Coucou ! Tu as une minute ?', sent: false, time: '17:00', status: 'read' },
        { id: 2, text: 'Bien sûr, qu\'est-ce qu\'il y a ?', sent: true, time: '17:05', status: 'read' },
        { id: 3, text: 'Je voulais te remercier pour ton aide hier', sent: false, time: '17:10', status: 'read' },
        { id: 4, text: 'Avec plaisir ! N\'hésite pas si besoin', sent: true, time: '17:15', status: 'read' },
        { id: 5, text: 'Merci beaucoup ! 🙏', sent: false, time: '18:30', status: 'read' }
      ]
    },
    {
      id: 4,
      name: 'Lucas Bernard',
      avatar: 'LB',
      avatarColor: '--tg-avatar-gradient-4',
      lastMessage: 'On se rejoint où exactement ?',
      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 ça te va ?', sent: false, time: '19:10', status: 'read' },
        { id: 3, text: 'Parfait ! On se retrouve où ?', sent: true, time: '19:15', status: 'read' },
        { id: 4, text: 'On se rejoint où exactement ?', sent: false, time: '19:30', status: 'read' }
      ]
    },
    {
      id: 5,
      name: 'Emma Petit',
      avatar: 'EP',
      avatarColor: '--tg-avatar-gradient-5',
      lastMessage: '📸 Photo',
      time: 'Lun',
      unread: 3,
      status: 'en ligne',
      messages: [
        { id: 1, text: 'Hello ! Regarde cette vue 😍', sent: false, time: '09:00', status: 'read' },
        { id: 2, text: 'Wow, c\'est magnifique !', sent: true, time: '09:05', status: 'read' },
        { id: 3, text: '📸 Photo', sent: false, time: '09:10', status: 'read' }
      ]
    },
    {
      id: 6,
      name: 'Groupe Projet',
      avatar: 'GP',
      avatarColor: '--tg-avatar-gradient-1',
      lastMessage: 'Alex: La réunion est confirmée pour 14h',
      time: '09:30',
      unread: 5,
      status: '5 membres, 3 en ligne',
      isGroup: true,
      messages: [
        { id: 1, text: 'Marie: Bonjour tout le monde !', sent: false, time: '09:00', status: 'read' },
        { id: 2, text: 'Thomas: Hello ! Des nouvelles pour la réunion ?', sent: false, time: '09:15', status: 'read' },
        { id: 3, text: 'Moi: Oui, je propose 14h', sent: true, time: '09:20', status: 'read' },
        { id: 4, text: 'Alex: La réunion est confirmée pour 14h', sent: false, time: '09:30', status: 'read' }
      ]
    }
  ];

  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);
      
      const avatarStyle = `background: var(${conv.avatarColor})`;
      const checkIcon = conv.messages.some(m => m.sent && m.status === 'read') ? 
        '<i class="bi bi-check-all message-status"></i>' : 
        '<i class="bi bi-check message-status"></i>';
      
      chatItem.innerHTML = `
        <div class="chat-avatar" style="${avatarStyle}">${conv.avatar}</div>
        <div class="chat-info">
          <div class="chat-header">
            <span class="chat-name">${conv.isGroup ? '<i class="bi bi-people-fill"></i> ' : ''}${conv.name}</span>
            <span class="chat-time">${conv.time}</span>
          </div>
          <div class="chat-last-message">
            <span class="last-message">${conv.lastMessage}</span>
            ${conv.messages[conv.messages.length - 1]?.sent ? checkIcon : ''}
            ${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;
    
    // Réinitialiser les messages non lus
    conversation.unread = 0;
    
    // 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').textContent = conversation.avatar;
    document.getElementById('contactAvatar').style.background = `var(${conversation.avatarColor})`;
    
    // 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, index) => {
      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"></i>' : 
         '<i class="bi bi-check"></i>') : '';
      
      // Avatar pour les messages reçus
      const avatarHtml = !msg.sent ? 
        `<div class="message-avatar" style="background: var(--tg-avatar-gradient-2);">${msg.senderInitial || '?'}</div>` : '';
      
      messageDiv.innerHTML = `
        <div class="message-bubble-wrapper">
          ${avatarHtml}
          <div>
            <div class="message-bubble">
              ${msg.text}
            </div>
            <div class="message-meta">
              <span>${msg.time}</span>
              <span class="message-status">${statusIcon}</span>
            </div>
          </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);
    
    // Marquer comme lu après un délai
    setTimeout(() => {
      newMessage.status = 'read';
      if (currentChatId === conversation.id) {
        renderMessages(conversation.messages);
      }
      renderChatList();
    }, 1500);
    
    // Simuler une réponse après 1-3 secondes
    setTimeout(() => {
      simulateResponse(conversation);
    }, Math.random() * 2000 + 1500);
  }

  // ===== 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 !",
      "Je suis d'accord avec toi",
      "On en parle demain ?"
    ];
    
    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' }),
      status: 'read',
      senderInitial: conversation.avatar
    };
    
    conversation.messages.push(responseMessage);
    conversation.lastMessage = randomResponse;
    conversation.time = responseMessage.time;
    
    // 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();
  }

  // ===== RETOUR (mobile) =====
  function goBack() {
    document.getElementById('chatArea').classList.remove('active');
    currentChatId = null;
    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();
      }
    });
  }

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

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

</body>
</html>

Ouvrir cet aperçu dans un nouvel onglet du navigateur

🔗 Ouvrir dans le navigateur