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